diff --git a/BUILD.gn b/BUILD.gn index ea376e89..7ac0e16 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -766,6 +766,7 @@ deps += [ "//fuchsia:webrunner_unittests", "//fuchsia/http:http_service_tests", + "//fuchsia/runners:cast_runner_unittests", "//headless", ] }
diff --git a/DEPS b/DEPS index afcf250c..3330acfe 100644 --- a/DEPS +++ b/DEPS
@@ -121,11 +121,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'd562545e8a239e18bf9dfdc6959b12780507b1ca', + 'skia_revision': '094ab18b457e0a5c79c2159231dea2b7252e8275', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '21b1ee522c100e983d64754291774d68e7bdc31f', + 'v8_revision': '9df9418edf64d6a080ba569ef43cd5ca0171a820', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -133,7 +133,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '5313c8a89964f536bff2c7f7943499f9c52e5664', + 'angle_revision': '47ca1b2fa3990e51a2ced20f7a7d3589a5477ad1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -145,7 +145,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '56250c3ee3c02842227d0eafc41d1551942f9924', + 'pdfium_revision': 'b2bab1fee5345fef9c103cf9b20c381705485d4e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -177,11 +177,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling HarfBuzz # and whatever else without interference from each other. - 'harfbuzz_revision': '89bcfb204c736f5962d377896af2c1350f179882', + 'harfbuzz_revision': '36fb2b4da9718a86978fa07c99ba4345f7ca9b4b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'dd2de388fc4e3e8fa97a97515ec35c5b3834b753', + 'catapult_revision': 'b9dbf6c17c965f7c49f017e59f9f7098d0ed1e8f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -229,11 +229,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'spv_tools_revision': '4a405eda53bedd282a35c406cc9bab08505e2994', + 'spv_tools_revision': '86d0d9be254a97cb532268bfcff1861bd562ceac', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'spv_headers_revision': '79b6681aadcb53c27d1052e5f8a0e82a981dbf2f', + 'spv_headers_revision': 'f3abb280c2aacf677bc45293a1893b8493b63faf', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -249,7 +249,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'quiche_revision': '9e83c26b83c78c6bb0e537e84090eee0269b2826', + 'quiche_revision': '1605d8b142ed791a195d0250992893bb8033fe01', } # Only these hosts are allowed for dependencies in this DEPS file. @@ -670,7 +670,7 @@ Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'), 'src/third_party/cct_dynamic_module/src': { - 'url': Var('chromium_git') + '/dynamicmodule' + '@' + '4c0a460459bc34177d3a71d6b49e253476431ec9', + 'url': Var('chromium_git') + '/dynamicmodule' + '@' + '441bbbf3ab849b8816bb2c827a51df9a81b83a4f', 'condition': 'checkout_android', }, @@ -679,7 +679,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'cec40a962e60f3e82d0ee2f05b8f950567649a8e', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'f580d49078627875f4564a12562bc4d01e1f7b26', 'condition': 'checkout_linux', }, @@ -704,7 +704,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'f7971436824dd8eeb9b0cf19dabc3e32b369a904', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '695e7cf352585cee87dd635e1c127339913c5717', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -739,7 +739,7 @@ }, 'src/third_party/ffmpeg': - Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '42bb040dde0a5e1bdb4b6d91f54297e0cc7f0977', + Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '4b75b8bab99385646911c24403a016ce9c3d5740', 'src/third_party/flac': Var('chromium_git') + '/chromium/deps/flac.git' + '@' + 'af862024c8c8fa0ae07ced05e89013d881b00596', @@ -766,7 +766,7 @@ }, 'src/third_party/glslang/src': - Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '0ac199df32687fe17b38cd2d0da64c3742e24fef', + Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '4930964683168aaefa55562cf6cdbcc7af901970', 'src/third_party/google_toolbox_for_mac/src': { 'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'), @@ -1036,7 +1036,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '0df3edc9d973b0f9fd7ecd5ee8fbfcb61b57baaf', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'ed17109c24b1213d359d8fa55d7104bf87180fdd', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78', @@ -1196,10 +1196,10 @@ Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd', 'src/third_party/webgl/src': - Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'f22b9ad8d75bf99652dfc3b1db40e73d9fdd3840', + Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'db52df17f0d012983dc281e4864c71485a86bd0e', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '71b5a7df7794bbc4103296fcd8bd740acebdc901', + Var('webrtc_git') + '/src.git' + '@' + 'b0397d69a93a909fc0b29ffdb9236bab1e1b2db7', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1240,7 +1240,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@9eb5076ed0c18acbb2032589ff7c9a4361e62b4d', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2d2052fde8d4cc5088a03f431433899955307445', 'condition': 'checkout_src_internal', }, @@ -1248,7 +1248,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_deps/libs/com_google_android_play_core_verification', - 'version': 'CMX_sCQTYt-Pj3-xFaCMPNGK3TjVMfToP2glkNm1a4AC', + 'version': '8G9OLUMhXcZ3EtWR234C86_a9afooucYik62UE_FjrsC', }, ], 'condition': 'checkout_android',
diff --git a/WATCHLISTS b/WATCHLISTS index 72ee5e2..fba0621 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -2186,8 +2186,7 @@ 'mattreynolds+watch@chromium.org', 'timvolodine@chromium.org', 'wanming.lin@intel.com'], - 'geolocation': ['mattreynolds+watch@chromium.org', - 'mlamouri+watch-geolocation@chromium.org'], + 'geolocation': ['mattreynolds+watch@chromium.org'], 'gfx_geometry': ['cc-bugs@chromium.org'], 'gfx_image': ['rsesek+watch@chromium.org'], 'gn': ['agrieve+watch@chromium.org', @@ -2374,10 +2373,11 @@ 'screen_orientation': ['mlamouri+watch-screen-orientation@chromium.org'], 'security': ['security-watchlist@chromium.org'], 'send_tab_to_self': ['hansberry+watch-send_tab_to_self@chromium.org', - 'tgupta+watch@chromium.org', 'jeffreycohen+watch-send_tab_to_self@chromium.org', + 'jhawkins+watch-send_tab_to_self@chromium.org', 'jlklein+watch-send_tab_to_self@chromium.org', - 'jhawkins+watch-send_tab_to_self@chromium.org'], + 'sebsg+watch-send_tab_to_self@chromium.org', + 'tgupta+watch@chromium.org'], 'service_worker': ['horo+watch@chromium.org', 'jsbell+serviceworker@chromium.org', 'kinuko+serviceworker@chromium.org',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index efd1397..bbfe5cc5 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -534,8 +534,6 @@ "browser/aw_picture.h", "browser/aw_print_manager.cc", "browser/aw_print_manager.h", - "browser/aw_printing_message_filter.cc", - "browser/aw_printing_message_filter.h", "browser/aw_proxy_controller.cc", "browser/aw_proxying_url_loader_factory.cc", "browser/aw_proxying_url_loader_factory.h",
diff --git a/android_webview/browser/aw_autofill_client.cc b/android_webview/browser/aw_autofill_client.cc index 35941e4..b041018 100644 --- a/android_webview/browser/aw_autofill_client.cc +++ b/android_webview/browser/aw_autofill_client.cc
@@ -128,6 +128,7 @@ void AwAutofillClient::ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<autofill::MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) { NOTIMPLEMENTED();
diff --git a/android_webview/browser/aw_autofill_client.h b/android_webview/browser/aw_autofill_client.h index 18f2783..e2ef3fa 100644 --- a/android_webview/browser/aw_autofill_client.h +++ b/android_webview/browser/aw_autofill_client.h
@@ -85,6 +85,7 @@ base::OnceClosure show_migration_dialog_closure) override; void ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<autofill::MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) override;
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index f762a0b..d9e368de 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -20,7 +20,6 @@ #include "android_webview/browser/aw_devtools_manager_delegate.h" #include "android_webview/browser/aw_feature_list_creator.h" #include "android_webview/browser/aw_login_delegate.h" -#include "android_webview/browser/aw_printing_message_filter.h" #include "android_webview/browser/aw_proxying_url_loader_factory.h" #include "android_webview/browser/aw_quota_permission_context.h" #include "android_webview/browser/aw_settings.h" @@ -359,7 +358,6 @@ host->AddFilter(new AwContentsMessageFilter(host->GetID())); // WebView always allows persisting data. host->AddFilter(new cdm::CdmMessageFilterAndroid(true, false)); - host->AddFilter(new AwPrintingMessageFilter(host->GetID())); } bool AwContentBrowserClient::ShouldUseMobileFlingCurve() const {
diff --git a/android_webview/browser/aw_print_manager.cc b/android_webview/browser/aw_print_manager.cc index af87bbe..e3569b2 100644 --- a/android_webview/browser/aw_print_manager.cc +++ b/android_webview/browser/aw_print_manager.cc
@@ -5,12 +5,34 @@ #include "android_webview/browser/aw_print_manager.h" #include "base/memory/ptr_util.h" +#include "base/memory/ref_counted_memory.h" +#include "base/numerics/safe_conversions.h" +#include "base/task/post_task.h" +#include "base/task/task_traits.h" #include "components/printing/browser/print_manager_utils.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" namespace android_webview { +namespace { + +int SaveDataToFd(int fd, + int page_count, + scoped_refptr<base::RefCountedSharedMemoryMapping> data) { + base::File file(fd); + bool result = + file.IsValid() && base::IsValueInRangeForNumericType<int>(data->size()); + if (result) { + int size = data->size(); + result = file.WriteAtCurrentPos(data->front_as<char>(), size) == size; + } + file.TakePlatformFile(); + return result ? page_count : 0; +} + +} // namespace + struct AwPrintManager::FrameDispatchHelper { AwPrintManager* manager; content::RenderFrameHost* render_frame_host; @@ -68,7 +90,8 @@ content::RenderFrameHost* render_frame_host) { FrameDispatchHelper helper = {this, render_frame_host}; bool handled = true; - IPC_BEGIN_MESSAGE_MAP(AwPrintManager, message) + IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(AwPrintManager, message, render_frame_host) + IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintDocument, OnDidPrintDocument) IPC_MESSAGE_FORWARD_DELAY_REPLY( PrintHostMsg_GetDefaultPrintSettings, &helper, FrameDispatchHelper::OnGetDefaultPrintSettings) @@ -104,6 +127,38 @@ render_frame_host->Send(reply_msg); } +void AwPrintManager::OnDidPrintDocument( + content::RenderFrameHost* render_frame_host, + const PrintHostMsg_DidPrintDocument_Params& params) { + if (params.document_cookie != cookie_) + return; + + const PrintHostMsg_DidPrintContent_Params& content = params.content; + if (!content.metafile_data_region.IsValid()) { + NOTREACHED() << "invalid memory handle"; + web_contents()->Stop(); + PdfWritingDone(0); + return; + } + + auto data = base::RefCountedSharedMemoryMapping::CreateFromWholeRegion( + content.metafile_data_region); + if (!data) { + NOTREACHED() << "couldn't map"; + web_contents()->Stop(); + PdfWritingDone(0); + return; + } + + base::PostTaskAndReplyWithResult( + base::CreateTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}) + .get(), + FROM_HERE, base::BindRepeating(&SaveDataToFd, fd_, number_pages_, data), + pdf_writing_done_callback_); +} + WEB_CONTENTS_USER_DATA_KEY_IMPL(AwPrintManager) } // namespace android_webview
diff --git a/android_webview/browser/aw_print_manager.h b/android_webview/browser/aw_print_manager.h index b037db8..209620f 100644 --- a/android_webview/browser/aw_print_manager.h +++ b/android_webview/browser/aw_print_manager.h
@@ -32,8 +32,6 @@ bool PrintNow(); - int fd() const { return fd_; } - private: friend class content::WebContentsUserData<AwPrintManager>; struct FrameDispatchHelper; @@ -53,6 +51,8 @@ void OnScriptedPrint(content::RenderFrameHost* render_frame_host, const PrintHostMsg_ScriptedPrint_Params& params, IPC::Message* reply_msg); + void OnDidPrintDocument(content::RenderFrameHost* render_frame_host, + const PrintHostMsg_DidPrintDocument_Params& params); printing::PrintSettings settings_;
diff --git a/android_webview/browser/aw_printing_message_filter.cc b/android_webview/browser/aw_printing_message_filter.cc deleted file mode 100644 index 3277cac7..0000000 --- a/android_webview/browser/aw_printing_message_filter.cc +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "android_webview/browser/aw_printing_message_filter.h" - -#include "android_webview/browser/aw_print_manager.h" -#include "base/file_descriptor_posix.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/web_contents.h" - -using content::BrowserThread; -using content::WebContents; - -namespace android_webview { - -namespace { - -AwPrintManager* GetPrintManager(int render_process_id, int render_frame_id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::RenderFrameHost* frame = - content::RenderFrameHost::FromID(render_process_id, render_frame_id); - if (!frame) - return nullptr; - WebContents* web_contents = WebContents::FromRenderFrameHost(frame); - return web_contents ? AwPrintManager::FromWebContents(web_contents) : nullptr; -} - -} // namespace - -AwPrintingMessageFilter::AwPrintingMessageFilter(int render_process_id) - : BrowserMessageFilter(PrintMsgStart), - render_process_id_(render_process_id) { -} - -AwPrintingMessageFilter::~AwPrintingMessageFilter() { -} - -void AwPrintingMessageFilter::OverrideThreadForMessage( - const IPC::Message& message, BrowserThread::ID* thread) { - if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID || - message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) { - *thread = BrowserThread::UI; - } -} - -bool AwPrintingMessageFilter::OnMessageReceived(const IPC::Message& message) { - // TODO(timvolodine): move this filter to component (crbug.com/500949). - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(AwPrintingMessageFilter, message) - IPC_MESSAGE_HANDLER(PrintHostMsg_AllocateTempFileForPrinting, - OnAllocateTempFileForPrinting) - IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten, - OnTempFileForPrintingWritten) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void AwPrintingMessageFilter::OnAllocateTempFileForPrinting( - int render_frame_id, - base::FileDescriptor* temp_file_fd, - int* sequence_number) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - AwPrintManager* print_manager = - GetPrintManager(render_process_id_, render_frame_id); - if (!print_manager) - return; - - *sequence_number = 0; // we don't really use the sequence number. - temp_file_fd->fd = print_manager->fd(); - temp_file_fd->auto_close = false; -} - -void AwPrintingMessageFilter::OnTempFileForPrintingWritten(int render_frame_id, - int sequence_number, - int page_count) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK_GT(page_count, 0); - AwPrintManager* print_manager = - GetPrintManager(render_process_id_, render_frame_id); - if (print_manager) - print_manager->PdfWritingDone(page_count); -} - -} // namespace android_webview
diff --git a/android_webview/browser/aw_printing_message_filter.h b/android_webview/browser/aw_printing_message_filter.h deleted file mode 100644 index 236475c..0000000 --- a/android_webview/browser/aw_printing_message_filter.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ANDROID_WEBVIEW_BROWSER_AW_PRINTING_MESSAGE_FILTER_H_ -#define ANDROID_WEBVIEW_BROWSER_AW_PRINTING_MESSAGE_FILTER_H_ - -#include "base/macros.h" -#include "content/public/browser/browser_message_filter.h" -#include "content/public/browser/browser_thread.h" - -namespace base { -struct FileDescriptor; -} - -namespace android_webview { - -// This class filters out incoming printing related IPC messages for the -// renderer process on the IPC thread. -class AwPrintingMessageFilter : public content::BrowserMessageFilter { - public: - explicit AwPrintingMessageFilter(int render_process_id); - - // content::BrowserMessageFilter methods. - void OverrideThreadForMessage(const IPC::Message& message, - content::BrowserThread::ID* thread) override; - bool OnMessageReceived(const IPC::Message& message) override; - - private: - ~AwPrintingMessageFilter() override; - - // Used to ask the browser allocate a temporary file for the renderer - // to fill in resulting PDF in renderer. - void OnAllocateTempFileForPrinting(int render_frame_id, - base::FileDescriptor* temp_file_fd, - int* sequence_number); - void OnTempFileForPrintingWritten(int render_frame_id, - int sequence_number, - int page_count); - - const int render_process_id_; - - DISALLOW_COPY_AND_ASSIGN(AwPrintingMessageFilter); -}; - -} // namespace android_webview - -#endif // ANDROID_WEBVIEW_BROWSER_AW_PRINTING_MESSAGE_FILTER_H_
diff --git a/android_webview/browser/aw_proxying_url_loader_factory.cc b/android_webview/browser/aw_proxying_url_loader_factory.cc index 6d1051c..4d1aefe1 100644 --- a/android_webview/browser/aw_proxying_url_loader_factory.cc +++ b/android_webview/browser/aw_proxying_url_loader_factory.cc
@@ -32,6 +32,7 @@ namespace { const char kAutoLoginHeaderName[] = "X-Auto-Login"; +const char kRequestedWithHeaderName[] = "X-Requested-With"; class InterceptResponseDelegate : public AndroidStreamReaderURLLoader::ResponseDelegate { @@ -241,24 +242,38 @@ request_.load_flags = UpdateLoadFlags(request_.load_flags, io_thread_client.get()); - // TODO: verify the case when WebContents::RenderFrameDeleted is called - // before network request is intercepted (i.e. if that's possible and - // whether it can result in any issues). - io_thread_client->ShouldInterceptRequestAsync( - AwWebResourceRequest(request_), - base::BindOnce(&InterceptedRequest::InterceptResponseReceived, - weak_factory_.GetWeakPtr())); + if (!input_stream_previously_failed_ && + (request_.url.SchemeIs(url::kContentScheme) || + android_webview::IsAndroidSpecialFileUrl(request_.url))) { + // Do not call shouldInterceptRequest callback for special android urls, + // unless they fail to load on first attempt. Special android urls are urls + // such as "file:///android_asset/", "file:///android_res/" urls or + // "content:" scheme urls. + InterceptResponseReceived(nullptr); + } else { + // TODO: verify the case when WebContents::RenderFrameDeleted is called + // before network request is intercepted (i.e. if that's possible and + // whether it can result in any issues). + io_thread_client->ShouldInterceptRequestAsync( + AwWebResourceRequest(request_), + base::BindOnce(&InterceptedRequest::InterceptResponseReceived, + weak_factory_.GetWeakPtr())); + } +} +void SetRequestedWithHeader(net::HttpRequestHeaders& headers) { // We send the application's package name in the X-Requested-With header for // compatibility with previous WebView versions. This should not be visible to // shouldInterceptRequest. - request_.headers.SetHeaderIfMissing( - "X-Requested-With", + headers.SetHeaderIfMissing( + kRequestedWithHeaderName, base::android::BuildInfo::GetInstance()->host_package_name()); } void InterceptedRequest::InterceptResponseReceived( std::unique_ptr<AwWebResourceResponse> response) { + SetRequestedWithHeader(request_.headers); + if (response) { // non-null response: make sure to use it as an override for the // normal network data.
diff --git a/android_webview/browser/deferred_gpu_command_service.cc b/android_webview/browser/deferred_gpu_command_service.cc index 116ad45..bc97ed8 100644 --- a/android_webview/browser/deferred_gpu_command_service.cc +++ b/android_webview/browser/deferred_gpu_command_service.cc
@@ -160,7 +160,8 @@ mailbox_manager.get(), nullptr, gl::GLSurfaceFormat(), - shared_image_manager.get()), + shared_image_manager.get(), + nullptr), sync_point_manager_(std::move(sync_point_manager)), mailbox_manager_(std::move(mailbox_manager)), gpu_info_(gpu_info),
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc index 41458e42..18391f9 100644 --- a/android_webview/lib/aw_main_delegate.cc +++ b/android_webview/lib/aw_main_delegate.cc
@@ -36,7 +36,7 @@ #include "components/autofill/core/common/autofill_features.h" #include "components/crash/core/common/crash_key.h" #include "components/safe_browsing/android/safe_browsing_api_handler_bridge.h" -#include "components/services/heap_profiling/public/cpp/allocator_shim.h" +#include "components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h" #include "components/spellcheck/spellcheck_buildflags.h" #include "components/viz/common/features.h" #include "content/public/browser/android/browser_media_player_manager_register.h"
diff --git a/android_webview/test/embedded_test_server/java/AndroidManifest.xml b/android_webview/test/embedded_test_server/java/AndroidManifest.xml index ccfe776..81e730775 100644 --- a/android_webview/test/embedded_test_server/java/AndroidManifest.xml +++ b/android_webview/test/embedded_test_server/java/AndroidManifest.xml
@@ -8,7 +8,7 @@ xmlns:tools="http://schemas.android.com/tools" package="org.chromium.android_webview.test.support"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.INTERNET"/>
diff --git a/android_webview/tools/PRESUBMIT.py b/android_webview/tools/PRESUBMIT.py index f12654d..edc0f95 100644 --- a/android_webview/tools/PRESUBMIT.py +++ b/android_webview/tools/PRESUBMIT.py
@@ -5,14 +5,21 @@ """Presubmit for android_webview/tools.""" +def _GetPythonUnitTests(input_api, output_api): + return input_api.canned_checks.GetUnitTestsRecursively( + input_api, output_api, + input_api.PresubmitLocalPath(), + whitelist=['.*_test\\.py$'], + blacklist=[]) + + def CommonChecks(input_api, output_api): """Presubmit checks run on both upload and commit. - - This is currently limited to pylint. """ checks = [] checks.extend(input_api.canned_checks.GetPylint( input_api, output_api, pylintrc='pylintrc')) + checks.extend(_GetPythonUnitTests(input_api, output_api)) return input_api.RunTests(checks, False)
diff --git a/android_webview/tools/automated_ui_tests/java/AndroidManifest.xml b/android_webview/tools/automated_ui_tests/java/AndroidManifest.xml index d283b44..ea1650d 100644 --- a/android_webview/tools/automated_ui_tests/java/AndroidManifest.xml +++ b/android_webview/tools/automated_ui_tests/java/AndroidManifest.xml
@@ -10,7 +10,7 @@ android:versionCode="1" android:versionName="1.0" > - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
diff --git a/android_webview/tools/run_cts.py b/android_webview/tools/run_cts.py index 3862b46..a9e50c8 100755 --- a/android_webview/tools/run_cts.py +++ b/android_webview/tools/run_cts.py
@@ -47,6 +47,13 @@ version_codes.OREO_MR1: 'O' } +# TODO(aluo): support 'x86' and 'x86_64' +_SUPPORTED_ARCH_DICT = { + 'arm64-v8a': 'arm64', + # The test apks under 'arm64' support both arm and arm64 devices. + 'armeabi-v7a': 'arm64', +} + def GetCtsInfo(arch, platform, item): """Gets contents of CTS Info for arch and platform. @@ -145,7 +152,7 @@ "Can't merge results field %s that is not a list or dict" % v) -def ExtractCTSZip(args): +def ExtractCTSZip(args, arch): """Extract the CTS tests for args.platform. Extract the CTS zip file from _CTS_ARCHIVE_DIR to @@ -158,7 +165,7 @@ """ base_cts_dir = None delete_cts_dir = False - relative_cts_zip_path = GetCtsInfo(args.arch, args.platform, 'filename') + relative_cts_zip_path = GetCtsInfo(arch, args.platform, 'filename') if args.apk_dir: base_cts_dir = args.apk_dir @@ -168,7 +175,7 @@ cts_zip_path = os.path.join(_CTS_ARCHIVE_DIR, relative_cts_zip_path) local_cts_dir = os.path.join(base_cts_dir, - GetCtsInfo(args.arch, args.platform, + GetCtsInfo(arch, args.platform, 'unzip_dir') ) zf = zipfile.ZipFile(cts_zip_path, 'r') @@ -176,7 +183,7 @@ return (local_cts_dir, base_cts_dir, delete_cts_dir) -def RunAllCTSTests(args, test_runner_args): +def RunAllCTSTests(args, arch, test_runner_args): """Run CTS tests downloaded from _CTS_BUCKET. Downloads CTS tests from bucket, runs them for the @@ -186,11 +193,11 @@ returns the failure code of the last failing test. """ - local_cts_dir, base_cts_dir, delete_cts_dir = ExtractCTSZip(args) + local_cts_dir, base_cts_dir, delete_cts_dir = ExtractCTSZip(args, arch) cts_result = 0 json_results_file = args.json_results_file try: - cts_test_runs = GetCtsInfo(args.arch, args.platform, 'test_runs') + cts_test_runs = GetCtsInfo(arch, args.platform, 'test_runs') cts_results_json = {} for cts_test_run in cts_test_runs: iteration_cts_result = 0 @@ -227,14 +234,34 @@ """ return _SDK_PLATFORM_DICT.get(device.build_version_sdk) +def DetermineArch(device): + """Determines which architecture to use based on the device properties + + Args: + device: The DeviceUtils instance + Returns: + The formatted arch string (as expected by CIPD) + Raises: + Exception: if device architecture is not currently supported by this script. + """ + arch = _SUPPORTED_ARCH_DICT.get(device.product_cpu_abi) + if not arch: + raise Exception('Could not find CIPD bucket for your device arch (' + + device.product_cpu_abi + + '), please specify with --arch') + logging.info('Guessing arch=%s because product.cpu.abi=%s', arch, + device.product_cpu_abi) + return arch def main(): parser = argparse.ArgumentParser() parser.add_argument( '--arch', - choices=['arm64'], - default='arm64', - help='Arch for CTS tests.') + choices=list(set(_SUPPORTED_ARCH_DICT.values())), + default=None, + type=str, + help=('Architecture to for CTS tests. Will auto-determine based on ' + 'the device ro.product.cpu.abi property.')) parser.add_argument( '--platform', choices=['L', 'M', 'N', 'O'], @@ -265,18 +292,21 @@ devil_chromium.Initialize() devices = script_common.GetDevices(args.devices, args.blacklist_file) + device = devices[0] if len(devices) > 1: logging.warning('Only single device supported, using 1st of %d devices: %s', - len(devices), devices[0].serial) - test_runner_args.extend(['-d', devices[0].serial]) + len(devices), device.serial) + test_runner_args.extend(['-d', device.serial]) if args.platform is None: - args.platform = DeterminePlatform(devices[0]) + args.platform = DeterminePlatform(device) if args.platform is None: raise Exception('Could not auto-determine device platform, ' 'please specifiy --platform') - return RunAllCTSTests(args, test_runner_args) + arch = args.arch if args.arch else DetermineArch(device) + + return RunAllCTSTests(args, arch, test_runner_args) if __name__ == '__main__':
diff --git a/android_webview/tools/run_cts_test.py b/android_webview/tools/run_cts_test.py new file mode 100644 index 0000000..5ba01f21 --- /dev/null +++ b/android_webview/tools/run_cts_test.py
@@ -0,0 +1,30 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging +import unittest +import mock +import run_cts + +class _RunCtsTest(unittest.TestCase): + """Unittests for the run_cts module. + """ + + def testDetermineArch_arm64(self): + logging_mock = mock.Mock() + logging.info = logging_mock + device = mock.Mock(product_cpu_abi='arm64-v8a') + self.assertEqual(run_cts.DetermineArch(device), 'arm64') + # We should log a message to explain how we auto-determined the arch. We + # don't assert the message itself, since that's rather strict. + logging_mock.assert_called() + + def testDetermineArch_unsupported(self): + device = mock.Mock(product_cpu_abi='madeup-abi') + with self.assertRaises(Exception) as _: + run_cts.DetermineArch(device) + + +if __name__ == '__main__': + unittest.main()
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 509d1c8..e57ff71 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -71,7 +71,7 @@ "wm/client_controlled_state.h", "wm/drag_window_resizer.h", "wm/mru_window_tracker.h", - "wm/overview/window_selector_controller.h", + "wm/overview/overview_controller.h", "wm/splitview/split_view_controller.h", "wm/tablet_mode/tablet_mode_controller.h", "wm/tablet_mode/tablet_mode_observer.h", @@ -229,16 +229,6 @@ "assistant/ui/main_stage/suggestion_container_view.h", "assistant/ui/main_stage/ui_element_container_view.cc", "assistant/ui/main_stage/ui_element_container_view.h", - "assistant/util/animation_util.cc", - "assistant/util/animation_util.h", - "assistant/util/assistant_util.cc", - "assistant/util/assistant_util.h", - "assistant/util/deep_link_util.cc", - "assistant/util/deep_link_util.h", - "assistant/util/histogram_util.cc", - "assistant/util/histogram_util.h", - "assistant/util/views_util.cc", - "assistant/util/views_util.h", "autoclick/autoclick_controller.cc", "autoclick/autoclick_controller.h", "autoclick/autoclick_drag_event_rewriter.cc", @@ -698,11 +688,6 @@ "system/cast/tray_cast.h", "system/cast/unified_cast_detailed_view_controller.cc", "system/cast/unified_cast_detailed_view_controller.h", - "system/date/clock_observer.h", - "system/date/date_view.cc", - "system/date/date_view.h", - "system/date/tray_system_info.cc", - "system/date/tray_system_info.h", "system/enterprise/enterprise_domain_observer.h", "system/flag_warning/flag_warning_tray.cc", "system/flag_warning/flag_warning_tray.h", @@ -760,6 +745,7 @@ "system/message_center/unified_message_list_view.h", "system/model/clock_model.cc", "system/model/clock_model.h", + "system/model/clock_observer.h", "system/model/enterprise_domain_model.cc", "system/model/enterprise_domain_model.h", "system/model/locale_model.cc", @@ -922,6 +908,10 @@ "system/supervised/supervised_notification_controller.h", "system/system_notification_controller.cc", "system/system_notification_controller.h", + "system/time/time_tray_item_view.cc", + "system/time/time_tray_item_view.h", + "system/time/time_view.cc", + "system/time/time_view.h", "system/toast/toast_data.cc", "system/toast/toast_data.h", "system/toast/toast_manager.cc", @@ -1126,28 +1116,28 @@ "wm/overview/drop_target_view.h", "wm/overview/overview_animation_type.h", "wm/overview/overview_constants.h", + "wm/overview/overview_controller.cc", + "wm/overview/overview_delegate.h", + "wm/overview/overview_grid.cc", + "wm/overview/overview_grid.h", + "wm/overview/overview_item.cc", + "wm/overview/overview_item.h", + "wm/overview/overview_session.cc", + "wm/overview/overview_session.h", "wm/overview/overview_utils.cc", "wm/overview/overview_utils.h", "wm/overview/overview_window_drag_controller.cc", "wm/overview/overview_window_drag_controller.h", "wm/overview/rounded_rect_view.cc", "wm/overview/rounded_rect_view.h", - "wm/overview/scoped_hide_overview_windows.cc", - "wm/overview/scoped_hide_overview_windows.h", "wm/overview/scoped_overview_animation_settings.cc", "wm/overview/scoped_overview_animation_settings.h", - "wm/overview/scoped_transform_overview_window.cc", - "wm/overview/scoped_transform_overview_window.h", + "wm/overview/scoped_overview_hide_windows.cc", + "wm/overview/scoped_overview_hide_windows.h", + "wm/overview/scoped_overview_transform_window.cc", + "wm/overview/scoped_overview_transform_window.h", "wm/overview/start_animation_observer.cc", "wm/overview/start_animation_observer.h", - "wm/overview/window_grid.cc", - "wm/overview/window_grid.h", - "wm/overview/window_selector.cc", - "wm/overview/window_selector.h", - "wm/overview/window_selector_controller.cc", - "wm/overview/window_selector_delegate.h", - "wm/overview/window_selector_item.cc", - "wm/overview/window_selector_item.h", "wm/pip/pip_positioner.cc", "wm/pip/pip_positioner.h", "wm/pip/pip_window_resizer.cc", @@ -1330,6 +1320,7 @@ "//ash/app_menu", "//ash/assistant/model", "//ash/assistant/ui:constants", + "//ash/assistant/util", "//ash/components/cursor", "//ash/components/fast_ink", "//ash/components/quick_launch/public/mojom", @@ -1747,7 +1738,6 @@ "system/bluetooth/bluetooth_power_controller_unittest.cc", "system/bluetooth/tray_bluetooth_helper_legacy_unittest.cc", "system/caps_lock_notification_controller_unittest.cc", - "system/date/date_view_unittest.cc", "system/flag_warning/flag_warning_tray_unittest.cc", "system/ime/ime_feature_pod_controller_unittest.cc", "system/ime_menu/ime_menu_tray_unittest.cc", @@ -1796,6 +1786,7 @@ "system/session/session_limit_notification_controller_unittest.cc", "system/status_area_widget_unittest.cc", "system/supervised/supervised_notification_controller_unittest.cc", + "system/time/time_view_unittest.cc", "system/toast/toast_manager_unittest.cc", "system/tracing_notification_controller_unittest.cc", "system/tray/size_range_layout_unittest.cc", @@ -1844,10 +1835,10 @@ "wm/overlay_event_filter_unittest.cc", "wm/overlay_layout_manager_unittest.cc", "wm/overview/cleanup_animation_observer_unittest.cc", - "wm/overview/scoped_transform_overview_window_unittest.cc", + "wm/overview/overview_controller_unittest.cc", + "wm/overview/overview_session_unittest.cc", + "wm/overview/scoped_overview_transform_window_unittest.cc", "wm/overview/start_animation_observer_unittest.cc", - "wm/overview/window_selector_controller_unittest.cc", - "wm/overview/window_selector_unittest.cc", "wm/pip/pip_positioner_unittest.cc", "wm/pip/pip_unittest.cc", "wm/pip/pip_window_resizer_unittest.cc", @@ -1904,6 +1895,7 @@ "//ash/app_list/presenter", "//ash/app_menu", "//ash/assistant/model", + "//ash/assistant/util", "//ash/components/fast_ink", "//ash/components/fast_ink:unit_tests", "//ash/components/quick_launch/public/mojom:constants", @@ -2049,7 +2041,6 @@ deps = [ ":ash_shell_lib_with_content", "//base", - "//build/win:default_exe_manifest", "//components/user_manager", "//content", "//content/public/app:both",
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc index abcf325..adf15ef8 100644 --- a/ash/accelerators/accelerator_controller.cc +++ b/ash/accelerators/accelerator_controller.cc
@@ -57,7 +57,7 @@ #include "ash/utility/screenshot_controller.h" #include "ash/voice_interaction/voice_interaction_controller.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/screen_pinning_controller.h" #include "ash/wm/window_cycle_controller.h" #include "ash/wm/window_positioning_utils.h" @@ -529,7 +529,7 @@ void HandleToggleOverview() { base::RecordAction(base::UserMetricsAction("Accel_Overview_F5")); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); } void HandleToggleUnifiedDesktop() {
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc index 55bf182..3a81b1d 100644 --- a/ash/accelerators/accelerator_controller_unittest.cc +++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -1006,6 +1006,43 @@ controller->FlushMojoForTesting(); EXPECT_FALSE(controller->IsCapsLockEnabled()); controller->UpdateCapsLockState(false); + generator->ReleaseKey(ui::VKEY_M, ui::EF_NONE); + generator->ReleaseKey(ui::VKEY_LWIN, ui::EF_ALT_DOWN); + + // 6. Toggle CapsLock shortcut should still work after the partial screenshot + // shortcut is used. (https://crbug.com/920030) + { + TestScreenshotDelegate* delegate = GetScreenshotDelegate(); + delegate->set_can_take_screenshot(true); + + EXPECT_EQ(0, delegate->handle_take_partial_screenshot_count()); + + // Press Ctrl+Shift+F5 then release to enter the partial screenshot session. + const ui::Accelerator press_partial_screenshot_shortcut( + ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN); + EXPECT_TRUE(ProcessInController(press_partial_screenshot_shortcut)); + const ui::Accelerator release_partial_screenshot_shortcut = + CreateReleaseAccelerator(ui::VKEY_MEDIA_LAUNCH_APP1, + ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN); + EXPECT_FALSE(ProcessInController(release_partial_screenshot_shortcut)); + + // Press mouse left button, move mouse and release mouse button. Then + // the partial screenshot is taken. + generator->MoveMouseTo(0, 0); + generator->PressLeftButton(); + generator->MoveMouseTo(10, 10); + generator->ReleaseLeftButton(); + EXPECT_EQ(1, delegate->handle_take_partial_screenshot_count()); + + // Press Search, Press Alt, Release Search, Release Alt. CapsLock should be + // triggered. + EXPECT_FALSE(ProcessInController(press_search_then_alt)); + EXPECT_TRUE(ProcessInController(release_search_before_alt)); + controller->FlushMojoForTesting(); + EXPECT_EQ(5, client.set_caps_lock_count_); + EXPECT_TRUE(controller->IsCapsLockEnabled()); + controller->UpdateCapsLockState(false); + } } class PreferredReservedAcceleratorsTest : public AshTestBase {
diff --git a/ash/accessibility/accessibility_focus_ring_controller.cc b/ash/accessibility/accessibility_focus_ring_controller.cc index b9241e17..66e9880 100644 --- a/ash/accessibility/accessibility_focus_ring_controller.cc +++ b/ash/accessibility/accessibility_focus_ring_controller.cc
@@ -162,8 +162,10 @@ } void AccessibilityFocusRingController::SetNoFadeForTesting() { + no_fade_for_testing_ = true; for (auto iter = focus_ring_groups_.begin(); iter != focus_ring_groups_.end(); ++iter) { + iter->second->set_no_fade_for_testing(); iter->second->focus_animation_info()->fade_in_time = base::TimeDelta(); iter->second->focus_animation_info()->fade_out_time = base::TimeDelta::FromHours(1); @@ -253,6 +255,9 @@ // Add it and then return it. focus_ring_groups_[caller_id_to_focus_ring_group_] = std::make_unique<AccessibilityFocusRingGroup>(); + if (no_fade_for_testing_) { + SetNoFadeForTesting(); + } return focus_ring_groups_[caller_id_to_focus_ring_group_].get(); }
diff --git a/ash/accessibility/accessibility_focus_ring_controller.h b/ash/accessibility/accessibility_focus_ring_controller.h index d8b66ed..0cf323cf4 100644 --- a/ash/accessibility/accessibility_focus_ring_controller.h +++ b/ash/accessibility/accessibility_focus_ring_controller.h
@@ -116,6 +116,8 @@ SkColor highlight_color_ = SK_ColorBLACK; float highlight_opacity_ = 0.f; + bool no_fade_for_testing_ = false; + DISALLOW_COPY_AND_ASSIGN(AccessibilityFocusRingController); };
diff --git a/ash/accessibility/accessibility_focus_ring_group.cc b/ash/accessibility/accessibility_focus_ring_group.cc index ddf578e..1cda6af1 100644 --- a/ash/accessibility/accessibility_focus_ring_group.cc +++ b/ash/accessibility/accessibility_focus_ring_group.cc
@@ -83,9 +83,10 @@ } if (focus_ring_behavior_ == mojom::FocusRingBehavior::PERSIST_FOCUS_RING && - focus_layers_[0]->CanAnimate()) { + focus_layers_[0]->CanAnimate() && !no_fade_for_testing_) { // In PERSIST mode, animate the first ring to its destination // location, then set the rest of the rings directly. + // If no_fade_for_testing_ is set, don't wait for animation. for (size_t i = 1; i < focus_rings_.size(); ++i) focus_layers_[i]->Set(focus_rings_[i]); } else {
diff --git a/ash/accessibility/accessibility_focus_ring_group.h b/ash/accessibility/accessibility_focus_ring_group.h index 7a88c73..7f1c3ae 100644 --- a/ash/accessibility/accessibility_focus_ring_group.h +++ b/ash/accessibility/accessibility_focus_ring_group.h
@@ -48,6 +48,8 @@ LayerAnimationInfo* focus_animation_info() { return &focus_animation_info_; } + void set_no_fade_for_testing() { no_fade_for_testing_ = true; } + const std::vector<std::unique_ptr<AccessibilityFocusRingLayer>>& focus_layers_for_testing() const { return focus_layers_; @@ -81,6 +83,7 @@ LayerAnimationInfo focus_animation_info_; mojom::FocusRingBehavior focus_ring_behavior_ = mojom::FocusRingBehavior::FADE_OUT_FOCUS_RING; + bool no_fade_for_testing_ = false; DISALLOW_COPY_AND_ASSIGN(AccessibilityFocusRingGroup); };
diff --git a/ash/accessibility/accessibility_highlight_layer.cc b/ash/accessibility/accessibility_highlight_layer.cc index 18408b8..7d89c3e 100644 --- a/ash/accessibility/accessibility_highlight_layer.cc +++ b/ash/accessibility/accessibility_highlight_layer.cc
@@ -57,6 +57,10 @@ return false; } +bool AccessibilityHighlightLayer::NeedToAnimate() const { + return false; +} + int AccessibilityHighlightLayer::GetInset() const { return kLayerMargin; }
diff --git a/ash/accessibility/accessibility_highlight_layer.h b/ash/accessibility/accessibility_highlight_layer.h index bf565a7c..5d06115 100644 --- a/ash/accessibility/accessibility_highlight_layer.h +++ b/ash/accessibility/accessibility_highlight_layer.h
@@ -26,6 +26,7 @@ // AccessibilityLayer overrides: bool CanAnimate() const override; + bool NeedToAnimate() const override; int GetInset() const override; private:
diff --git a/ash/accessibility/accessibility_layer.cc b/ash/accessibility/accessibility_layer.cc index 2fbbcec..230d4ba 100644 --- a/ash/accessibility/accessibility_layer.cc +++ b/ash/accessibility/accessibility_layer.cc
@@ -65,7 +65,7 @@ gfx::Rect layer_bounds(0, 0, bounds.width(), bounds.height()); layer_->SchedulePaint(layer_bounds); - if (CanAnimate()) { + if (NeedToAnimate()) { // Update the animation observer. display::Display display = display::Screen::GetScreen()->GetDisplayMatching(bounds);
diff --git a/ash/accessibility/accessibility_layer.h b/ash/accessibility/accessibility_layer.h index e124a005..1a5f30d 100644 --- a/ash/accessibility/accessibility_layer.h +++ b/ash/accessibility/accessibility_layer.h
@@ -54,6 +54,9 @@ // animation observer. virtual bool CanAnimate() const = 0; + // Returns true if a layer needs to animate. + virtual bool NeedToAnimate() const = 0; + // Gets the inset for this layer in DIPs. This is used to increase // the bounding box to provide space for any margins or padding. virtual int GetInset() const = 0;
diff --git a/ash/accessibility/focus_ring_layer.cc b/ash/accessibility/focus_ring_layer.cc index 52e2034a..2d1311a2 100644 --- a/ash/accessibility/focus_ring_layer.cc +++ b/ash/accessibility/focus_ring_layer.cc
@@ -47,6 +47,10 @@ return compositor_ && compositor_->HasAnimationObserver(this); } +bool FocusRingLayer::NeedToAnimate() const { + return true; +} + int FocusRingLayer::GetInset() const { return kShadowRadius + 2; }
diff --git a/ash/accessibility/focus_ring_layer.h b/ash/accessibility/focus_ring_layer.h index ca2a696b..7d21008 100644 --- a/ash/accessibility/focus_ring_layer.h +++ b/ash/accessibility/focus_ring_layer.h
@@ -26,6 +26,7 @@ // AccessibilityLayer overrides: bool CanAnimate() const override; + bool NeedToAnimate() const override; int GetInset() const override; // Set a custom color, or reset to the default.
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc index 886f06a..5197605 100644 --- a/ash/app_list/app_list_controller_impl.cc +++ b/ash/app_list/app_list_controller_impl.cc
@@ -25,7 +25,7 @@ #include "ash/voice_interaction/voice_interaction_controller.h" #include "ash/wallpaper/wallpaper_controller.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" @@ -502,25 +502,25 @@ presenter_.ScheduleOverviewModeAnimation( /*start=*/true, Shell::Get() - ->window_selector_controller() - ->window_selector() + ->overview_controller() + ->overview_session() ->enter_exit_overview_type() == - WindowSelector::EnterExitOverviewType::kWindowsMinimized); + OverviewSession::EnterExitOverviewType::kWindowsMinimized); } void AppListControllerImpl::OnOverviewModeEnding( - WindowSelector* window_selector) { + OverviewSession* overview_session) { if (!IsTabletMode()) return; // Animate the launcher if overview mode is sliding out. Let // OnOverviewModeEndingAnimationComplete handle showing the launcher after - // overview mode finishes animating. WindowSelector however is nullptr by the + // overview mode finishes animating. Overview however is nullptr by the // time the animations are finished, so we need to check the animation type // here. - use_slide_to_exit_overview_mode_ = - window_selector->enter_exit_overview_type() == - WindowSelector::EnterExitOverviewType::kWindowsMinimized; + use_slide_to_exit_overview_ = + overview_session->enter_exit_overview_type() == + OverviewSession::EnterExitOverviewType::kWindowsMinimized; } void AppListControllerImpl::OnOverviewModeEndingAnimationComplete( @@ -529,7 +529,7 @@ return; presenter_.ScheduleOverviewModeAnimation(/*start=*/false, - use_slide_to_exit_overview_mode_); + use_slide_to_exit_overview_); } void AppListControllerImpl::OnTabletModeStarted() { @@ -621,10 +621,10 @@ } if (!handled) { - if (Shell::Get()->window_selector_controller()->IsSelecting()) { + if (Shell::Get()->overview_controller()->IsSelecting()) { // End overview mode. - Shell::Get()->window_selector_controller()->ToggleOverview( - WindowSelector::EnterExitOverviewType::kWindowsMinimized); + Shell::Get()->overview_controller()->ToggleOverview( + OverviewSession::EnterExitOverviewType::kWindowsMinimized); handled = true; } if (Shell::Get()->split_view_controller()->IsSplitViewModeActive()) { @@ -814,10 +814,9 @@ bool AppListControllerImpl::CanProcessEventsOnApplistViews() { // Do not allow processing events during overview or while overview is // finished but still animating out. - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - if (window_selector_controller->IsSelecting() || - window_selector_controller->IsCompletingShutdownAnimations()) { + OverviewController* overview_controller = Shell::Get()->overview_controller(); + if (overview_controller->IsSelecting() || + overview_controller->IsCompletingShutdownAnimations()) { return false; } @@ -910,8 +909,7 @@ if (!IsTabletMode() || !presenter_.GetWindow()) return; - const bool in_overview = - Shell::Get()->window_selector_controller()->IsSelecting(); + const bool in_overview = Shell::Get()->overview_controller()->IsSelecting(); if (in_wallpaper_preview_ || in_overview || in_window_dragging_) presenter_.GetWindow()->Hide(); else
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h index 303720fd..99990ca 100644 --- a/ash/app_list/app_list_controller_impl.h +++ b/ash/app_list/app_list_controller_impl.h
@@ -190,7 +190,7 @@ // ShellObserver: void OnOverviewModeStarting() override; - void OnOverviewModeEnding(WindowSelector* window_selector) override; + void OnOverviewModeEnding(OverviewSession* overview_session) override; void OnOverviewModeEndingAnimationComplete(bool canceled) override; // TabletModeObserver: @@ -270,7 +270,7 @@ // Each time overview mode is exited, set this variable based on whether // overview mode is sliding out, so the home launcher knows what to do when // overview mode exit animations are finished. - bool use_slide_to_exit_overview_mode_ = false; + bool use_slide_to_exit_overview_ = false; // Whether the wallpaper is being previewed. The home launcher (if enabled) // should be hidden during wallpaper preview.
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc index e7e5b0a..86d5207 100644 --- a/ash/app_list/app_list_presenter_delegate_unittest.cc +++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -37,7 +37,7 @@ #include "ash/test/ash_test_base.h" #include "ash/wallpaper/wallpaper_controller_test_api.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/root_window_finder.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" @@ -1483,16 +1483,15 @@ GetAppListTestHelper()->CheckVisibility(true); // Enable overview mode. - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - window_selector_controller->ToggleOverview(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + overview_controller->ToggleOverview(); + EXPECT_TRUE(overview_controller->IsSelecting()); ui::Layer* layer = GetAppListView()->GetWidget()->GetNativeWindow()->layer(); EXPECT_EQ(0.0f, layer->opacity()); // Disable overview mode. - window_selector_controller->ToggleOverview(); - EXPECT_FALSE(window_selector_controller->IsSelecting()); + overview_controller->ToggleOverview(); + EXPECT_FALSE(overview_controller->IsSelecting()); EXPECT_EQ(1.0f, layer->opacity()); } @@ -1530,15 +1529,14 @@ // Verify the app list is hidden. wallpaper_test_api.StartWallpaperPreview(); EXPECT_FALSE(GetAppListView()->GetWidget()->IsVisible()); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - window_selector_controller->ToggleOverview(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + overview_controller->ToggleOverview(); + EXPECT_TRUE(overview_controller->IsSelecting()); EXPECT_FALSE(GetAppListView()->GetWidget()->IsVisible()); // Disable overview mode. Verify the app list is still hidden because // wallpaper preview is still active. - window_selector_controller->ToggleOverview(); - EXPECT_FALSE(window_selector_controller->IsSelecting()); + overview_controller->ToggleOverview(); + EXPECT_FALSE(overview_controller->IsSelecting()); EXPECT_FALSE(GetAppListView()->GetWidget()->IsVisible()); // End preview by confirming the wallpaper. Verify the app list is shown. wallpaper_test_api.EndWallpaperPreview(true /*confirm_preview_wallpaper=*/); @@ -1602,19 +1600,18 @@ } // Tests that the app list button will end overview mode. -TEST_F(AppListPresenterDelegateHomeLauncherTest, AppListButtonEndOverViewMode) { +TEST_F(AppListPresenterDelegateHomeLauncherTest, AppListButtonEndOverviewMode) { // Show app list in tablet mode. Enter overview mode. EnableTabletMode(true); GetAppListTestHelper()->CheckVisibility(true); std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithId(0)); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - window_selector_controller->ToggleOverview(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + overview_controller->ToggleOverview(); + EXPECT_TRUE(overview_controller->IsSelecting()); // Press app list button. PressAppListButton(); - EXPECT_FALSE(window_selector_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->IsSelecting()); GetAppListTestHelper()->CheckVisibility(true); }
diff --git a/ash/app_list/home_launcher_gesture_handler.cc b/ash/app_list/home_launcher_gesture_handler.cc index c58dddb..9648ed5 100644 --- a/ash/app_list/home_launcher_gesture_handler.cc +++ b/ash/app_list/home_launcher_gesture_handler.cc
@@ -11,8 +11,8 @@ #include "ash/screen_util.h" #include "ash/shell.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_divider.h" #include "ash/wm/window_state.h" @@ -432,13 +432,13 @@ void HomeLauncherGestureHandler::OnImplicitAnimationsCompleted() { float app_list_opacity = 1.f; const bool is_final_state_show = IsFinalStateShow(); - if (Shell::Get()->window_selector_controller()->IsSelecting()) { + if (Shell::Get()->overview_controller()->IsSelecting()) { if (overview_active_on_gesture_start_ && is_final_state_show) { // Exit overview if event is released on the top half. This will also // end splitview if it is active as SplitViewController observes // overview mode ends. - Shell::Get()->window_selector_controller()->ToggleOverview( - WindowSelector::EnterExitOverviewType::kSwipeFromShelf); + Shell::Get()->overview_controller()->ToggleOverview( + OverviewSession::EnterExitOverviewType::kSwipeFromShelf); } else { app_list_opacity = 0.f; } @@ -545,11 +545,10 @@ : base::NullCallback()); // Update the overview grid if needed. - WindowSelectorController* controller = - Shell::Get()->window_selector_controller(); + OverviewController* controller = Shell::Get()->overview_controller(); if (overview_active_on_gesture_start_ && controller->IsSelecting()) { DCHECK_EQ(mode_, Mode::kSlideUpToShow); - controller->window_selector()->UpdateGridAtLocationYPositionAndOpacity( + controller->overview_session()->UpdateGridAtLocationYPositionAndOpacity( display_.id(), y_position - work_area.height(), 1.f - opacity, work_area, animate @@ -580,11 +579,10 @@ // animation end, so only observe one of the animations. If overview // is active, observe the shield widget of the grid, else observe // |window1_|. - UpdateSettings( - settings.get(), - this->GetWindow1() == window && - !(overview_active_on_gesture_start_ && - Shell::Get()->window_selector_controller()->IsSelecting())); + UpdateSettings(settings.get(), + this->GetWindow1() == window && + !(overview_active_on_gesture_start_ && + Shell::Get()->overview_controller()->IsSelecting())); } window->layer()->SetOpacity(opacity); window->SetTransform(transform); @@ -651,11 +649,11 @@ return true; if (overview_active_on_gesture_start_ && - Shell::Get()->window_selector_controller()->IsSelecting() && + Shell::Get()->overview_controller()->IsSelecting() && Shell::Get() - ->window_selector_controller() - ->window_selector() - ->IsWindowGridAnimating()) { + ->overview_controller() + ->overview_session() + ->IsOverviewGridAnimating()) { return true; } @@ -688,7 +686,7 @@ SplitViewController* split_view_controller = Shell::Get()->split_view_controller(); overview_active_on_gesture_start_ = - Shell::Get()->window_selector_controller()->IsSelecting(); + Shell::Get()->overview_controller()->IsSelecting(); const bool split_view_active = split_view_controller->IsSplitViewModeActive(); auto windows = Shell::Get()->mru_window_tracker()->BuildWindowForCycleList(); if (window && (mode != Mode::kSlideDownToHide ||
diff --git a/ash/app_list/home_launcher_gesture_handler_unittest.cc b/ash/app_list/home_launcher_gesture_handler_unittest.cc index 9b491357..516baa8 100644 --- a/ash/app_list/home_launcher_gesture_handler_unittest.cc +++ b/ash/app_list/home_launcher_gesture_handler_unittest.cc
@@ -8,7 +8,7 @@ #include "ash/shelf/shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" @@ -196,8 +196,7 @@ EXPECT_FALSE(wm::GetWindowState(window1.get())->IsMinimized()); EXPECT_FALSE(wm::GetWindowState(window2.get())->IsMinimized()); - WindowSelectorController* controller = - Shell::Get()->window_selector_controller(); + OverviewController* controller = Shell::Get()->overview_controller(); controller->ToggleOverview(); const int window1_initial_translation = window1->transform().To2dTranslation().y(); @@ -241,7 +240,7 @@ auto window = CreateWindowForTesting(); GetGestureHandler()->ShowHomeLauncher( display_manager()->FindDisplayContainingPoint(gfx::Point(10, 10))); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); } // Tests that HomeLauncherGestureHandler works as expected when one window is @@ -253,13 +252,12 @@ auto window2 = CreateWindowForTesting(); // Snap one window and leave overview mode open with the other window. - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - window_selector_controller->ToggleOverview(); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + overview_controller->ToggleOverview(); SplitViewController* split_view_controller = Shell::Get()->split_view_controller(); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT); - ASSERT_TRUE(window_selector_controller->IsSelecting()); + ASSERT_TRUE(overview_controller->IsSelecting()); ASSERT_TRUE(split_view_controller->IsSplitViewModeActive()); const int window2_initial_translation = @@ -279,14 +277,14 @@ EXPECT_EQ(window1->transform(), gfx::Transform()); EXPECT_EQ(window2_initial_translation, window2->transform().To2dTranslation().y()); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->IsSelecting()); EXPECT_TRUE(split_view_controller->IsSplitViewModeActive()); // Tests that after releasing on the bottom half, overivew and splitview have // both been exited, and both windows are minimized to show the home launcher. DoPress(Mode::kSlideUpToShow); GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 100)); - EXPECT_FALSE(window_selector_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->IsSelecting()); EXPECT_FALSE(split_view_controller->IsSplitViewModeActive()); EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMinimized()); EXPECT_TRUE(wm::GetWindowState(window2.get())->IsMinimized());
diff --git a/ash/assistant/assistant_interaction_controller.cc b/ash/assistant/assistant_interaction_controller.cc index ec9acde..53154d80 100644 --- a/ash/assistant/assistant_interaction_controller.cc +++ b/ash/assistant/assistant_interaction_controller.cc
@@ -14,6 +14,7 @@ #include "ash/assistant/model/assistant_query.h" #include "ash/assistant/model/assistant_response.h" #include "ash/assistant/model/assistant_ui_element.h" +#include "ash/assistant/model/assistant_ui_model.h" #include "ash/assistant/ui/assistant_ui_constants.h" #include "ash/assistant/util/deep_link_util.h" #include "ash/assistant/util/histogram_util.h"
diff --git a/ash/assistant/assistant_interaction_controller.h b/ash/assistant/assistant_interaction_controller.h index 076c5c4..6e765bb 100644 --- a/ash/assistant/assistant_interaction_controller.h +++ b/ash/assistant/assistant_interaction_controller.h
@@ -25,6 +25,7 @@ class AssistantController; class AssistantInteractionModelObserver; +enum class AssistantButtonId; enum class AssistantQuerySource; class AssistantInteractionController
diff --git a/ash/assistant/model/assistant_ui_model.h b/ash/assistant/model/assistant_ui_model.h index 419fca2..a28de95 100644 --- a/ash/assistant/model/assistant_ui_model.h +++ b/ash/assistant/model/assistant_ui_model.h
@@ -62,6 +62,19 @@ kVisible, // Assistant UI is visible and a session is in progress. }; +// Enumeration of Assistant button ID. These values are persisted to logs. +// Entries should not be renumbered and numeric values should never be reused. +// Only append to this enum is allowed if more buttons will be added. +enum class AssistantButtonId { + kBack = 1, + kClose = 2, + kMinimize = 3, + kKeyboardInputToggle = 4, + kVoiceInputToggle = 5, + kSettings = 6, + kMaxValue = kSettings, +}; + // Models the Assistant UI. class COMPONENT_EXPORT(ASSISTANT_MODEL) AssistantUiModel { public:
diff --git a/ash/assistant/ui/assistant_main_view.cc b/ash/assistant/ui/assistant_main_view.cc index 6623bd1..c5abdaa 100644 --- a/ash/assistant/ui/assistant_main_view.cc +++ b/ash/assistant/ui/assistant_main_view.cc
@@ -8,6 +8,7 @@ #include <memory> #include "ash/assistant/model/assistant_interaction_model.h" +#include "ash/assistant/model/assistant_ui_model.h" #include "ash/assistant/ui/assistant_ui_constants.h" #include "ash/assistant/ui/assistant_view_delegate.h" #include "ash/assistant/ui/caption_bar.h"
diff --git a/ash/assistant/ui/assistant_web_view.cc b/ash/assistant/ui/assistant_web_view.cc index 48f03a6..e24f394bfc 100644 --- a/ash/assistant/ui/assistant_web_view.cc +++ b/ash/assistant/ui/assistant_web_view.cc
@@ -7,6 +7,7 @@ #include <algorithm> #include <utility> +#include "ash/assistant/model/assistant_ui_model.h" #include "ash/assistant/ui/assistant_ui_constants.h" #include "ash/assistant/ui/assistant_view_delegate.h" #include "ash/assistant/util/deep_link_util.h"
diff --git a/ash/assistant/ui/assistant_web_view.h b/ash/assistant/ui/assistant_web_view.h index cfa1e69..bcc2872 100644 --- a/ash/assistant/ui/assistant_web_view.h +++ b/ash/assistant/ui/assistant_web_view.h
@@ -20,6 +20,7 @@ namespace ash { +enum class AssistantButtonId; class AssistantViewDelegate; // AssistantWebView is a child of AssistantBubbleView which allows Assistant UI
diff --git a/ash/assistant/ui/base/assistant_button.cc b/ash/assistant/ui/base/assistant_button.cc index 4695274..37bb81eb 100644 --- a/ash/assistant/ui/base/assistant_button.cc +++ b/ash/assistant/ui/base/assistant_button.cc
@@ -4,7 +4,11 @@ #include "ash/assistant/ui/base/assistant_button.h" +#include "ash/assistant/model/assistant_ui_model.h" #include "ash/assistant/util/histogram_util.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/color_utils.h" +#include "ui/gfx/paint_vector_icon.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" @@ -43,6 +47,22 @@ AssistantButton::~AssistantButton() = default; +// static +views::ImageButton* AssistantButton::Create(views::ButtonListener* listener, + const gfx::VectorIcon& icon, + int size_in_dip, + int icon_size_in_dip, + int accessible_name_id, + AssistantButtonId button_id, + SkColor icon_color) { + auto* button = new AssistantButton(listener, button_id); + button->SetAccessibleName(l10n_util::GetStringUTF16(accessible_name_id)); + button->SetImage(views::Button::STATE_NORMAL, + gfx::CreateVectorIcon(icon, icon_size_in_dip, icon_color)); + button->SetPreferredSize(gfx::Size(size_in_dip, size_in_dip)); + return button; +} + const char* AssistantButton::GetClassName() const { return "AssistantButton"; }
diff --git a/ash/assistant/ui/base/assistant_button.h b/ash/assistant/ui/base/assistant_button.h index 46ae8386..c4079fe 100644 --- a/ash/assistant/ui/base/assistant_button.h +++ b/ash/assistant/ui/base/assistant_button.h
@@ -8,22 +8,22 @@ #include <memory> #include "base/macros.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/color_palette.h" #include "ui/views/controls/button/image_button.h" +namespace gfx { +struct VectorIcon; +} // namespace gfx + +namespace views { +class ButtonListener; +class ImageButton; +} // namespace views + namespace ash { -// Enumeration of Assistant button ID. These values are persisted to logs. -// Entries should not be renumbered and numeric values should never be reused. -// Only append to this enum is allowed if more buttons will be added. -enum class AssistantButtonId { - kBack = 1, - kClose = 2, - kMinimize = 3, - kKeyboardInputToggle = 4, - kVoiceInputToggle = 5, - kSettings = 6, - kMaxValue = kSettings, -}; +enum class AssistantButtonId; class AssistantButton : public views::ImageButton, public views::ButtonListener { @@ -31,6 +31,15 @@ AssistantButton(views::ButtonListener* listener, AssistantButtonId button_id); ~AssistantButton() override; + // Creates an ImageButton with the default Assistant styles. + static views::ImageButton* Create(views::ButtonListener* listener, + const gfx::VectorIcon& icon, + int size_in_dip, + int icon_size_in_dip, + int accessible_name_id, + AssistantButtonId button_id, + SkColor icon_color = gfx::kGoogleGrey700); + // views::Button: const char* GetClassName() const override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
diff --git a/ash/assistant/ui/caption_bar.cc b/ash/assistant/ui/caption_bar.cc index b0a57c1..b8145135 100644 --- a/ash/assistant/ui/caption_bar.cc +++ b/ash/assistant/ui/caption_bar.cc
@@ -6,9 +6,9 @@ #include <memory> +#include "ash/assistant/model/assistant_ui_model.h" #include "ash/assistant/ui/assistant_ui_constants.h" #include "ash/assistant/ui/base/assistant_button.h" -#include "ash/assistant/util/views_util.h" #include "ash/public/cpp/vector_icons/vector_icons.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ui/gfx/color_palette.h" @@ -34,9 +34,9 @@ int accessible_name_id, AssistantButtonId button_id, views::ButtonListener* listener) { - return assistant::util::CreateImageButton( - listener, icon, kCaptionButtonSizeDip, kVectorIconSizeDip, - accessible_name_id, button_id, gfx::kGoogleGrey700); + return AssistantButton::Create(listener, icon, kCaptionButtonSizeDip, + kVectorIconSizeDip, accessible_name_id, + button_id, gfx::kGoogleGrey700); } } // namespace
diff --git a/ash/assistant/ui/dialog_plate/action_view.cc b/ash/assistant/ui/dialog_plate/action_view.cc index 330b82df..a550dfd 100644 --- a/ash/assistant/ui/dialog_plate/action_view.cc +++ b/ash/assistant/ui/dialog_plate/action_view.cc
@@ -6,9 +6,9 @@ #include <memory> +#include "ash/assistant/model/assistant_ui_model.h" #include "ash/assistant/ui/assistant_view_delegate.h" #include "ash/assistant/ui/logo_view/base_logo_view.h" -#include "ash/assistant/util/views_util.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h"
diff --git a/ash/assistant/ui/dialog_plate/action_view.h b/ash/assistant/ui/dialog_plate/action_view.h index ed9de3f..0390584 100644 --- a/ash/assistant/ui/dialog_plate/action_view.h +++ b/ash/assistant/ui/dialog_plate/action_view.h
@@ -12,6 +12,7 @@ namespace ash { class ActionView; +enum class AssistantButtonId; class AssistantViewDelegate; class BaseLogoView;
diff --git a/ash/assistant/ui/dialog_plate/dialog_plate.cc b/ash/assistant/ui/dialog_plate/dialog_plate.cc index 3fd5732..3735d3f 100644 --- a/ash/assistant/ui/dialog_plate/dialog_plate.cc +++ b/ash/assistant/ui/dialog_plate/dialog_plate.cc
@@ -4,10 +4,11 @@ #include "ash/assistant/ui/dialog_plate/dialog_plate.h" +#include "ash/assistant/model/assistant_ui_model.h" #include "ash/assistant/ui/assistant_ui_constants.h" #include "ash/assistant/ui/assistant_view_delegate.h" +#include "ash/assistant/ui/base/assistant_button.h" #include "ash/assistant/util/animation_util.h" -#include "ash/assistant/util/views_util.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/strings/grit/ash_strings.h" #include "base/bind.h" @@ -284,10 +285,10 @@ InitVoiceLayoutContainer(); // Settings. - settings_button_ = assistant::util::CreateImageButton( - this, kSettingsIcon, kButtonSizeDip, kIconSizeDip, - IDS_ASH_ASSISTANT_DIALOG_PLATE_SETTINGS_ACCNAME, - AssistantButtonId::kSettings); + settings_button_ = + AssistantButton::Create(this, kSettingsIcon, kButtonSizeDip, kIconSizeDip, + IDS_ASH_ASSISTANT_DIALOG_PLATE_SETTINGS_ACCNAME, + AssistantButtonId::kSettings); AddChildView(settings_button_); // Artificially trigger event to set initial state. @@ -333,10 +334,10 @@ layout_manager->SetFlexForView(textfield_, 1); // Voice input toggle. - voice_input_toggle_ = assistant::util::CreateImageButton( - this, kMicIcon, kButtonSizeDip, kIconSizeDip, - IDS_ASH_ASSISTANT_DIALOG_PLATE_MIC_ACCNAME, - AssistantButtonId::kVoiceInputToggle); + voice_input_toggle_ = + AssistantButton::Create(this, kMicIcon, kButtonSizeDip, kIconSizeDip, + IDS_ASH_ASSISTANT_DIALOG_PLATE_MIC_ACCNAME, + AssistantButtonId::kVoiceInputToggle); keyboard_layout_container_->AddChildView(voice_input_toggle_); input_modality_layout_container_->AddChildView(keyboard_layout_container_); @@ -358,10 +359,10 @@ views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER); // Keyboard input toggle. - keyboard_input_toggle_ = assistant::util::CreateImageButton( - this, kKeyboardIcon, kButtonSizeDip, kIconSizeDip, - IDS_ASH_ASSISTANT_DIALOG_PLATE_KEYBOARD_ACCNAME, - AssistantButtonId::kKeyboardInputToggle); + keyboard_input_toggle_ = + AssistantButton::Create(this, kKeyboardIcon, kButtonSizeDip, kIconSizeDip, + IDS_ASH_ASSISTANT_DIALOG_PLATE_KEYBOARD_ACCNAME, + AssistantButtonId::kKeyboardInputToggle); voice_layout_container_->AddChildView(keyboard_input_toggle_); // Spacer.
diff --git a/ash/assistant/ui/dialog_plate/dialog_plate.h b/ash/assistant/ui/dialog_plate/dialog_plate.h index ac45d8ff..fee0767 100644 --- a/ash/assistant/ui/dialog_plate/dialog_plate.h +++ b/ash/assistant/ui/dialog_plate/dialog_plate.h
@@ -29,6 +29,7 @@ namespace ash { class ActionView; +enum class AssistantButtonId; class AssistantViewDelegate; // DialogPlateObserver ---------------------------------------------------------
diff --git a/ash/assistant/util/BUILD.gn b/ash/assistant/util/BUILD.gn new file mode 100644 index 0000000..6f388218 --- /dev/null +++ b/ash/assistant/util/BUILD.gn
@@ -0,0 +1,33 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_chromeos) + +component("util") { + output_name = "assistant_util" + + defines = [ "IS_ASSISTANT_UTIL_IMPL" ] + + sources = [ + "animation_util.cc", + "animation_util.h", + "assistant_util.cc", + "assistant_util.h", + "deep_link_util.cc", + "deep_link_util.h", + "histogram_util.cc", + "histogram_util.h", + ] + + deps = [ + "//ash/assistant/model", + "//base", + "//base:i18n", + "//net", + "//ui/base", + "//ui/gfx", + "//ui/views", + "//url", + ] +}
diff --git a/ash/assistant/util/DEPS b/ash/assistant/util/DEPS new file mode 100644 index 0000000..40905a7 --- /dev/null +++ b/ash/assistant/util/DEPS
@@ -0,0 +1,16 @@ +include_rules = [ + "-ash", + "+ash/assistant/model", + "+ash/assistant/util", + "+net", + "+ui/base", + "+ui/gfx", + "+ui/views", + "+url", +] + +specific_include_rules = { + "deep_link_util_unittest\.cc": [ + "+ash/test/ash_test_base.h", + ], +}
diff --git a/ash/assistant/util/animation_util.h b/ash/assistant/util/animation_util.h index 4d4bf3a..a3e31e27 100644 --- a/ash/assistant/util/animation_util.h +++ b/ash/assistant/util/animation_util.h
@@ -8,6 +8,7 @@ #include <memory> #include <vector> +#include "base/component_export.h" #include "ui/gfx/animation/tween.h" namespace base { @@ -34,6 +35,7 @@ // Creates a LayerAnimationSequence containing the specified // LayerAnimationElements with the given |params|. The method caller assumes // ownership of the returned pointer. +COMPONENT_EXPORT(ASSISTANT_UTIL) ::ui::LayerAnimationSequence* CreateLayerAnimationSequence( std::unique_ptr<::ui::LayerAnimationElement> a, const LayerAnimationSequenceParams& params = {}); @@ -41,6 +43,7 @@ // Creates a LayerAnimationSequence containing the specified // LayerAnimationElements with the given |params|. The method caller assumes // ownership of the returned pointer. +COMPONENT_EXPORT(ASSISTANT_UTIL) ::ui::LayerAnimationSequence* CreateLayerAnimationSequence( std::unique_ptr<::ui::LayerAnimationElement> a, std::unique_ptr<::ui::LayerAnimationElement> b, @@ -49,6 +52,7 @@ // Creates a LayerAnimationSequence containing the specified // LayerAnimationElements with the given |params|. The method caller assumes // ownership of the returned pointer. +COMPONENT_EXPORT(ASSISTANT_UTIL) ::ui::LayerAnimationSequence* CreateLayerAnimationSequence( std::unique_ptr<::ui::LayerAnimationElement> a, std::unique_ptr<::ui::LayerAnimationElement> b, @@ -58,6 +62,7 @@ // Creates a LayerAnimationSequence containing the specified // LayerAnimationElements with the given |params|. The method caller assumes // ownership of the returned pointer. +COMPONENT_EXPORT(ASSISTANT_UTIL) ::ui::LayerAnimationSequence* CreateLayerAnimationSequence( std::unique_ptr<::ui::LayerAnimationElement> a, std::unique_ptr<::ui::LayerAnimationElement> b, @@ -66,6 +71,7 @@ const LayerAnimationSequenceParams& params = {}); // Creates a LayerAnimationElement to animate opacity with the given parameters. +COMPONENT_EXPORT(ASSISTANT_UTIL) std::unique_ptr<::ui::LayerAnimationElement> CreateOpacityElement( float opacity, const base::TimeDelta& duration, @@ -73,7 +79,8 @@ // Creates a LayerAnimationElement to animate transform with the given // parameters. -::std::unique_ptr<::ui::LayerAnimationElement> CreateTransformElement( +COMPONENT_EXPORT(ASSISTANT_UTIL) +std::unique_ptr<::ui::LayerAnimationElement> CreateTransformElement( const gfx::Transform& transform, const base::TimeDelta& duration, const gfx::Tween::Type& tween = gfx::Tween::Type::LINEAR); @@ -81,6 +88,7 @@ // Starts the specified |layer_animation_sequence| on the given // |layer_animator|. If an optional |observer| is supplied, it will be added to // the sequence. +COMPONENT_EXPORT(ASSISTANT_UTIL) void StartLayerAnimationSequence( ::ui::LayerAnimator* layer_animator, ::ui::LayerAnimationSequence* layer_animation_sequence, @@ -89,6 +97,7 @@ // Starts the specified |layer_animation_sequences| together on the given // |layer_animator|. If an optional |observer| is supplied, it will be added // to each sequence in the animation set. +COMPONENT_EXPORT(ASSISTANT_UTIL) void StartLayerAnimationSequencesTogether( ::ui::LayerAnimator* layer_animator, const std::vector<::ui::LayerAnimationSequence*>& layer_animation_sequences,
diff --git a/ash/assistant/util/assistant_util.h b/ash/assistant/util/assistant_util.h index 33a1db1..06d13094 100644 --- a/ash/assistant/util/assistant_util.h +++ b/ash/assistant/util/assistant_util.h
@@ -5,6 +5,8 @@ #ifndef ASH_ASSISTANT_UTIL_ASSISTANT_UTIL_H_ #define ASH_ASSISTANT_UTIL_ASSISTANT_UTIL_H_ +#include "base/component_export.h" + namespace ash { enum class AssistantVisibility; @@ -13,10 +15,12 @@ namespace util { // Returns true if Assistant is starting a new session, false otherwise. +COMPONENT_EXPORT(ASSISTANT_UTIL) bool IsStartingSession(AssistantVisibility new_visibility, AssistantVisibility old_visibility); // Returns true if Assistant is finishing a session, false otherwise. +COMPONENT_EXPORT(ASSISTANT_UTIL) bool IsFinishingSession(AssistantVisibility new_visibility); } // namespace util
diff --git a/ash/assistant/util/deep_link_util.h b/ash/assistant/util/deep_link_util.h index 09d181ce..41ed5ea4 100644 --- a/ash/assistant/util/deep_link_util.h +++ b/ash/assistant/util/deep_link_util.h
@@ -8,7 +8,7 @@ #include <map> #include <string> -#include "ash/ash_export.h" +#include "base/component_export.h" #include "base/optional.h" class GURL; @@ -40,67 +40,75 @@ }; // Returns a deep link to send an Assistant query. -ASH_EXPORT GURL CreateAssistantQueryDeepLink(const std::string& query); +COMPONENT_EXPORT(ASSISTANT_UTIL) +GURL CreateAssistantQueryDeepLink(const std::string& query); // Returns a deep link to top level Assistant Settings. -ASH_EXPORT GURL CreateAssistantSettingsDeepLink(); +COMPONENT_EXPORT(ASSISTANT_UTIL) GURL CreateAssistantSettingsDeepLink(); // Returns a deep link to initiate a screen context interaction. -ASH_EXPORT GURL CreateWhatsOnMyScreenDeepLink(); +COMPONENT_EXPORT(ASSISTANT_UTIL) GURL CreateWhatsOnMyScreenDeepLink(); // Returns the parsed parameters for the specified |deep_link|. If the supplied // argument is not a supported deep link or if no parameters are found, an empty // map is returned. -ASH_EXPORT std::map<std::string, std::string> GetDeepLinkParams( - const GURL& deep_link); +COMPONENT_EXPORT(ASSISTANT_UTIL) +std::map<std::string, std::string> GetDeepLinkParams(const GURL& deep_link); // Returns a specific string |param| from the given parameters. If the desired // parameter is not found, and empty value is returned. -ASH_EXPORT base::Optional<std::string> GetDeepLinkParam( +COMPONENT_EXPORT(ASSISTANT_UTIL) +base::Optional<std::string> GetDeepLinkParam( const std::map<std::string, std::string>& params, DeepLinkParam param); // Returns a specific bool |param| from the given parameters. If the desired // parameter is not found or is not a bool, an empty value is returned. -ASH_EXPORT base::Optional<bool> GetDeepLinkParamAsBool( +COMPONENT_EXPORT(ASSISTANT_UTIL) +base::Optional<bool> GetDeepLinkParamAsBool( const std::map<std::string, std::string>& params, DeepLinkParam param); // Returns the deep link type of the specified |url|. If the specified url is // not a supported deep link, DeepLinkType::kUnsupported is returned. -ASH_EXPORT DeepLinkType GetDeepLinkType(const GURL& url); +COMPONENT_EXPORT(ASSISTANT_UTIL) DeepLinkType GetDeepLinkType(const GURL& url); // Returns true if the specified |url| is a deep link of the given |type|. -ASH_EXPORT bool IsDeepLinkType(const GURL& url, DeepLinkType type); +COMPONENT_EXPORT(ASSISTANT_UTIL) +bool IsDeepLinkType(const GURL& url, DeepLinkType type); // Returns true if the specified |url| is a deep link, false otherwise. -ASH_EXPORT bool IsDeepLinkUrl(const GURL& url); +COMPONENT_EXPORT(ASSISTANT_UTIL) bool IsDeepLinkUrl(const GURL& url); // Returns the URL for the specified Assistant reminder |id|. If id is absent, // the returned URL will be for top-level Assistant Reminders. -ASH_EXPORT GURL GetAssistantRemindersUrl(const base::Optional<std::string>& id); +COMPONENT_EXPORT(ASSISTANT_UTIL) +GURL GetAssistantRemindersUrl(const base::Optional<std::string>& id); // Returns the URL for the specified Chrome Settings |page|. If page is absent // or not allowed, the URL will be for top-level Chrome Settings. -ASH_EXPORT GURL GetChromeSettingsUrl(const base::Optional<std::string>& page); +COMPONENT_EXPORT(ASSISTANT_UTIL) +GURL GetChromeSettingsUrl(const base::Optional<std::string>& page); // Returns the web URL for the specified |deep_link|. A return value will only // be present if |deep_link| is a web deep link as identified by the // IsWebDeepLink(GURL) API. -ASH_EXPORT base::Optional<GURL> GetWebUrl(const GURL& deep_link); +COMPONENT_EXPORT(ASSISTANT_UTIL) +base::Optional<GURL> GetWebUrl(const GURL& deep_link); // Returns the web URL for a deep link of the specified |type| with the given // |params|. A return value will only be present if the deep link type is a web // deep link type as identified by the IsWebDeepLinkType(DeepLinkType) API. -ASH_EXPORT base::Optional<GURL> GetWebUrl( +COMPONENT_EXPORT(ASSISTANT_UTIL) +base::Optional<GURL> GetWebUrl( DeepLinkType type, const std::map<std::string, std::string>& params); // Returns true if the specified |deep_link| is a web deep link. -ASH_EXPORT bool IsWebDeepLink(const GURL& deep_link); +COMPONENT_EXPORT(ASSISTANT_UTIL) bool IsWebDeepLink(const GURL& deep_link); // Returns true if the specified deep link |type| is a web deep link. -ASH_EXPORT bool IsWebDeepLinkType(DeepLinkType type); +COMPONENT_EXPORT(ASSISTANT_UTIL) bool IsWebDeepLinkType(DeepLinkType type); } // namespace util } // namespace assistant
diff --git a/ash/assistant/util/histogram_util.cc b/ash/assistant/util/histogram_util.cc index 6bd722c..52f0657 100644 --- a/ash/assistant/util/histogram_util.cc +++ b/ash/assistant/util/histogram_util.cc
@@ -6,7 +6,6 @@ #include "ash/assistant/model/assistant_query.h" #include "ash/assistant/model/assistant_ui_model.h" -#include "ash/assistant/ui/base/assistant_button.h" #include "base/metrics/histogram_macros.h" namespace ash {
diff --git a/ash/assistant/util/histogram_util.h b/ash/assistant/util/histogram_util.h index 3506df8..d72b951d 100644 --- a/ash/assistant/util/histogram_util.h +++ b/ash/assistant/util/histogram_util.h
@@ -5,29 +5,36 @@ #ifndef ASH_ASSISTANT_UTIL_HISTOGRAM_UTIL_H_ #define ASH_ASSISTANT_UTIL_HISTOGRAM_UTIL_H_ +#include "base/component_export.h" + namespace ash { +enum class AssistantButtonId; enum class AssistantEntryPoint; enum class AssistantExitPoint; -enum class AssistantButtonId; enum class AssistantQuerySource; namespace assistant { namespace util { // Increment number of queries fired for each entry point. +COMPONENT_EXPORT(ASSISTANT_UTIL) void IncrementAssistantQueryCountForEntryPoint(AssistantEntryPoint entry_point); // Record the entry point where Assistant UI becomes visible. +COMPONENT_EXPORT(ASSISTANT_UTIL) void RecordAssistantEntryPoint(AssistantEntryPoint entry_point); // Record the exit point where Assistant UI becomes invisible. +COMPONENT_EXPORT(ASSISTANT_UTIL) void RecordAssistantExitPoint(AssistantExitPoint exit_point); // Count the number of times buttons are clicked on Assistant UI. +COMPONENT_EXPORT(ASSISTANT_UTIL) void IncrementAssistantButtonClickCount(AssistantButtonId button_id); // Record the input source of each query (e.g. voice, typing). +COMPONENT_EXPORT(ASSISTANT_UTIL) void RecordAssistantQuerySource(AssistantQuerySource source); } // namespace util
diff --git a/ash/assistant/util/views_util.cc b/ash/assistant/util/views_util.cc deleted file mode 100644 index dbd986d..0000000 --- a/ash/assistant/util/views_util.cc +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/assistant/util/views_util.h" - -#include <memory> - -#include "ash/assistant/ui/base/assistant_button.h" -#include "base/macros.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/color_utils.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/controls/button/image_button.h" - -namespace ash { -namespace assistant { -namespace util { - -views::ImageButton* CreateImageButton(views::ButtonListener* listener, - const gfx::VectorIcon& icon, - int size_in_dip, - int icon_size_in_dip, - int accessible_name_id, - AssistantButtonId button_id, - SkColor icon_color) { - auto* button = new AssistantButton(listener, button_id); - button->SetAccessibleName(l10n_util::GetStringUTF16(accessible_name_id)); - button->SetImage(views::Button::STATE_NORMAL, - gfx::CreateVectorIcon(icon, icon_size_in_dip, icon_color)); - button->SetPreferredSize(gfx::Size(size_in_dip, size_in_dip)); - return button; -} - -} // namespace util -} // namespace assistant -} // namespace ash
diff --git a/ash/assistant/util/views_util.h b/ash/assistant/util/views_util.h deleted file mode 100644 index 558a2b3..0000000 --- a/ash/assistant/util/views_util.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_ASSISTANT_UTIL_VIEWS_UTIL_H_ -#define ASH_ASSISTANT_UTIL_VIEWS_UTIL_H_ - -#include "base/optional.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/color_palette.h" - -namespace gfx { -struct VectorIcon; -} // namespace gfx - -namespace views { -class ButtonListener; -class ImageButton; -} // namespace views - -namespace ash { - -enum class AssistantButtonId; - -namespace assistant { -namespace util { - -// Creates an ImageButton with the default Assistant styles. -views::ImageButton* CreateImageButton(views::ButtonListener* listener, - const gfx::VectorIcon& icon, - int size_in_dip, - int icon_size_in_dip, - int accessible_name_id, - AssistantButtonId button_id, - SkColor icon_color = gfx::kGoogleGrey700); - -} // namespace util -} // namespace assistant -} // namespace ash -#endif // ASH_ASSISTANT_UTIL_VIEWS_UTIL_H_
diff --git a/ash/display/root_window_transformers.cc b/ash/display/root_window_transformers.cc index 0e0bd29..54c4932 100644 --- a/ash/display/root_window_transformers.cc +++ b/ash/display/root_window_transformers.cc
@@ -55,13 +55,6 @@ return transform; } -gfx::Transform CreateMirrorTransform(const display::Display& display) { - gfx::Transform transform; - transform.matrix().set3x3(-1, 0, 0, 0, 1, 0, 0, 0, 1); - transform.Translate(-display.size().width(), 0); - return transform; -} - // RootWindowTransformer for ash environment. class AshRootWindowTransformer : public RootWindowTransformer { public: @@ -75,14 +68,6 @@ CreateInsetsAndScaleTransform(host_insets_, display.device_scale_factor()) * CreateRootWindowRotationTransform(root, display); - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshEnableMirroredScreen)) { - // Apply the transform that flips the screen image horizontally so that - // the screen looks normal when reflected on a mirror. - root_window_bounds_transform_ = - root_window_bounds_transform_ * CreateMirrorTransform(display); - } - transform_ = root_window_bounds_transform_; MagnificationController* magnifier = Shell::Get()->magnification_controller();
diff --git a/ash/frame/non_client_frame_view_ash.cc b/ash/frame/non_client_frame_view_ash.cc index fd287bcd..af18ac2 100644 --- a/ash/frame/non_client_frame_view_ash.cc +++ b/ash/frame/non_client_frame_view_ash.cc
@@ -17,7 +17,7 @@ #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h" #include "ash/public/cpp/window_properties.h" #include "ash/shell.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_observer.h" #include "ash/wm/window_state.h" @@ -458,14 +458,14 @@ void NonClientFrameViewAsh::UpdateHeaderView() { SplitViewController* split_view_controller = Shell::Get()->split_view_controller(); - if (in_overview_mode_ && split_view_controller->IsSplitViewModeActive() && + if (in_overview_ && split_view_controller->IsSplitViewModeActive() && split_view_controller->GetDefaultSnappedWindow() == frame_->GetNativeWindow()) { // TODO(sammiequon): This works for now, but we may have to check if // |frame_|'s native window is in the overview list instead. SetShouldPaintHeader(true); } else { - SetShouldPaintHeader(!in_overview_mode_); + SetShouldPaintHeader(!in_overview_); } } @@ -474,12 +474,12 @@ } void NonClientFrameViewAsh::OnOverviewModeStarting() { - in_overview_mode_ = true; + in_overview_ = true; UpdateHeaderView(); } void NonClientFrameViewAsh::OnOverviewModeEnded() { - in_overview_mode_ = false; + in_overview_ = false; UpdateHeaderView(); }
diff --git a/ash/frame/non_client_frame_view_ash.h b/ash/frame/non_client_frame_view_ash.h index b73698c..5d64b08 100644 --- a/ash/frame/non_client_frame_view_ash.h +++ b/ash/frame/non_client_frame_view_ash.h
@@ -178,9 +178,9 @@ // Track whether the device is in overview mode. Set this to true when // overview mode started and false when overview mode finished. Use this to // check whether we should paint when splitview state changes instead of - // Shell::Get()->window_selector_controller()->IsSelecting() because the + // Shell::Get()->overview_controller()->IsSelecting() because the // later actually may be still be false after overview mode has started. - bool in_overview_mode_ = false; + bool in_overview_ = false; // Helpers for the context menu users will see when right-clicking on // |header_view_|.
diff --git a/ash/frame/non_client_frame_view_ash_unittest.cc b/ash/frame/non_client_frame_view_ash_unittest.cc index 2404f76..cf4bc85d 100644 --- a/ash/frame/non_client_frame_view_ash_unittest.cc +++ b/ash/frame/non_client_frame_view_ash_unittest.cc
@@ -19,7 +19,7 @@ #include "ash/resources/vector_icons/vector_icons.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" #include "ash/wm/window_state_delegate.h" @@ -431,10 +431,10 @@ // Verify the header is not painted in overview mode and painted when not in // overview mode. - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_FALSE(delegate->header_view()->should_paint()); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_TRUE(delegate->header_view()->should_paint()); } @@ -458,7 +458,7 @@ // Verify that when one window is snapped, the header is drawn for the snapped // window, but not drawn for the window still in overview. - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); Shell::Get()->split_view_controller()->SnapWindow(widget1->GetNativeWindow(), SplitViewController::LEFT); EXPECT_TRUE(delegate1->header_view()->should_paint()); @@ -476,7 +476,7 @@ // Toggle overview mode so we return back to left snapped mode. Verify that // the header is again drawn for the snapped window, but not for the unsnapped // window. - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); ASSERT_EQ(SplitViewController::LEFT_SNAPPED, Shell::Get()->split_view_controller()->state()); EXPECT_TRUE(delegate1->header_view()->should_paint()); @@ -722,9 +722,9 @@ EXPECT_FALSE(header_view->should_paint()); EXPECT_TRUE(wide_header_view->should_paint()); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_FALSE(wide_header_view->should_paint()); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_TRUE(wide_header_view->should_paint()); // Test immersive.
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc index c3b34725..5eb16225 100644 --- a/ash/login/ui/lock_contents_view.cc +++ b/ash/login/ui/lock_contents_view.cc
@@ -42,6 +42,7 @@ #include "components/user_manager/user_type.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/ui_base_features.h" #include "ui/display/display.h" #include "ui/display/manager/display_manager.h" #include "ui/display/manager/managed_display_info.h" @@ -388,7 +389,7 @@ system_info_ = new views::View(); auto* system_info_layout = system_info_->SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::kVertical, gfx::Insets(5, 8))); + views::BoxLayout::kVertical, gfx::Insets(6, 8))); system_info_layout->set_cross_axis_alignment( views::BoxLayout::CROSS_AXIS_ALIGNMENT_END); system_info_->SetVisible(false); @@ -880,6 +881,8 @@ for (int i = 0; i < 3; ++i) system_info_->AddChildView(create_info_label()); } + if (::features::IsSingleProcessMash()) + system_info_->AddChildView(create_info_label()); if (show) system_info_->SetVisible(true); @@ -893,6 +896,8 @@ update_label(0, os_version_label_text); update_label(1, enterprise_info_text); update_label(2, bluetooth_name); + if (::features::IsSingleProcessMash()) + update_label(3, "SingleProcessMash"); LayoutTopHeader(); }
diff --git a/ash/login/ui/login_expanded_public_account_view.cc b/ash/login/ui/login_expanded_public_account_view.cc index 44132a4..b2c5f33 100644 --- a/ash/login/ui/login_expanded_public_account_view.cc +++ b/ash/login/ui/login_expanded_public_account_view.cc
@@ -87,6 +87,36 @@ return label; } +class LoginExpandedPublicAccountEventHandler : public ui::EventHandler { + public: + explicit LoginExpandedPublicAccountEventHandler( + LoginExpandedPublicAccountView* view) + : view_(view) { + Shell::Get()->AddPreTargetHandler(this); + } + ~LoginExpandedPublicAccountEventHandler() override { + Shell::Get()->RemovePreTargetHandler(this); + } + + private: + // ui::EventHandler: + void OnMouseEvent(ui::MouseEvent* event) override { + if (event->type() == ui::ET_MOUSE_PRESSED) + view_->ProcessPressedEvent(event->AsLocatedEvent()); + } + void OnGestureEvent(ui::GestureEvent* event) override { + if ((event->type() == ui::ET_GESTURE_TAP || + event->type() == ui::ET_GESTURE_TAP_DOWN)) { + view_->ProcessPressedEvent(event->AsLocatedEvent()); + } + } + void OnKeyEvent(ui::KeyEvent* event) override { view_->OnKeyEvent(event); } + + LoginExpandedPublicAccountView* view_; + + DISALLOW_COPY_AND_ASSIGN(LoginExpandedPublicAccountEventHandler); +}; + } // namespace // Button with text on the left side and an icon on the right side. @@ -648,8 +678,9 @@ LoginExpandedPublicAccountView::LoginExpandedPublicAccountView( const OnPublicSessionViewDismissed& on_dismissed) : NonAccessibleView(kLoginExpandedPublicAccountViewClassName), - on_dismissed_(on_dismissed) { - Shell::Get()->AddPreTargetHandler(this); + on_dismissed_(on_dismissed), + event_handler_( + std::make_unique<LoginExpandedPublicAccountEventHandler>(this)) { SetLayoutManager( std::make_unique<views::BoxLayout>(views::BoxLayout::kHorizontal)); SetPreferredSize(gfx::Size(kExpandedViewWidthDp, kExpandedViewHeightDp)); @@ -681,9 +712,7 @@ AddChildView(right_pane_); } -LoginExpandedPublicAccountView::~LoginExpandedPublicAccountView() { - Shell::Get()->RemovePreTargetHandler(this); -} +LoginExpandedPublicAccountView::~LoginExpandedPublicAccountView() = default; void LoginExpandedPublicAccountView::ProcessPressedEvent( const ui::LocatedEvent* event) { @@ -759,18 +788,6 @@ canvas->DrawRoundRect(GetContentsBounds(), kRoundRectCornerRadiusDp, flags); } -void LoginExpandedPublicAccountView::OnMouseEvent(ui::MouseEvent* event) { - if (event->type() == ui::ET_MOUSE_PRESSED) - ProcessPressedEvent(event->AsLocatedEvent()); -} - -void LoginExpandedPublicAccountView::OnGestureEvent(ui::GestureEvent* event) { - if ((event->type() == ui::ET_GESTURE_TAP || - event->type() == ui::ET_GESTURE_TAP_DOWN)) { - ProcessPressedEvent(event->AsLocatedEvent()); - } -} - void LoginExpandedPublicAccountView::OnKeyEvent(ui::KeyEvent* event) { if (!visible() || event->type() != ui::ET_KEY_PRESSED) return;
diff --git a/ash/login/ui/login_expanded_public_account_view.h b/ash/login/ui/login_expanded_public_account_view.h index 9c29c3ea..a044503 100644 --- a/ash/login/ui/login_expanded_public_account_view.h +++ b/ash/login/ui/login_expanded_public_account_view.h
@@ -5,6 +5,8 @@ #ifndef ASH_LOGIN_UI_LOGIN_EXPANDED_PUBLIC_ACCOUNT_VIEW_H_ #define ASH_LOGIN_UI_LOGIN_EXPANDED_PUBLIC_ACCOUNT_VIEW_H_ +#include <memory> + #include "ash/ash_export.h" #include "ash/login/ui/login_menu_view.h" #include "ash/login/ui/non_accessible_view.h" @@ -65,8 +67,6 @@ void OnPaint(gfx::Canvas* canvas) override; // ui::EventHandler: - void OnMouseEvent(ui::MouseEvent* event) override; - void OnGestureEvent(ui::GestureEvent* event) override; void OnKeyEvent(ui::KeyEvent* event) override; private: @@ -74,6 +74,7 @@ RightPaneView* right_pane_ = nullptr; OnPublicSessionViewDismissed on_dismissed_; PublicAccountWarningDialog* warning_dialog_ = nullptr; + std::unique_ptr<ui::EventHandler> event_handler_; base::WeakPtrFactory<LoginExpandedPublicAccountView> weak_factory_{this};
diff --git a/ash/login/ui/login_expanded_public_account_view_unittest.cc b/ash/login/ui/login_expanded_public_account_view_unittest.cc index 0484457..3342c93 100644 --- a/ash/login/ui/login_expanded_public_account_view_unittest.cc +++ b/ash/login/ui/login_expanded_public_account_view_unittest.cc
@@ -34,7 +34,9 @@ constexpr char kKeyboardIdForItem2[] = "keyboard_id2"; constexpr char kKeyboardNameForItem2[] = "keyboard2"; -class LoginExpandedPublicAccountViewTest : public LoginTestBase { +class LoginExpandedPublicAccountViewTest + : public LoginTestBase, + public ::testing::WithParamInterface<const char*> { protected: LoginExpandedPublicAccountViewTest() = default; ~LoginExpandedPublicAccountViewTest() override = default; @@ -95,9 +97,16 @@ } void TapOnView(views::View* tap_target) { - GetEventGenerator()->MoveMouseTo( - tap_target->GetBoundsInScreen().CenterPoint()); - GetEventGenerator()->ClickLeftButton(); + if (GetParam() == std::string("mouse")) { + GetEventGenerator()->MoveMouseTo( + tap_target->GetBoundsInScreen().CenterPoint()); + GetEventGenerator()->ClickLeftButton(); + } else { + GetEventGenerator()->MoveTouch( + tap_target->GetBoundsInScreen().CenterPoint()); + GetEventGenerator()->PressTouch(); + GetEventGenerator()->ReleaseTouch(); + } } mojom::LoginUserInfoPtr user_; @@ -114,7 +123,7 @@ } // namespace // Verifies toggle advanced view will update the layout correctly. -TEST_F(LoginExpandedPublicAccountViewTest, ToggleAdvancedView) { +TEST_P(LoginExpandedPublicAccountViewTest, ToggleAdvancedView) { public_account_->SizeToPreferredSize(); EXPECT_EQ(public_account_->width(), kBubbleTotalWidthDp); EXPECT_EQ(public_account_->height(), kBubbleTotalHeightDp); @@ -142,7 +151,7 @@ } // Verifies warning dialog shows up correctly. -TEST_F(LoginExpandedPublicAccountViewTest, ShowWarningDialog) { +TEST_P(LoginExpandedPublicAccountViewTest, ShowWarningDialog) { LoginExpandedPublicAccountView::TestApi test_api(public_account_); views::StyledLabel::TestApi styled_label_test(test_api.learn_more_label()); EXPECT_EQ(test_api.warning_dialog(), nullptr); @@ -150,17 +159,13 @@ // Tap on the learn more link. views::View* link_view = styled_label_test.link_targets().begin()->first; - GetEventGenerator()->MoveMouseTo( - link_view->GetBoundsInScreen().CenterPoint()); - GetEventGenerator()->ClickLeftButton(); + TapOnView(link_view); EXPECT_NE(test_api.warning_dialog(), nullptr); EXPECT_TRUE(test_api.warning_dialog()->IsVisible()); // When warning dialog is shown, tap outside of public account expanded view // should not hide it. - GetEventGenerator()->MoveMouseTo( - other_view_->GetBoundsInScreen().CenterPoint()); - GetEventGenerator()->ClickLeftButton(); + TapOnView(other_view_); EXPECT_TRUE(public_account_->visible()); EXPECT_NE(test_api.warning_dialog(), nullptr); EXPECT_TRUE(test_api.warning_dialog()->IsVisible()); @@ -184,7 +189,7 @@ } // Verifies tap on submit button will try to launch public session. -TEST_F(LoginExpandedPublicAccountViewTest, LaunchPublicSession) { +TEST_P(LoginExpandedPublicAccountViewTest, LaunchPublicSession) { LoginExpandedPublicAccountView::TestApi test_api(public_account_); // Verify the language and keyboard information is populated correctly. @@ -205,7 +210,7 @@ } // Verifies both language and keyboard menus shows up correctly. -TEST_F(LoginExpandedPublicAccountViewTest, ShowLanguageAndKeyboardMenu) { +TEST_P(LoginExpandedPublicAccountViewTest, ShowLanguageAndKeyboardMenu) { LoginExpandedPublicAccountView::TestApi test_api(public_account_); EXPECT_FALSE(user_->public_account_info->show_advanced_view); EXPECT_FALSE(test_api.advanced_view()->visible()); @@ -248,7 +253,7 @@ EXPECT_EQ(nullptr, test_api.keyboard_menu_view()); } -TEST_F(LoginExpandedPublicAccountViewTest, ChangeMenuSelection) { +TEST_P(LoginExpandedPublicAccountViewTest, ChangeMenuSelection) { LoginExpandedPublicAccountView::TestApi test_api(public_account_); user_->public_account_info->show_advanced_view = true; public_account_->UpdateForUser(user_); @@ -291,4 +296,8 @@ EXPECT_EQ(test_api.selected_keyboard_item().value, kKeyboardIdForItem1); } +INSTANTIATE_TEST_CASE_P(, + LoginExpandedPublicAccountViewTest, + ::testing::Values("mouse", "touch")); + } // namespace ash
diff --git a/ash/magnifier/docked_magnifier_controller.cc b/ash/magnifier/docked_magnifier_controller.cc index 2e958f9..4d80781 100644 --- a/ash/magnifier/docked_magnifier_controller.cc +++ b/ash/magnifier/docked_magnifier_controller.cc
@@ -16,7 +16,7 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shell.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "base/numerics/ranges.h" #include "components/prefs/pref_change_registrar.h" @@ -567,8 +567,8 @@ // overview mode, before we actually update the state of docked magnifier // below. https://crbug.com/894256. Shell* shell = Shell::Get(); - auto* window_selector_controller = shell->window_selector_controller(); - if (window_selector_controller->IsSelecting()) { + auto* overview_controller = shell->overview_controller(); + if (overview_controller->IsSelecting()) { auto* split_view_controller = shell->split_view_controller(); if (split_view_controller->IsSplitViewModeActive()) { // In this case, we're in a single-split-view mode, i.e. a window is @@ -580,7 +580,7 @@ SplitViewController::EndReason::kNormal); } - window_selector_controller->ToggleOverview(); + overview_controller->ToggleOverview(); } if (new_enabled) {
diff --git a/ash/magnifier/docked_magnifier_controller_unittest.cc b/ash/magnifier/docked_magnifier_controller_unittest.cc index 0ceafd37..dd1bd14b 100644 --- a/ash/magnifier/docked_magnifier_controller_unittest.cc +++ b/ash/magnifier/docked_magnifier_controller_unittest.cc
@@ -22,7 +22,7 @@ #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" @@ -334,16 +334,16 @@ wm::GetWindowState(window.get())->Maximize(); // Enable overview mode followed by the magnifier. - auto* window_selector_controller = Shell::Get()->window_selector_controller(); - window_selector_controller->ToggleOverview(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + auto* overview_controller = Shell::Get()->overview_controller(); + overview_controller->ToggleOverview(); + EXPECT_TRUE(overview_controller->IsSelecting()); controller()->SetEnabled(true); EXPECT_TRUE(controller()->GetEnabled()); // Expect that overview mode is exited, the display's work area is updated, // and the window's bounds are updated to be equal to the new display's work // area bounds. - EXPECT_FALSE(window_selector_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->IsSelecting()); const display::Display& display = display_manager()->GetDisplayAt(0); gfx::Rect workarea = display.bounds(); const int magnifier_height = GetMagnifierHeight(display.bounds().height()); @@ -372,20 +372,20 @@ // Simulate going into split view, by enabling overview mode, and snapping // a window to the left. - auto* window_selector_controller = Shell::Get()->window_selector_controller(); - window_selector_controller->ToggleOverview(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + auto* overview_controller = Shell::Get()->overview_controller(); + overview_controller->ToggleOverview(); + EXPECT_TRUE(overview_controller->IsSelecting()); split_view_controller->SnapWindow(window.get(), SplitViewController::LEFT); EXPECT_EQ(split_view_controller->state(), SplitViewController::LEFT_SNAPPED); EXPECT_EQ(split_view_controller->left_window(), window.get()); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->IsSelecting()); // Enable the docked magnifier and expect that both overview and split view // modes are exited, and the window remains maximized, and its bounds are // updated to match the new display's work area. controller()->SetEnabled(true); EXPECT_TRUE(controller()->GetEnabled()); - EXPECT_FALSE(window_selector_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->IsSelecting()); EXPECT_EQ(split_view_controller->state(), SplitViewController::NO_SNAP); EXPECT_EQ(split_view_controller->IsSplitViewModeActive(), false); const display::Display& display = display_manager()->GetDisplayAt(0); @@ -411,9 +411,9 @@ std::unique_ptr<aura::Window> window2( CreateTestWindowInShell(SK_ColorWHITE, 200, gfx::Rect(0, 0, 200, 200))); - auto* window_selector_controller = Shell::Get()->window_selector_controller(); - window_selector_controller->ToggleOverview(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + auto* overview_controller = Shell::Get()->overview_controller(); + overview_controller->ToggleOverview(); + EXPECT_TRUE(overview_controller->IsSelecting()); auto* split_view_controller = Shell::Get()->split_view_controller(); EXPECT_EQ(split_view_controller->IsSplitViewModeActive(), false); @@ -423,7 +423,7 @@ EXPECT_EQ(split_view_controller->state(), SplitViewController::BOTH_SNAPPED); // Snapping both windows should exit overview mode. - EXPECT_FALSE(window_selector_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->IsSelecting()); // Enable the docked magnifier, and expect that split view does not exit, and // the two windows heights are updated to be equal to the height of the
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc index d6898fa2..8e98036 100644 --- a/ash/public/cpp/ash_features.cc +++ b/ash/public/cpp/ash_features.cc
@@ -38,7 +38,7 @@ base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kPipRoundedCorners{"PipRoundedCorners", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kSeparateNetworkIcons{"SeparateNetworkIcons", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ash/public/cpp/ash_switches.cc b/ash/public/cpp/ash_switches.cc index ff6bf24d..e4c1dbb 100644 --- a/ash/public/cpp/ash_switches.cc +++ b/ash/public/cpp/ash_switches.cc
@@ -18,9 +18,6 @@ // Enable keyboard shortcuts used by developers only. const char kAshDeveloperShortcuts[] = "ash-dev-shortcuts"; -// Disables the dimming and blur of the wallpaper on login and lock screens. -const char kAshDisableLoginDimAndBlur[] = "ash-disable-login-dim-and-blur"; - // Disables the split view on tablet mode. const char kAshDisableTabletSplitView[] = "disable-tablet-splitview"; @@ -56,9 +53,6 @@ // Enable the wayland server. const char kAshEnableWaylandServer[] = "enable-wayland-server"; -// Enables mirrored screen. -const char kAshEnableMirroredScreen[] = "ash-enable-mirrored-screen"; - // Enables the stylus tools next to the status area. const char kAshForceEnableStylusTools[] = "force-enable-stylus-tools";
diff --git a/ash/public/cpp/ash_switches.h b/ash/public/cpp/ash_switches.h index 01e8cf6..76ae978 100644 --- a/ash/public/cpp/ash_switches.h +++ b/ash/public/cpp/ash_switches.h
@@ -19,7 +19,6 @@ ASH_PUBLIC_EXPORT extern const char kAshConstrainPointerToRoot[]; ASH_PUBLIC_EXPORT extern const char kAshDebugShortcuts[]; ASH_PUBLIC_EXPORT extern const char kAshDeveloperShortcuts[]; -ASH_PUBLIC_EXPORT extern const char kAshDisableLoginDimAndBlur[]; ASH_PUBLIC_EXPORT extern const char kAshDisableTabletSplitView[]; ASH_PUBLIC_EXPORT extern const char kAshDisableTouchExplorationMode[]; ASH_PUBLIC_EXPORT extern const char kAshEnableCursorMotionBlur[]; @@ -28,7 +27,6 @@ ASH_PUBLIC_EXPORT extern const char kAshEnablePaletteOnAllDisplays[]; ASH_PUBLIC_EXPORT extern const char kAshEnableTabletMode[]; ASH_PUBLIC_EXPORT extern const char kAshEnableWaylandServer[]; -ASH_PUBLIC_EXPORT extern const char kAshEnableMirroredScreen[]; ASH_PUBLIC_EXPORT extern const char kAshForceEnableStylusTools[]; ASH_PUBLIC_EXPORT extern const char kAshPowerButtonPosition[]; ASH_PUBLIC_EXPORT extern const char kAshUiMode[];
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index c9566a91..ceb1dae 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc
@@ -652,7 +652,7 @@ base::TimeTicks::Now())); menu_runner_->RunMenuAt(wallpaper_widget_controller()->GetWidget(), nullptr, gfx::Rect(location_in_screen, gfx::Size()), - views::MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE, + views::MENU_ANCHOR_BUBBLE_TOUCHABLE_RIGHT, source_type); }
diff --git a/ash/session/session_controller.cc b/ash/session/session_controller.cc index 377e76b6..a4ea7f9 100644 --- a/ash/session/session_controller.cc +++ b/ash/session/session_controller.cc
@@ -21,7 +21,7 @@ #include "ash/system/screen_security/screen_switch_check_controller.h" #include "ash/wm/lock_state_controller.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "ash/wm/wm_event.h" @@ -447,8 +447,7 @@ void SessionController::CanSwitchActiveUser( CanSwitchActiveUserCallback callback) { // Cancel overview mode when switching user profiles. - WindowSelectorController* controller = - Shell::Get()->window_selector_controller(); + OverviewController* controller = Shell::Get()->overview_controller(); if (controller->IsSelecting()) controller->ToggleOverview();
diff --git a/ash/session/session_controller_unittest.cc b/ash/session/session_controller_unittest.cc index 1c1715e2..2526d07 100644 --- a/ash/session/session_controller_unittest.cc +++ b/ash/session/session_controller_unittest.cc
@@ -16,7 +16,7 @@ #include "ash/shell.h" #include "ash/system/tray/system_tray_notifier.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/window_util.h" #include "base/callback.h" #include "base/macros.h" @@ -648,10 +648,10 @@ // Methods needed to test with overview mode. bool ToggleOverview() { - return Shell::Get()->window_selector_controller()->ToggleOverview(); + return Shell::Get()->overview_controller()->ToggleOverview(); } bool IsSelecting() const { - return Shell::Get()->window_selector_controller()->IsSelecting(); + return Shell::Get()->overview_controller()->IsSelecting(); } // Various counter accessors.
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc index 697cc4a..9e2adee 100644 --- a/ash/shelf/shelf_layout_manager.cc +++ b/ash/shelf/shelf_layout_manager.cc
@@ -30,7 +30,7 @@ #include "ash/wm/fullscreen_window_finder.h" #include "ash/wm/lock_state_controller.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/screen_pinning_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" @@ -793,8 +793,7 @@ // movement on async preference initialization in tests: crbug.com/834369 display_ = display::Screen::GetScreen()->GetDisplayNearestWindow( shelf_widget_->GetNativeWindow()); - bool in_overview = - Shell::Get()->window_selector_controller()->IsSelecting(); + bool in_overview = Shell::Get()->overview_controller()->IsSelecting(); if (!in_overview && !state_.IsScreenLocked() && (shelf_->alignment() != SHELF_ALIGNMENT_BOTTOM_LOCKED || display_.work_area() == display_.bounds())) { @@ -1091,8 +1090,8 @@ return SHELF_AUTO_HIDE_SHOWN; // Do not hide the shelf if overview mode is active. - if (Shell::Get()->window_selector_controller() && - Shell::Get()->window_selector_controller()->IsSelecting()) { + if (Shell::Get()->overview_controller() && + Shell::Get()->overview_controller()->IsSelecting()) { return SHELF_AUTO_HIDE_SHOWN; }
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc index 8148e1a..0f1c5575 100644 --- a/ash/shelf/shelf_layout_manager_unittest.cc +++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -34,7 +34,7 @@ #include "ash/wallpaper/wallpaper_controller.h" #include "ash/window_factory.h" #include "ash/wm/lock_state_controller.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_divider.h" #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" @@ -1270,16 +1270,15 @@ EXPECT_EQ(display.bounds().bottom() - kHiddenShelfInScreenPortion, GetShelfWidget()->GetWindowBoundsInScreen().y()); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); + OverviewController* overview_controller = Shell::Get()->overview_controller(); // Tests that the shelf is visible when in overview mode - window_selector_controller->ToggleOverview(); + overview_controller->ToggleOverview(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, GetShelfWidget()->GetBackgroundType()); // Test that on exiting overview mode, the shelf returns to auto hide state. - window_selector_controller->ToggleOverview(); + overview_controller->ToggleOverview(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); } @@ -2394,7 +2393,7 @@ wm::GetWindowState(window1.get())->OnWMEvent(&minimize_event); EXPECT_EQ(split_view_controller->IsSplitViewModeActive(), true); EXPECT_EQ(split_view_controller->state(), SplitViewController::RIGHT_SNAPPED); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(SHELF_BACKGROUND_SPLIT_VIEW, GetShelfWidget()->GetBackgroundType()); // Drag the divider to left to end split view mode, which will maximize the @@ -2406,7 +2405,7 @@ drag_point.set_x(0); split_view_controller->EndResize(drag_point); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, GetShelfWidget()->GetBackgroundType()); }
diff --git a/ash/shelf/shelf_tooltip_manager.cc b/ash/shelf/shelf_tooltip_manager.cc index 46e6663..864a4b2e 100644 --- a/ash/shelf/shelf_tooltip_manager.cc +++ b/ash/shelf/shelf_tooltip_manager.cc
@@ -146,6 +146,11 @@ ProcessPressedEvent(*event); } +void ShelfTooltipManager::OnKeyEvent(ui::KeyEvent* event) { + // Close any currently shown bubble. + Close(); +} + void ShelfTooltipManager::WillChangeVisibilityState( ShelfVisibilityState new_state) { if (new_state == SHELF_HIDDEN)
diff --git a/ash/shelf/shelf_tooltip_manager.h b/ash/shelf/shelf_tooltip_manager.h index fbc0804e..4b0a9809 100644 --- a/ash/shelf/shelf_tooltip_manager.h +++ b/ash/shelf/shelf_tooltip_manager.h
@@ -51,6 +51,7 @@ // ui::EventHandler overrides: void OnMouseEvent(ui::MouseEvent* event) override; void OnTouchEvent(ui::TouchEvent* event) override; + void OnKeyEvent(ui::KeyEvent* event) override; // ShelfObserver overrides: void WillChangeVisibilityState(ShelfVisibilityState new_state) override;
diff --git a/ash/shelf/shelf_tooltip_manager_unittest.cc b/ash/shelf/shelf_tooltip_manager_unittest.cc index b8133a4..26b375c 100644 --- a/ash/shelf/shelf_tooltip_manager_unittest.cc +++ b/ash/shelf/shelf_tooltip_manager_unittest.cc
@@ -209,14 +209,14 @@ EXPECT_FALSE(tooltip_manager_->IsVisible()); } -TEST_F(ShelfTooltipManagerTest, DoNotHideForKeyEvents) { +TEST_F(ShelfTooltipManagerTest, KeyEvents) { ui::test::EventGenerator* generator = GetEventGenerator(); - // Should not hide for key events. + // Should hide when 'Esc' is pressed. tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); ASSERT_TRUE(tooltip_manager_->IsVisible()); - generator->PressKey(ui::VKEY_A, ui::EF_NONE); - EXPECT_TRUE(tooltip_manager_->IsVisible()); + generator->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE); + EXPECT_FALSE(tooltip_manager_->IsVisible()); } } // namespace ash
diff --git a/ash/shell.cc b/ash/shell.cc index c7f9e7e..c0c007d 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -138,7 +138,7 @@ #include "ash/wm/native_cursor_manager_ash.h" #include "ash/wm/non_client_frame_controller.h" #include "ash/wm/overlay_event_filter.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/resize_shadow_controller.h" #include "ash/wm/root_window_finder.h" #include "ash/wm/screen_pinning_controller.h" @@ -586,10 +586,10 @@ observer.OnOverviewModeStartingAnimationComplete(canceled); } -void Shell::NotifyOverviewModeEnding(WindowSelector* window_selector) { - DCHECK(window_selector); +void Shell::NotifyOverviewModeEnding(OverviewSession* overview_session) { + DCHECK(overview_session); for (auto& observer : shell_observers_) - observer.OnOverviewModeEnding(window_selector); + observer.OnOverviewModeEnding(overview_session); } void Shell::NotifyOverviewModeEnded() { @@ -814,10 +814,10 @@ // Has to happen before ~MruWindowTracker. window_cycle_controller_.reset(); - window_selector_controller_.reset(); + overview_controller_.reset(); // |split_view_controller_| needs to be deleted after - // |window_selector_controller_|. + // |overview_controller_|. split_view_controller_.reset(); // Stop dispatching events (e.g. synthesized mouse exits from window close). @@ -1080,7 +1080,7 @@ focus_controller_ = std::make_unique<::wm::FocusController>(focus_rules_); focus_controller_->AddObserver(this); - window_selector_controller_ = std::make_unique<WindowSelectorController>(); + overview_controller_ = std::make_unique<OverviewController>(); screen_position_controller_ = std::make_unique<ScreenPositionController>();
diff --git a/ash/shell.h b/ash/shell.h index ddcfee3d..af0db52 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -200,8 +200,8 @@ class WindowServiceOwner; class WindowCycleController; class WindowPositioner; -class WindowSelector; -class WindowSelectorController; +class OverviewSession; +class OverviewController; class WindowTreeHostManager; enum class LoginStatus; @@ -554,8 +554,8 @@ return window_cycle_controller_.get(); } WindowPositioner* window_positioner() { return window_positioner_.get(); } - WindowSelectorController* window_selector_controller() { - return window_selector_controller_.get(); + OverviewController* overview_controller() { + return overview_controller_.get(); } WindowServiceOwner* window_service_owner() { return window_service_owner_.get(); @@ -609,8 +609,8 @@ void NotifyOverviewModeStartingAnimationComplete(bool canceled); // Notifies observers that overview mode is about to end (before the windows - // restore themselves). |window_selector| must not be null. - void NotifyOverviewModeEnding(WindowSelector* window_selector); + // restore themselves). |overview_session| must not be null. + void NotifyOverviewModeEnding(OverviewSession* overview_session); // Notifies observers that overview mode has ended. void NotifyOverviewModeEnded(); @@ -778,7 +778,7 @@ std::unique_ptr<VpnList> vpn_list_; std::unique_ptr<WallpaperController> wallpaper_controller_; std::unique_ptr<WindowCycleController> window_cycle_controller_; - std::unique_ptr<WindowSelectorController> window_selector_controller_; + std::unique_ptr<OverviewController> overview_controller_; // Owned by |focus_controller_|. ::wm::FocusRules* focus_rules_ = nullptr; std::unique_ptr<::wm::ShadowController> shadow_controller_;
diff --git a/ash/shell/content/client/shell_main_delegate.cc b/ash/shell/content/client/shell_main_delegate.cc index 87d7874..c63bf2c 100644 --- a/ash/shell/content/client/shell_main_delegate.cc +++ b/ash/shell/content/client/shell_main_delegate.cc
@@ -78,6 +78,7 @@ if (service) { service_manager::Service::RunAsyncUntilTermination( std::move(service), base::BindOnce(&TerminateThisProcess)); + return true; } return false; }
diff --git a/ash/shell_observer.h b/ash/shell_observer.h index 7ae4a98e..32a9c59 100644 --- a/ash/shell_observer.h +++ b/ash/shell_observer.h
@@ -16,7 +16,7 @@ namespace ash { -class WindowSelector; +class OverviewSession; class ASH_EXPORT ShellObserver { public: @@ -53,8 +53,8 @@ virtual void OnOverviewModeStartingAnimationComplete(bool canceled) {} // Called when the overview mode is about to end (bofore the windows restore - // themselves). |window_selector| will not be null. - virtual void OnOverviewModeEnding(WindowSelector* window_selector) {} + // themselves). |overview_session| will not be null. + virtual void OnOverviewModeEnding(OverviewSession* overview_session) {} // Called after overview mode has ended. virtual void OnOverviewModeEnded() {}
diff --git a/ash/shell_test_api.cc b/ash/shell_test_api.cc index 4763532..9be0c024 100644 --- a/ash/shell_test_api.cc +++ b/ash/shell_test_api.cc
@@ -11,7 +11,7 @@ #include "ash/shell.h" #include "ash/system/power/backlights_forced_off_setter.h" #include "ash/system/power/power_button_controller.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/ws/window_service_owner.h" @@ -114,7 +114,7 @@ } void ShellTestApi::ToggleOverviewMode(ToggleOverviewModeCallback cb) { - shell_->window_selector_controller()->ToggleOverview(); + shell_->overview_controller()->ToggleOverview(); std::move(cb).Run(); }
diff --git a/ash/system/accessibility/dictation_button_tray_unittest.cc b/ash/system/accessibility/dictation_button_tray_unittest.cc index 6cbfadd7..36a479c 100644 --- a/ash/system/accessibility/dictation_button_tray_unittest.cc +++ b/ash/system/accessibility/dictation_button_tray_unittest.cc
@@ -17,7 +17,7 @@ #include "ash/system/status_area_widget_test_helper.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h"
diff --git a/ash/system/model/clock_model.cc b/ash/system/model/clock_model.cc index 3be491c8..8115c713 100644 --- a/ash/system/model/clock_model.cc +++ b/ash/system/model/clock_model.cc
@@ -6,7 +6,7 @@ #include "ash/session/session_controller.h" #include "ash/shell.h" -#include "ash/system/date/clock_observer.h" +#include "ash/system/model/clock_observer.h" #include "ash/system/model/system_tray_model.h" #include "chromeos/dbus/dbus_thread_manager.h"
diff --git a/ash/system/date/clock_observer.h b/ash/system/model/clock_observer.h similarity index 80% rename from ash/system/date/clock_observer.h rename to ash/system/model/clock_observer.h index a62e2be..5bc179f 100644 --- a/ash/system/date/clock_observer.h +++ b/ash/system/model/clock_observer.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_DATE_CLOCK_OBSERVER_H_ -#define ASH_SYSTEM_DATE_CLOCK_OBSERVER_H_ +#ifndef ASH_SYSTEM_MODEL_CLOCK_OBSERVER_H_ +#define ASH_SYSTEM_MODEL_CLOCK_OBSERVER_H_ #include "ash/ash_export.h" @@ -23,4 +23,4 @@ } // namespace ash -#endif // ASH_SYSTEM_DATE_CLOCK_OBSERVER_H_ +#endif // ASH_SYSTEM_MODEL_CLOCK_OBSERVER_H_
diff --git a/ash/system/overview/overview_button_tray.cc b/ash/system/overview/overview_button_tray.cc index 0b171316..e4735d7 100644 --- a/ash/system/overview/overview_button_tray.cc +++ b/ash/system/overview/overview_button_tray.cc
@@ -13,8 +13,8 @@ #include "ash/system/tray/tray_constants.h" #include "ash/system/tray/tray_container.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" @@ -66,7 +66,7 @@ void OverviewButtonTray::OnGestureEvent(ui::GestureEvent* event) { Button::OnGestureEvent(event); if (event->type() == ui::ET_GESTURE_LONG_PRESS) { - Shell::Get()->window_selector_controller()->OnOverviewButtonTrayLongPressed( + Shell::Get()->overview_controller()->OnOverviewButtonTrayLongPressed( event->location()); } } @@ -75,11 +75,10 @@ DCHECK(event.type() == ui::ET_MOUSE_RELEASED || event.type() == ui::ET_GESTURE_TAP); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); + OverviewController* overview_controller = Shell::Get()->overview_controller(); // Skip if the second tap happened outside of overview. This can happen if a // window gets activated in between, which cancels overview mode. - if (window_selector_controller->IsSelecting() && last_press_event_time_ && + if (overview_controller->IsSelecting() && last_press_event_time_ && event.time_stamp() - last_press_event_time_.value() < kDoubleTapThresholdMs) { base::RecordAction(base::UserMetricsAction("Tablet_QuickSwitch")); @@ -93,9 +92,8 @@ // current window) if it exists, unless splitview mode is active. Do not // switch we entered overview mode will all windows minimized. if (mru_window_list.size() > 1u && - window_selector_controller->window_selector() - ->enter_exit_overview_type() != - WindowSelector::EnterExitOverviewType::kWindowsMinimized) { + overview_controller->overview_session()->enter_exit_overview_type() != + OverviewSession::EnterExitOverviewType::kWindowsMinimized) { aura::Window* new_active_window = mru_window_list[1]; // In splitview mode, quick switch will only affect the windows on the non @@ -123,13 +121,11 @@ // If not in overview mode record the time of this tap. A subsequent tap will // be checked against this to see if we should quick switch. - last_press_event_time_ = - Shell::Get()->window_selector_controller()->IsSelecting() - ? base::nullopt - : base::make_optional(event.time_stamp()); + last_press_event_time_ = Shell::Get()->overview_controller()->IsSelecting() + ? base::nullopt + : base::make_optional(event.time_stamp()); - WindowSelectorController* controller = - Shell::Get()->window_selector_controller(); + OverviewController* controller = Shell::Get()->overview_controller(); // Note: Toggling overview mode will fail if there is no window to show, the // screen is locked, a modal dialog is open or is running in kiosk app // session. @@ -167,7 +163,7 @@ void OverviewButtonTray::UpdateIconVisibility() { // The visibility of the OverviewButtonTray has diverged from - // WindowSelectorController::CanSelect. The visibility of the button should + // OverviewController::CanSelect. The visibility of the button should // not change during transient times in which CanSelect is false. Such as when // a modal dialog is present. SessionController* session_controller = Shell::Get()->session_controller();
diff --git a/ash/system/overview/overview_button_tray.h b/ash/system/overview/overview_button_tray.h index ae77606..47097fd 100644 --- a/ash/system/overview/overview_button_tray.h +++ b/ash/system/overview/overview_button_tray.h
@@ -20,7 +20,7 @@ namespace ash { // Status area tray for showing a toggle for Overview Mode. Overview Mode -// is equivalent to WindowSelectorController being in selection mode. +// is equivalent to OverviewController being in selection mode. // This hosts a ShellObserver that listens for the activation of Maximize Mode // This tray will only be visible while in this state. This tray does not // provide any bubble view windows. @@ -70,7 +70,7 @@ friend class OverviewButtonTrayTest; // Sets the icon to visible if tablet mode is enabled and - // WindowSelectorController::CanSelect. + // OverviewController::CanSelect. void UpdateIconVisibility(); // Weak pointer, will be parented by TrayContainer for its lifetime.
diff --git a/ash/system/overview/overview_button_tray_unittest.cc b/ash/system/overview/overview_button_tray_unittest.cc index cab20b7..17352a7 100644 --- a/ash/system/overview/overview_button_tray_unittest.cc +++ b/ash/system/overview/overview_button_tray_unittest.cc
@@ -16,7 +16,7 @@ #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" #include "ash/window_factory.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" @@ -119,23 +119,23 @@ // Tests that activating this control brings up window selection mode. TEST_F(OverviewButtonTrayTest, PerformAction) { - ASSERT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); // Overview Mode only works when there is a window std::unique_ptr<aura::Window> window( CreateTestWindowInShellWithBounds(gfx::Rect(5, 5, 20, 20))); GetTray()->PerformAction(CreateTapEvent()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Verify tapping on the button again closes overview mode. GetTray()->PerformAction(CreateTapEvent()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); } TEST_F(OverviewButtonTrayTest, PerformDoubleTapAction) { TabletModeControllerTestApi().EnterTabletMode(); - ASSERT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); // Add two windows and activate the second one to test quick switch. std::unique_ptr<aura::Window> window1( @@ -148,21 +148,21 @@ // Verify that after double tapping, we have switched to window 1. PerformDoubleTap(); EXPECT_TRUE(wm::IsActiveWindow(window1.get())); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); // Verify that if we double tap on the window selection page, it acts as two // taps, and ends up on the window selection page again. ui::GestureEvent tap = CreateTapEvent(); ASSERT_TRUE(wm::IsActiveWindow(window1.get())); GetTray()->PerformAction(tap); - ASSERT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); PerformDoubleTap(); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Verify that if we minimize a window, double tapping the overlay tray button // will bring up the window, and it should be the active window. GetTray()->PerformAction(tap); - ASSERT_TRUE(!Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_TRUE(!Shell::Get()->overview_controller()->IsSelecting()); ASSERT_TRUE(wm::IsActiveWindow(window1.get())); wm::GetWindowState(window2.get())->Minimize(); ASSERT_EQ(window2->layer()->GetTargetOpacity(), 0.0); @@ -172,7 +172,7 @@ // Verify that if all windows are minimized, double tapping the tray will have // no effect. - ASSERT_TRUE(!Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_TRUE(!Shell::Get()->overview_controller()->IsSelecting()); wm::GetWindowState(window1.get())->Minimize(); wm::GetWindowState(window2.get())->Minimize(); PerformDoubleTap(); @@ -182,7 +182,7 @@ // Tests that tapping on the control will record the user action Tray_Overview. TEST_F(OverviewButtonTrayTest, TrayOverviewUserAction) { - ASSERT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); // With one window present, tapping on the control to enter overview mode // should record the user action. @@ -191,14 +191,14 @@ CreateTestWindowInShellWithBounds(gfx::Rect(5, 5, 20, 20))); GetTray()->PerformAction( CreateTapEvent(OverviewButtonTray::kDoubleTapThresholdMs)); - ASSERT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(1, user_action_tester.GetActionCount(kTrayOverview)); // Tapping on the control to exit overview mode should record the // user action. GetTray()->PerformAction( CreateTapEvent(OverviewButtonTray::kDoubleTapThresholdMs * 2)); - ASSERT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(2, user_action_tester.GetActionCount(kTrayOverview)); } @@ -253,19 +253,19 @@ // Tests that the tray only renders as active while selection is ongoing. Any // dismissal of overview mode clears the active state. TEST_F(OverviewButtonTrayTest, ActiveStateOnlyDuringOverviewMode) { - ASSERT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); ASSERT_FALSE(GetTray()->is_active()); // Overview Mode only works when there is a window std::unique_ptr<aura::Window> window( CreateTestWindowInShellWithBounds(gfx::Rect(5, 5, 20, 20))); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->ToggleOverview()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->ToggleOverview()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_TRUE(GetTray()->is_active()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->ToggleOverview()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->ToggleOverview()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_FALSE(GetTray()->is_active()); } @@ -349,7 +349,7 @@ // Enter splitview mode. Snap |window1| to the left, this will be the default // splitview window. - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); SplitViewController* split_view_controller = Shell::Get()->split_view_controller(); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT);
diff --git a/ash/system/power/power_event_observer.cc b/ash/system/power/power_event_observer.cc index d2b810c9..fea6c3d 100644 --- a/ash/system/power/power_event_observer.cc +++ b/ash/system/power/power_event_observer.cc
@@ -108,7 +108,6 @@ RunCallbackIfAllCompositingEnded(); } - void OnCompositingChildResizing(ui::Compositor* compositor) override {} void OnCompositingShuttingDown(ui::Compositor* compositor) override { compositor_observer_.Remove(compositor); pending_compositing_.erase(compositor);
diff --git a/ash/system/power/tray_power.cc b/ash/system/power/tray_power.cc index 73a430a..9bbbe9d0 100644 --- a/ash/system/power/tray_power.cc +++ b/ash/system/power/tray_power.cc
@@ -12,9 +12,9 @@ #include "ash/session/session_controller.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/date/date_view.h" #include "ash/system/power/battery_notification.h" #include "ash/system/power/dual_role_notification.h" +#include "ash/system/time/time_view.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/tray/tray_item_view.h" #include "ash/system/tray/tray_utils.h"
diff --git a/ash/system/date/tray_system_info.cc b/ash/system/time/time_tray_item_view.cc similarity index 90% rename from ash/system/date/tray_system_info.cc rename to ash/system/time/time_tray_item_view.cc index fcaa5cc..6ec8e4cf 100644 --- a/ash/system/date/tray_system_info.cc +++ b/ash/system/time/time_tray_item_view.cc
@@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/date/tray_system_info.h" +#include "ash/system/time/time_tray_item_view.h" #include "ash/shelf/shelf.h" #include "ash/shell.h" -#include "ash/system/date/date_view.h" #include "ash/system/model/clock_model.h" #include "ash/system/model/system_tray_model.h" -#include "ash/system/tray/system_tray_notifier.h" +#include "ash/system/time/time_view.h" namespace ash {
diff --git a/ash/system/date/tray_system_info.h b/ash/system/time/time_tray_item_view.h similarity index 76% rename from ash/system/date/tray_system_info.h rename to ash/system/time/time_tray_item_view.h index 182319a..4e203ab0 100644 --- a/ash/system/date/tray_system_info.h +++ b/ash/system/time/time_tray_item_view.h
@@ -2,16 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_DATE_TRAY_SYSTEM_INFO_H_ -#define ASH_SYSTEM_DATE_TRAY_SYSTEM_INFO_H_ - -#include <memory> +#ifndef ASH_SYSTEM_TIME_TIME_TRAY_ITEM_VIEW_H_ +#define ASH_SYSTEM_TIME_TIME_TRAY_ITEM_VIEW_H_ #include "ash/ash_export.h" -#include "ash/login_status.h" -#include "ash/session/session_controller.h" #include "ash/session/session_observer.h" -#include "ash/system/date/clock_observer.h" #include "ash/system/tray/tray_item_view.h" #include "base/macros.h" @@ -42,4 +37,4 @@ } // namespace tray } // namespace ash -#endif // ASH_SYSTEM_DATE_TRAY_SYSTEM_INFO_H_ +#endif // ASH_SYSTEM_TIME_TIME_TRAY_ITEM_VIEW_H_
diff --git a/ash/system/date/date_view.cc b/ash/system/time/time_view.cc similarity index 95% rename from ash/system/date/date_view.cc rename to ash/system/time/time_view.cc index 589bd322..b394cd82e 100644 --- a/ash/system/date/date_view.cc +++ b/ash/system/time/time_view.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/date/date_view.h" +#include "ash/system/time/time_view.h" #include "ash/session/session_controller.h" #include "ash/shell.h" @@ -22,6 +22,7 @@ #include "third_party/icu/source/i18n/unicode/smpdtfmt.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/ui_base_features.h" #include "ui/gfx/geometry/insets.h" #include "ui/views/border.h" #include "ui/views/controls/button/button.h" @@ -179,7 +180,13 @@ NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true); - base::string16 current_time = base::TimeFormatTimeOfDayWithHourClockType( + base::string16 current_time; + // Add a subtle indicator for SingleProcessMash that shows up in screenshots. + // TODO(crbug.com/918537): Remove before M-74 branch. + if (::features::IsSingleProcessMash()) { + current_time = base::ASCIIToUTF16("- "); + } + current_time += base::TimeFormatTimeOfDayWithHourClockType( now, model_->hour_clock_type(), base::kDropAmPm); horizontal_label_->SetText(current_time); horizontal_label_->SetTooltipText(base::TimeFormatFriendlyDate(now));
diff --git a/ash/system/date/date_view.h b/ash/system/time/time_view.h similarity index 93% rename from ash/system/date/date_view.h rename to ash/system/time/time_view.h index bfbf61b9..01ccad2f 100644 --- a/ash/system/date/date_view.h +++ b/ash/system/time/time_view.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_DATE_DATE_VIEW_H_ -#define ASH_SYSTEM_DATE_DATE_VIEW_H_ +#ifndef ASH_SYSTEM_TIME_TIME_VIEW_H_ +#define ASH_SYSTEM_TIME_TIME_VIEW_H_ #include <memory> #include "ash/ash_export.h" -#include "ash/system/date/clock_observer.h" +#include "ash/system/model/clock_observer.h" #include "ash/system/tray/actionable_view.h" #include "base/i18n/time_formatting.h" #include "base/macros.h" @@ -101,4 +101,4 @@ } // namespace tray } // namespace ash -#endif // ASH_SYSTEM_DATE_DATE_VIEW_H_ +#endif // ASH_SYSTEM_TIME_TIME_VIEW_H_
diff --git a/ash/system/date/date_view_unittest.cc b/ash/system/time/time_view_unittest.cc similarity index 97% rename from ash/system/date/date_view_unittest.cc rename to ash/system/time/time_view_unittest.cc index e2b874f..ca96e7a 100644 --- a/ash/system/date/date_view_unittest.cc +++ b/ash/system/time/time_view_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/date/date_view.h" +#include "ash/system/time/time_view.h" #include "ash/shell.h" #include "ash/system/model/system_tray_model.h"
diff --git a/ash/system/unified/unified_system_info_view.cc b/ash/system/unified/unified_system_info_view.cc index bc993e3b..2ebcff4 100644 --- a/ash/system/unified/unified_system_info_view.cc +++ b/ash/system/unified/unified_system_info_view.cc
@@ -9,9 +9,9 @@ #include "ash/session/session_controller.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/date/clock_observer.h" #include "ash/system/enterprise/enterprise_domain_observer.h" #include "ash/system/model/clock_model.h" +#include "ash/system/model/clock_observer.h" #include "ash/system/model/enterprise_domain_model.h" #include "ash/system/model/system_tray_model.h" #include "ash/system/power/power_status.h"
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc index 8e38db3..85f5432 100644 --- a/ash/system/unified/unified_system_tray.cc +++ b/ash/system/unified/unified_system_tray.cc
@@ -6,11 +6,10 @@ #include "ash/accessibility/accessibility_controller.h" #include "ash/public/cpp/ash_features.h" +#include "ash/session/session_controller.h" #include "ash/shelf/shelf.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/date/date_view.h" -#include "ash/system/date/tray_system_info.h" #include "ash/system/message_center/ash_popup_alignment_delegate.h" #include "ash/system/message_center/message_center_ui_controller.h" #include "ash/system/message_center/message_center_ui_delegate.h" @@ -20,6 +19,8 @@ #include "ash/system/network/network_tray_view.h" #include "ash/system/power/tray_power.h" #include "ash/system/status_area_widget.h" +#include "ash/system/time/time_tray_item_view.h" +#include "ash/system/time/time_view.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/tray/tray_container.h" #include "ash/system/unified/current_locale_view.h"
diff --git a/ash/system/unified/unified_system_tray_test_api.cc b/ash/system/unified/unified_system_tray_test_api.cc index 7d719c5..0e2f1647 100644 --- a/ash/system/unified/unified_system_tray_test_api.cc +++ b/ash/system/unified/unified_system_tray_test_api.cc
@@ -6,9 +6,9 @@ #include "ash/root_window_controller.h" #include "ash/shell.h" -#include "ash/system/date/date_view.h" -#include "ash/system/date/tray_system_info.h" #include "ash/system/status_area_widget.h" +#include "ash/system/time/time_tray_item_view.h" +#include "ash/system/time/time_view.h" #include "ash/system/unified/unified_system_tray.h" #include "ash/system/unified/unified_system_tray_bubble.h" #include "ash/system/unified/unified_system_tray_controller.h"
diff --git a/ash/utility/screenshot_controller.cc b/ash/utility/screenshot_controller.cc index 1d65e737..ef07130 100644 --- a/ash/utility/screenshot_controller.cc +++ b/ash/utility/screenshot_controller.cc
@@ -7,6 +7,7 @@ #include <cmath> #include <memory> +#include "ash/accelerators/accelerator_controller.h" #include "ash/display/mouse_cursor_event_filter.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/screenshot_delegate.h" @@ -460,6 +461,19 @@ // they should be able to continue manipulating the screen. if (!pen_events_only_) event->StopPropagation(); + + // Key event is blocked. So have to record current accelerator here. + if (event->stopped_propagation()) { + // Filter accelerators in the same way with AcceleratorFilter::OnKeyEvent. + if (event->is_char() || !event->target()) + return; + + ui::Accelerator accelerator(*event); + ash::Shell::Get() + ->accelerator_controller() + ->accelerator_history() + ->StoreCurrentAccelerator(accelerator); + } } void ScreenshotController::OnMouseEvent(ui::MouseEvent* event) {
diff --git a/ash/wallpaper/wallpaper_controller.cc b/ash/wallpaper/wallpaper_controller.cc index 07851550..a4366cd 100644 --- a/ash/wallpaper/wallpaper_controller.cc +++ b/ash/wallpaper/wallpaper_controller.cc
@@ -26,7 +26,7 @@ #include "ash/wallpaper/wallpaper_widget_controller.h" #include "ash/wallpaper/wallpaper_window_state_manager.h" #include "ash/wm/overview/overview_constants.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "base/bind.h" #include "base/command_line.h" #include "base/files/file_enumerator.h" @@ -731,15 +731,11 @@ bool WallpaperController::ShouldApplyDimming() const { return Shell::Get()->session_controller()->IsUserSessionBlocked() && - !IsOneShotWallpaper() && - !base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshDisableLoginDimAndBlur); + !IsOneShotWallpaper(); } bool WallpaperController::IsBlurAllowed() const { - return !IsDevicePolicyWallpaper() && !IsOneShotWallpaper() && - !base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshDisableLoginDimAndBlur); + return !IsDevicePolicyWallpaper() && !IsOneShotWallpaper(); } bool WallpaperController::IsWallpaperBlurred() const { @@ -1456,7 +1452,7 @@ bool session_blocked = Shell::Get()->session_controller()->IsUserSessionBlocked(); - bool in_overview = Shell::Get()->window_selector_controller()->IsSelecting(); + bool in_overview = Shell::Get()->overview_controller()->IsSelecting(); bool is_wallpaper_blurred = (session_blocked || in_overview) && IsBlurAllowed();
diff --git a/ash/wallpaper/wallpaper_view.cc b/ash/wallpaper/wallpaper_view.cc index 544d4fc..684b8d2 100644 --- a/ash/wallpaper/wallpaper_view.cc +++ b/ash/wallpaper/wallpaper_view.cc
@@ -12,11 +12,9 @@ #include "ash/shell.h" #include "ash/wallpaper/wallpaper_controller.h" #include "ash/wallpaper/wallpaper_widget_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/overview/overview_utils.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "base/strings/utf_string_conversions.h" #include "ui/aura/window.h" -#include "ui/base/ui_base_features.h" #include "ui/display/display.h" #include "ui/display/manager/display_manager.h" #include "ui/display/manager/managed_display_info.h" @@ -24,12 +22,9 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/color_analysis.h" #include "ui/gfx/color_utils.h" -#include "ui/gfx/font_list.h" #include "ui/gfx/geometry/safe_integer_conversions.h" #include "ui/gfx/geometry/size_conversions.h" -#include "ui/gfx/shadow_value.h" #include "ui/gfx/transform.h" -#include "ui/views/controls/label.h" #include "ui/views/widget/widget.h" #include "ui/wm/core/window_animations.h" @@ -123,8 +118,7 @@ void HandleClickOrTap(ui::Event* event) { CHECK_EQ(ui::EP_PRETARGET, event->phase()); - WindowSelectorController* controller = - Shell::Get()->window_selector_controller(); + OverviewController* controller = Shell::Get()->overview_controller(); if (!controller->IsSelecting()) return; // Events that happen while app list is sliding out during overview should @@ -314,27 +308,6 @@ aura::Window* container = root_window->GetChildById(container_id); wallpaper_widget->SetBounds(container->bounds()); - // SingleProcessMash changes a large chunk of underlying code, so put a label - // in the top-right of the screen to let developers and QA know that it is on. - if (::features::IsSingleProcessMash()) { - views::Label* label = - new views::Label(base::ASCIIToUTF16("SingleProcessMash enabled")); - label->SetTooltipText(base::ASCIIToUTF16("Use about:flags to disable")); - const int screen_width = root_window->GetBoundsInScreen().width(); - const int padding = 8; - label->SetBounds(padding, 0, screen_width - 2 * padding, 32); - label->SetHorizontalAlignment(gfx::ALIGN_RIGHT); - label->SetAutoColorReadabilityEnabled(false); - label->SetEnabledColor(SK_ColorWHITE); - label->SetFontList(views::Label::GetDefaultFontList().Derive( - -1, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL)); - const int elevation = 3; // DIPs. - label->SetShadows({gfx::ShadowValue::MakeMdShadowValues(elevation)}); - label->SetSubpixelRenderingEnabled(false); - label->SetVisible(true); - wallpaper_view->AddChildView(label); - } - return wallpaper_widget; }
diff --git a/ash/wm/gestures/overview_gesture_handler.cc b/ash/wm/gestures/overview_gesture_handler.cc index 0b4941f..e7ec20cc 100644 --- a/ash/wm/gestures/overview_gesture_handler.cc +++ b/ash/wm/gestures/overview_gesture_handler.cc
@@ -5,7 +5,7 @@ #include "ash/wm/gestures/overview_gesture_handler.h" #include "ash/shell.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "base/metrics/user_metrics.h" #include "ui/events/event.h" #include "ui/events/event_constants.h" @@ -33,12 +33,11 @@ scroll_x_ += event.x_offset(); scroll_y_ += event.y_offset(); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); + OverviewController* overview_controller = Shell::Get()->overview_controller(); // Horizontal 3-finger scroll moves selection when already in overview mode. if (std::fabs(scroll_x_) >= std::fabs(scroll_y_)) { - if (!window_selector_controller->IsSelecting()) { + if (!overview_controller->IsSelecting()) { scroll_x_ = scroll_y_ = 0; return false; } @@ -47,12 +46,12 @@ const int increment = scroll_x_ > 0 ? 1 : -1; scroll_x_ = scroll_y_ = 0; - window_selector_controller->IncrementSelection(increment); + overview_controller->IncrementSelection(increment); return true; } // Use vertical 3-finger scroll gesture up to enter overview, down to exit. - if (window_selector_controller->IsSelecting()) { + if (overview_controller->IsSelecting()) { if (scroll_y_ < 0) scroll_x_ = scroll_y_ = 0; if (scroll_y_ < vertical_threshold_pixels_) @@ -67,11 +66,11 @@ // Reset scroll amount on toggling. scroll_x_ = scroll_y_ = 0; base::RecordAction(base::UserMetricsAction("Touchpad_Gesture_Overview")); - if (window_selector_controller->IsSelecting() && - window_selector_controller->AcceptSelection()) { + if (overview_controller->IsSelecting() && + overview_controller->AcceptSelection()) { return true; } - window_selector_controller->ToggleOverview(); + overview_controller->ToggleOverview(); return true; }
diff --git a/ash/wm/gestures/overview_gesture_handler_unittest.cc b/ash/wm/gestures/overview_gesture_handler_unittest.cc index 1c2a161..441f114c 100644 --- a/ash/wm/gestures/overview_gesture_handler_unittest.cc +++ b/ash/wm/gestures/overview_gesture_handler_unittest.cc
@@ -7,7 +7,7 @@ #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/window_util.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/test/test_windows.h" @@ -28,11 +28,11 @@ } void ToggleOverview() { - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); } bool IsSelecting() { - return Shell::Get()->window_selector_controller()->IsSelecting(); + return Shell::Get()->overview_controller()->IsSelecting(); } float vertical_threshold_pixels() const {
diff --git a/ash/wm/immersive_gesture_drag_handler_unittest.cc b/ash/wm/immersive_gesture_drag_handler_unittest.cc index f6016ac..b8b39d3b 100644 --- a/ash/wm/immersive_gesture_drag_handler_unittest.cc +++ b/ash/wm/immersive_gesture_drag_handler_unittest.cc
@@ -10,9 +10,9 @@ #include "ash/system/status_area_widget.h" #include "ash/system/status_area_widget_test_helper.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_item.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_item.h" #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" #include "ash/wm/window_state.h" #include "base/time/time.h" @@ -79,21 +79,21 @@ ui::ET_GESTURE_SCROLL_UPDATE); EXPECT_TRUE(wm::GetWindowState(dragged_window_.get())->is_dragged()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - WindowSelector* window_selector = - Shell::Get()->window_selector_controller()->window_selector(); - EXPECT_TRUE(window_selector->IsWindowInOverview(none_dragged_window_.get())); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + OverviewSession* overview_session = + Shell::Get()->overview_controller()->overview_session(); + EXPECT_TRUE(overview_session->IsWindowInOverview(none_dragged_window_.get())); - WindowGrid* current_grid = window_selector->GetGridWithRootWindow( + OverviewGrid* current_grid = overview_session->GetGridWithRootWindow( none_dragged_window_->GetRootWindow()); - WindowSelectorItem* item = - current_grid->GetWindowSelectorItemContaining(none_dragged_window_.get()); + OverviewItem* item = + current_grid->GetOverviewItemContaining(none_dragged_window_.get()); GetEventGenerator()->GestureTapAt(item->GetTransformedBounds().CenterPoint()); // Overview mode is still active and |none_dragged_window_| is still in // overview grid after tried to tap it in overview grid. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - EXPECT_TRUE(window_selector->IsWindowInOverview(none_dragged_window_.get())); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_session->IsWindowInOverview(none_dragged_window_.get())); } // Tests that tap the overview button during window drag should not end overview @@ -107,11 +107,11 @@ SendGestureEvent(gfx::Point(700, 500), 700, 500, ui::ET_GESTURE_SCROLL_UPDATE); EXPECT_TRUE(wm::GetWindowState(dragged_window_.get())->is_dragged()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - WindowSelector* window_selector = - Shell::Get()->window_selector_controller()->window_selector(); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + OverviewSession* overview_session = + Shell::Get()->overview_controller()->overview_session(); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); OverviewButtonTray* overview_button_tray = StatusAreaWidgetTestHelper::GetStatusAreaWidget()->overview_button_tray(); ASSERT_TRUE(overview_button_tray->visible()); @@ -120,8 +120,8 @@ // Overview mode is still active and |none_dragged_window_| is still in // overview grid after tap the overview button. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - EXPECT_TRUE(window_selector->IsWindowInOverview(none_dragged_window_.get())); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_session->IsWindowInOverview(none_dragged_window_.get())); } } // namespace ash
diff --git a/ash/wm/non_client_frame_controller.cc b/ash/wm/non_client_frame_controller.cc index 226d9a3..456533a1 100644 --- a/ash/wm/non_client_frame_controller.cc +++ b/ash/wm/non_client_frame_controller.cc
@@ -139,6 +139,15 @@ return cursor_; } + gfx::Size GetMaximumSize() const override { + aura::Window* window = GetNativeWindow(); + if (window && client_provides_frame_ && + window->GetProperty(aura::client::kMaximumSize)) { + return *window->GetProperty(aura::client::kMaximumSize); + } + return views::NativeWidgetAura::GetMaximumSize(); + } + gfx::Size GetMinimumSize() const override { aura::Window* window = GetNativeWindow(); if (window && client_provides_frame_ &&
diff --git a/ash/wm/overview/caption_container_view.cc b/ash/wm/overview/caption_container_view.cc index 4cb580e1..da852ad 100644 --- a/ash/wm/overview/caption_container_view.cc +++ b/ash/wm/overview/caption_container_view.cc
@@ -7,9 +7,9 @@ #include "ash/resources/vector_icons/vector_icons.h" #include "ash/strings/grit/ash_strings.h" #include "ash/wm/overview/overview_constants.h" +#include "ash/wm/overview/overview_item.h" #include "ash/wm/overview/overview_utils.h" #include "ash/wm/overview/rounded_rect_view.h" -#include "ash/wm/overview/window_selector_item.h" #include "ash/wm/splitview/split_view_constants.h" #include "ash/wm/splitview/split_view_utils.h" #include "ui/aura/client/aura_constants.h" @@ -142,11 +142,11 @@ } ~ShieldButton() override = default; - // When WindowSelectorItem (which is a ButtonListener) is destroyed, its + // When OverviewItem (which is a ButtonListener) is destroyed, its // |item_widget_| is allowed to stay around to complete any animations. // Resetting the listener in all views that are targeted by events is // necessary to prevent a crash when a user clicks on the fading out widget - // after the WindowSelectorItem has been destroyed. + // after the OverviewItem has been destroyed. void ResetListener() { listener_ = nullptr; } // views::View: @@ -222,9 +222,7 @@ views::Button::OnGestureEvent(event); } - WindowSelectorItem* listener() { - return static_cast<WindowSelectorItem*>(listener_); - } + OverviewItem* listener() { return static_cast<OverviewItem*>(listener_); } protected: // views::View: @@ -342,7 +340,7 @@ void CaptionContainerView::Layout() { gfx::Rect bounds(GetLocalBounds()); - bounds.Inset(kWindowSelectorMargin, kWindowSelectorMargin); + bounds.Inset(kOverviewMargin, kOverviewMargin); listener_button_->SetBoundsRect(bounds); const int visible_height = close_button_->GetPreferredSize().height();
diff --git a/ash/wm/overview/cleanup_animation_observer.cc b/ash/wm/overview/cleanup_animation_observer.cc index 9f6da21..f687b4d 100644 --- a/ash/wm/overview/cleanup_animation_observer.cc +++ b/ash/wm/overview/cleanup_animation_observer.cc
@@ -34,7 +34,7 @@ delete this; } -void CleanupAnimationObserver::SetOwner(WindowSelectorDelegate* owner) { +void CleanupAnimationObserver::SetOwner(OverviewDelegate* owner) { owner_ = owner; }
diff --git a/ash/wm/overview/cleanup_animation_observer.h b/ash/wm/overview/cleanup_animation_observer.h index 80def4c..ce1a8ee5 100644 --- a/ash/wm/overview/cleanup_animation_observer.h +++ b/ash/wm/overview/cleanup_animation_observer.h
@@ -8,7 +8,7 @@ #include <memory> #include "ash/ash_export.h" -#include "ash/wm/overview/window_selector_delegate.h" +#include "ash/wm/overview/overview_delegate.h" #include "base/macros.h" #include "ui/compositor/layer_animation_observer.h" @@ -33,14 +33,12 @@ void OnImplicitAnimationsCompleted() override; // DelayedAnimationObserver: - void SetOwner(WindowSelectorDelegate* owner) override; + void SetOwner(OverviewDelegate* owner) override; void Shutdown() override; private: - FRIEND_TEST_ALL_PREFIXES(WindowSelectorTest, OverviewExitAnimationObserver); - std::unique_ptr<views::Widget> widget_; - WindowSelectorDelegate* owner_; + OverviewDelegate* owner_; DISALLOW_COPY_AND_ASSIGN(CleanupAnimationObserver); };
diff --git a/ash/wm/overview/cleanup_animation_observer_unittest.cc b/ash/wm/overview/cleanup_animation_observer_unittest.cc index b04a8b8..02fc5a1 100644 --- a/ash/wm/overview/cleanup_animation_observer_unittest.cc +++ b/ash/wm/overview/cleanup_animation_observer_unittest.cc
@@ -7,7 +7,7 @@ #include <vector> #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_selector_delegate.h" +#include "ash/wm/overview/overview_delegate.h" #include "base/containers/unique_ptr_adapters.h" #include "ui/aura/window.h" #include "ui/compositor/layer_animation_observer.h" @@ -20,18 +20,18 @@ namespace ash { namespace { -class TestWindowSelectorDelegate : public WindowSelectorDelegate { +class TestOverviewDelegate : public OverviewDelegate { public: - TestWindowSelectorDelegate() = default; + TestOverviewDelegate() = default; - ~TestWindowSelectorDelegate() override { + ~TestOverviewDelegate() override { // Destroy widgets that may be still animating if shell shuts down soon // after exiting overview mode. for (std::unique_ptr<DelayedAnimationObserver>& observer : observers_) observer->Shutdown(); } - // WindowSelectorDelegate: + // OverviewDelegate: void OnSelectionEnded() override {} void AddDelayedAnimationObserver( @@ -53,7 +53,7 @@ private: std::vector<std::unique_ptr<DelayedAnimationObserver>> observers_; - DISALLOW_COPY_AND_ASSIGN(TestWindowSelectorDelegate); + DISALLOW_COPY_AND_ASSIGN(TestOverviewDelegate); }; class CleanupAnimationObserverTest : public AshTestBase, @@ -102,17 +102,17 @@ // Tests that basic create-destroy sequence does not crash. TEST_F(CleanupAnimationObserverTest, CreateDestroy) { - TestWindowSelectorDelegate delegate; + TestOverviewDelegate delegate; std::unique_ptr<views::Widget> widget = CreateWindowWidget(gfx::Rect(40, 40)); auto observer = std::make_unique<CleanupAnimationObserver>(std::move(widget)); delegate.AddDelayedAnimationObserver(std::move(observer)); } // Tests that completing animation deletes the animation observer and the -// test widget and that deleting the WindowSelectorDelegate instance which +// test widget and that deleting the OverviewDelegate instance which // owns the observer does not crash. TEST_F(CleanupAnimationObserverTest, CreateAnimateComplete) { - TestWindowSelectorDelegate delegate; + TestOverviewDelegate delegate; std::unique_ptr<views::Widget> widget = CreateWindowWidget(gfx::Rect(40, 40)); aura::Window* widget_window = widget->GetNativeWindow(); { @@ -135,14 +135,14 @@ // the animation and calls OnImplicitAnimationsCompleted() on the cleanup // observer and auto-deletes the owned widget. EXPECT_TRUE(widget_destroyed()); - // TestWindowSelectorDelegate going out of scope should not crash. + // TestOverviewDelegate going out of scope should not crash. } // Tests that starting an animation and exiting doesn't crash. If not for -// TestWindowSelectorDelegate calling Shutdown() on a CleanupAnimationObserver +// TestOverviewDelegate calling Shutdown() on a CleanupAnimationObserver // instance in destructor, this test would have crashed. TEST_F(CleanupAnimationObserverTest, CreateAnimateShutdown) { - TestWindowSelectorDelegate delegate; + TestOverviewDelegate delegate; std::unique_ptr<views::Widget> widget = CreateWindowWidget(gfx::Rect(40, 40)); aura::Window* widget_window = widget->GetNativeWindow(); {
diff --git a/ash/wm/overview/overview_constants.h b/ash/wm/overview/overview_constants.h index e4a8d06..639bb78 100644 --- a/ash/wm/overview/overview_constants.h +++ b/ash/wm/overview/overview_constants.h
@@ -17,7 +17,7 @@ // Cover the transformed window including the gaps between the windows with a // transparent shield to block the input events from reaching the transformed // window while in overview. -constexpr int kWindowSelectorMargin = kWindowMargin * 2; +constexpr int kOverviewMargin = kWindowMargin * 2; // Height of an item header. constexpr int kHeaderHeightDp = 40;
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/overview_controller.cc similarity index 79% rename from ash/wm/overview/window_selector_controller.cc rename to ash/wm/overview/overview_controller.cc index e5a4fa03..26da70f5a 100644 --- a/ash/wm/overview/window_selector_controller.cc +++ b/ash/wm/overview/overview_controller.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include <vector> @@ -16,10 +16,10 @@ #include "ash/wallpaper/wallpaper_widget_controller.h" #include "ash/wm/mru_window_tracker.h" #include "ash/wm/overview/overview_constants.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_item.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/overview/overview_utils.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_item.h" #include "ash/wm/root_window_finder.h" #include "ash/wm/screen_pinning_controller.h" #include "ash/wm/splitview/split_view_controller.h" @@ -89,7 +89,7 @@ // mode. Blurs the wallpaper automatically if the wallpaper is not visible // prior to entering overview mode (covered by a window), otherwise animates // the blur. -class WindowSelectorController::OverviewBlurController +class OverviewController::OverviewBlurController : public ui::CompositorAnimationObserver, public aura::WindowObserver { public: @@ -186,14 +186,14 @@ const float value = should_blur ? kWallpaperBlurSigma : kWallpaperClearBlurSigma; - WindowSelector* window_selector = - Shell::Get()->window_selector_controller()->window_selector(); + OverviewSession* overview_session = + Shell::Get()->overview_controller()->overview_session(); for (aura::Window* root : Shell::Get()->GetAllRootWindows()) { // No need to animate the blur on exiting as this should only be called // after overview animations are finished. if (should_blur) { - DCHECK(window_selector); - if (window_selector->ShouldAnimateWallpaper(root)) { + DCHECK(overview_session); + if (overview_session->ShouldAnimateWallpaper(root)) { root->AddObserver(this); roots_to_animate_.push_back(root); continue; @@ -220,14 +220,14 @@ DISALLOW_COPY_AND_ASSIGN(OverviewBlurController); }; -WindowSelectorController::WindowSelectorController() +OverviewController::OverviewController() : occlusion_pause_duration_for_end_ms_(kOcclusionPauseDurationForEndMs), overview_blur_controller_(std::make_unique<OverviewBlurController>()), weak_ptr_factory_(this) { Shell::Get()->activation_client()->AddObserver(this); } -WindowSelectorController::~WindowSelectorController() { +OverviewController::~OverviewController() { Shell::Get()->activation_client()->RemoveObserver(this); overview_blur_controller_.reset(); @@ -238,14 +238,14 @@ animation_observer->Shutdown(); } - if (window_selector_.get()) { - window_selector_->Shutdown(); - window_selector_.reset(); + if (overview_session_) { + overview_session_->Shutdown(); + overview_session_.reset(); } } // static -bool WindowSelectorController::CanSelect() { +bool OverviewController::CanSelect() { // Don't allow a window overview if the user session is not active (e.g. // locked or in user-adding screen) or a modal dialog is open or running in // kiosk app session. @@ -257,8 +257,8 @@ !session_controller->IsRunningInAppMode(); } -bool WindowSelectorController::ToggleOverview( - WindowSelector::EnterExitOverviewType type) { +bool OverviewController::ToggleOverview( + OverviewSession::EnterExitOverviewType type) { // Hide the virtual keyboard as it obstructs the overview mode. // Don't need to hide if it's the a11y keyboard, as overview mode // can accept text input and it resizes correctly with the a11y keyboard. @@ -281,17 +281,17 @@ // We may want to slide the overview grid in or out in some cases, even if // not explicitly stated. - WindowSelector::EnterExitOverviewType new_type = type; - if (type == WindowSelector::EnterExitOverviewType::kNormal && + OverviewSession::EnterExitOverviewType new_type = type; + if (type == OverviewSession::EnterExitOverviewType::kNormal && ShouldSlideInOutOverview(windows)) { - new_type = WindowSelector::EnterExitOverviewType::kWindowsMinimized; + new_type = OverviewSession::EnterExitOverviewType::kWindowsMinimized; } if (IsSelecting()) { // Do not allow ending overview if we're in single split mode unless swiping // up from the shelf. if (windows.empty() && Shell::Get()->IsSplitViewModeActive() && - type != WindowSelector::EnterExitOverviewType::kSwipeFromShelf) { + type != OverviewSession::EnterExitOverviewType::kSwipeFromShelf) { return true; } @@ -301,9 +301,9 @@ std::make_unique<aura::WindowOcclusionTracker::ScopedPause>( Shell::Get()->aura_env()); - window_selector_->set_enter_exit_overview_type(new_type); - if (type == WindowSelector::EnterExitOverviewType::kWindowsMinimized || - type == WindowSelector::EnterExitOverviewType::kSwipeFromShelf) { + overview_session_->set_enter_exit_overview_type(new_type); + if (type == OverviewSession::EnterExitOverviewType::kWindowsMinimized || + type == OverviewSession::EnterExitOverviewType::kSwipeFromShelf) { // Minimize the windows without animations. When the home launcher button // is pressed, minimized widgets will get created in their place, and // those widgets will be slid out of overview. Otherwise, @@ -338,10 +338,10 @@ std::make_unique<aura::WindowOcclusionTracker::ScopedPause>( Shell::Get()->aura_env()); - window_selector_ = std::make_unique<WindowSelector>(this); - window_selector_->set_enter_exit_overview_type(new_type); + overview_session_ = std::make_unique<OverviewSession>(this); + overview_session_->set_enter_exit_overview_type(new_type); Shell::Get()->NotifyOverviewModeStarting(); - window_selector_->Init(windows, hide_windows); + overview_session_->Init(windows, hide_windows); if (IsBlurAllowed()) overview_blur_controller_->Blur(); if (start_animations_.empty()) @@ -351,49 +351,49 @@ return true; } -void WindowSelectorController::OnStartingAnimationComplete(bool canceled) { +void OverviewController::OnStartingAnimationComplete(bool canceled) { Shell::Get()->NotifyOverviewModeStartingAnimationComplete(canceled); - if (window_selector_) - window_selector_->OnStartingAnimationComplete(canceled); - reset_pauser_task_.Reset(base::BindOnce( - &WindowSelectorController::ResetPauser, weak_ptr_factory_.GetWeakPtr())); + if (overview_session_) + overview_session_->OnStartingAnimationComplete(canceled); + reset_pauser_task_.Reset(base::BindOnce(&OverviewController::ResetPauser, + weak_ptr_factory_.GetWeakPtr())); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, reset_pauser_task_.callback(), base::TimeDelta::FromMilliseconds(kOcclusionPauseDurationForStartMs)); } -void WindowSelectorController::OnEndingAnimationComplete(bool canceled) { +void OverviewController::OnEndingAnimationComplete(bool canceled) { Shell::Get()->NotifyOverviewModeEndingAnimationComplete(canceled); - reset_pauser_task_.Reset(base::BindOnce( - &WindowSelectorController::ResetPauser, weak_ptr_factory_.GetWeakPtr())); + reset_pauser_task_.Reset(base::BindOnce(&OverviewController::ResetPauser, + weak_ptr_factory_.GetWeakPtr())); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, reset_pauser_task_.callback(), base::TimeDelta::FromMilliseconds(occlusion_pause_duration_for_end_ms_)); } -void WindowSelectorController::ResetPauser() { +void OverviewController::ResetPauser() { occlusion_tracker_pauser_.reset(); } -bool WindowSelectorController::IsSelecting() const { - return window_selector_ != nullptr; +bool OverviewController::IsSelecting() const { + return overview_session_ != nullptr; } -bool WindowSelectorController::IsCompletingShutdownAnimations() { +bool OverviewController::IsCompletingShutdownAnimations() { return !delayed_animations_.empty(); } -void WindowSelectorController::IncrementSelection(int increment) { +void OverviewController::IncrementSelection(int increment) { DCHECK(IsSelecting()); - window_selector_->IncrementSelection(increment); + overview_session_->IncrementSelection(increment); } -bool WindowSelectorController::AcceptSelection() { +bool OverviewController::AcceptSelection() { DCHECK(IsSelecting()); - return window_selector_->AcceptSelection(); + return overview_session_->AcceptSelection(); } -void WindowSelectorController::OnOverviewButtonTrayLongPressed( +void OverviewController::OnOverviewButtonTrayLongPressed( const gfx::Point& event_location) { // Do nothing if split view is not enabled. if (!ShouldAllowSplitView()) @@ -438,7 +438,7 @@ return; } - WindowSelectorItem* item_to_snap = nullptr; + OverviewItem* item_to_snap = nullptr; if (!IsSelecting()) { // The current active window may be a transient child. aura::Window* active_window = wm::GetActiveWindow(); @@ -462,18 +462,16 @@ // If we are not in overview mode, enter overview mode and then find the // window item to snap. ToggleOverview(); - DCHECK(window_selector_); - WindowGrid* current_grid = - window_selector_->GetGridWithRootWindow(active_window->GetRootWindow()); - if (current_grid) { - item_to_snap = - current_grid->GetWindowSelectorItemContaining(active_window); - } + DCHECK(overview_session_); + OverviewGrid* current_grid = overview_session_->GetGridWithRootWindow( + active_window->GetRootWindow()); + if (current_grid) + item_to_snap = current_grid->GetOverviewItemContaining(active_window); } else { // Currently in overview mode, with no snapped windows. Retrieve the first // window selector item and attempt to snap that window. - DCHECK(window_selector_); - WindowGrid* current_grid = window_selector_->GetGridWithRootWindow( + DCHECK(overview_session_); + OverviewGrid* current_grid = overview_session_->GetGridWithRootWindow( wm::GetRootWindowAt(event_location)); if (current_grid) { const auto& windows = current_grid->window_list(); @@ -494,21 +492,21 @@ } std::vector<aura::Window*> -WindowSelectorController::GetWindowsListInOverviewGridsForTesting() { +OverviewController::GetWindowsListInOverviewGridsForTesting() { std::vector<aura::Window*> windows; - for (const std::unique_ptr<WindowGrid>& grid : - window_selector_->grid_list_for_testing()) { - for (const auto& window_selector_item : grid->window_list()) - windows.push_back(window_selector_item->GetWindow()); + for (const std::unique_ptr<OverviewGrid>& grid : + overview_session_->grid_list_for_testing()) { + for (const auto& overview_session_item : grid->window_list()) + windows.push_back(overview_session_item->GetWindow()); } return windows; } -// TODO(flackr): Make WindowSelectorController observe the activation of -// windows, so we can remove WindowSelectorDelegate. +// TODO(flackr): Make OverviewController observe the activation of +// windows, so we can remove OverviewDelegate. // TODO(sammiequon): Rename to something like EndOverview() and refactor to use // a single entry point for overview. -void WindowSelectorController::OnSelectionEnded() { +void OverviewController::OnSelectionEnded() { if (!IsSelecting()) return; @@ -523,13 +521,13 @@ OnStartingAnimationComplete(/*canceled=*/true); start_animations_.clear(); - window_selector_->UpdateMaskAndShadow(/*show=*/false); + overview_session_->UpdateMaskAndShadow(/*show=*/false); - auto* window_selector = window_selector_.release(); - Shell::Get()->NotifyOverviewModeEnding(window_selector); - window_selector->Shutdown(); - // Don't delete |window_selector_| yet since the stack is still using it. - base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, window_selector); + auto* overview_session = overview_session_.release(); + Shell::Get()->NotifyOverviewModeEnding(overview_session); + overview_session->Shutdown(); + // Don't delete |overview_session_| yet since the stack is still using it. + base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, overview_session); last_selection_time_ = base::Time::Now(); Shell::Get()->NotifyOverviewModeEnded(); @@ -541,13 +539,13 @@ } } -void WindowSelectorController::AddDelayedAnimationObserver( +void OverviewController::AddDelayedAnimationObserver( std::unique_ptr<DelayedAnimationObserver> animation_observer) { animation_observer->SetOwner(this); delayed_animations_.push_back(std::move(animation_observer)); } -void WindowSelectorController::RemoveAndDestroyAnimationObserver( +void OverviewController::RemoveAndDestroyAnimationObserver( DelayedAnimationObserver* animation_observer) { const bool previous_empty = delayed_animations_.empty(); base::EraseIf(delayed_animations_, @@ -556,8 +554,8 @@ // If something has been removed and its the last observer, unblur the // wallpaper and let observers know. This function may be called while still // in overview (ie. splitview restores one window but leaves overview active) - // so check that |window_selector_| is null before notifying. - if (!window_selector_ && !previous_empty && delayed_animations_.empty()) { + // so check that |overview_session_| is null before notifying. + if (!overview_session_ && !previous_empty && delayed_animations_.empty()) { if (IsBlurAllowed()) overview_blur_controller_->Unblur(); @@ -565,30 +563,30 @@ } } -void WindowSelectorController::OnWindowActivating(ActivationReason reason, - aura::Window* gained_active, - aura::Window* lost_active) { - if (window_selector_) - window_selector_->OnWindowActivating(reason, gained_active, lost_active); +void OverviewController::OnWindowActivating(ActivationReason reason, + aura::Window* gained_active, + aura::Window* lost_active) { + if (overview_session_) + overview_session_->OnWindowActivating(reason, gained_active, lost_active); } -void WindowSelectorController::OnAttemptToReactivateWindow( +void OverviewController::OnAttemptToReactivateWindow( aura::Window* request_active, aura::Window* actual_active) { - if (window_selector_) { - window_selector_->OnWindowActivating( + if (overview_session_) { + overview_session_->OnWindowActivating( ::wm::ActivationChangeObserver::ActivationReason::ACTIVATION_CLIENT, request_active, actual_active); } } -void WindowSelectorController::AddStartAnimationObserver( +void OverviewController::AddStartAnimationObserver( std::unique_ptr<DelayedAnimationObserver> animation_observer) { animation_observer->SetOwner(this); start_animations_.push_back(std::move(animation_observer)); } -void WindowSelectorController::RemoveAndDestroyStartAnimationObserver( +void OverviewController::RemoveAndDestroyStartAnimationObserver( DelayedAnimationObserver* animation_observer) { const bool previous_empty = start_animations_.empty(); base::EraseIf(start_animations_, base::MatchesUniquePtr(animation_observer)); @@ -598,11 +596,11 @@ } // static -void WindowSelectorController::SetDoNotChangeWallpaperBlurForTests() { +void OverviewController::SetDoNotChangeWallpaperBlurForTests() { g_disable_wallpaper_blur_for_tests = true; } -void WindowSelectorController::OnSelectionStarted() { +void OverviewController::OnSelectionStarted() { if (!last_selection_time_.is_null()) { UMA_HISTOGRAM_LONG_TIMES("Ash.WindowSelector.TimeBetweenUse", base::Time::Now() - last_selection_time_);
diff --git a/ash/wm/overview/window_selector_controller.h b/ash/wm/overview/overview_controller.h similarity index 80% rename from ash/wm/overview/window_selector_controller.h rename to ash/wm/overview/overview_controller.h index 80da3044..8fae320 100644 --- a/ash/wm/overview/window_selector_controller.h +++ b/ash/wm/overview/overview_controller.h
@@ -2,37 +2,34 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_ -#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_ +#ifndef ASH_WM_OVERVIEW_OVERVIEW_CONTROLLER_H_ +#define ASH_WM_OVERVIEW_OVERVIEW_CONTROLLER_H_ #include <memory> #include <vector> #include "ash/ash_export.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_delegate.h" +#include "ash/wm/overview/overview_delegate.h" +#include "ash/wm/overview/overview_session.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "ui/aura/window_occlusion_tracker.h" namespace ash { -class WindowSelector; -class WindowSelectorTest; -// Manages a window selector which displays an overview of all windows and +// Manages a overview session which displays an overview of all windows and // allows selecting a window to activate it. -class ASH_EXPORT WindowSelectorController - : public WindowSelectorDelegate, - public ::wm::ActivationChangeObserver { +class ASH_EXPORT OverviewController : public OverviewDelegate, + public ::wm::ActivationChangeObserver { public: enum class AnimationCompleteReason { kCompleted, kCanceled, }; - WindowSelectorController(); - ~WindowSelectorController() override; + OverviewController(); + ~OverviewController() override; // Returns true if selecting windows in an overview is enabled. This is false // at certain times, such as when the lock screen is visible. @@ -41,8 +38,8 @@ // Attempts to toggle overview mode and returns true if successful (showing // overview would be unsuccessful if there are no windows to show). Depending // on |type| the enter/exit animation will look different. - bool ToggleOverview(WindowSelector::EnterExitOverviewType type = - WindowSelector::EnterExitOverviewType::kNormal); + bool ToggleOverview(OverviewSession::EnterExitOverviewType type = + OverviewSession::EnterExitOverviewType::kNormal); // Returns true if window selection mode is active. bool IsSelecting() const; @@ -68,7 +65,7 @@ // overview mode is active for testing. std::vector<aura::Window*> GetWindowsListInOverviewGridsForTesting(); - // WindowSelectorDelegate: + // OverviewDelegate: void OnSelectionEnded() override; void AddDelayedAnimationObserver( std::unique_ptr<DelayedAnimationObserver> animation) override; @@ -89,7 +86,7 @@ void OnAttemptToReactivateWindow(aura::Window* request_active, aura::Window* actual_active) override; - WindowSelector* window_selector() { return window_selector_.get(); } + OverviewSession* overview_session() { return overview_session_.get(); } void set_occlusion_pause_duration_for_end_ms_for_test(int duration) { occlusion_pause_duration_for_end_ms_ = duration; @@ -97,10 +94,9 @@ private: class OverviewBlurController; - friend class WindowSelectorTest; + friend class OverviewSessionTest; FRIEND_TEST_ALL_PREFIXES(TabletModeControllerTest, DisplayDisconnectionDuringOverview); - FRIEND_TEST_ALL_PREFIXES(WindowSelectorTest, OverviewExitAnimationObserver); // There is no need to blur or unblur the wallpaper for tests. static void SetDoNotChangeWallpaperBlurForTests(); @@ -124,7 +120,7 @@ std::unique_ptr<aura::WindowOcclusionTracker::ScopedPause> occlusion_tracker_pauser_; - std::unique_ptr<WindowSelector> window_selector_; + std::unique_ptr<OverviewSession> overview_session_; base::Time last_selection_time_; int occlusion_pause_duration_for_end_ms_; @@ -135,11 +131,11 @@ base::CancelableOnceClosure reset_pauser_task_; - base::WeakPtrFactory<WindowSelectorController> weak_ptr_factory_; + base::WeakPtrFactory<OverviewController> weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(WindowSelectorController); + DISALLOW_COPY_AND_ASSIGN(OverviewController); }; } // namespace ash -#endif // ASH_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_ +#endif // ASH_WM_OVERVIEW_OVERVIEW_CONTROLLER_H_
diff --git a/ash/wm/overview/window_selector_controller_unittest.cc b/ash/wm/overview/overview_controller_unittest.cc similarity index 81% rename from ash/wm/overview/window_selector_controller_unittest.cc rename to ash/wm/overview/overview_controller_unittest.cc index 0f3dab6..a0cba8bd 100644 --- a/ash/wm/overview/window_selector_controller_unittest.cc +++ b/ash/wm/overview/overview_controller_unittest.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/app_list/test/app_list_test_helper.h" #include "ash/shell.h" #include "ash/shell_observer.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_selector.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" #include "ash/wm/window_resizer.h" #include "ash/wm/window_util.h" @@ -50,10 +50,10 @@ // ShellObserver: void OnOverviewModeStarting() override { UpdateLastAnimationWasSlide( - Shell::Get()->window_selector_controller()->window_selector()); + Shell::Get()->overview_controller()->overview_session()); } - void OnOverviewModeEnding(WindowSelector* window_selector) override { - UpdateLastAnimationWasSlide(window_selector); + void OnOverviewModeEnding(OverviewSession* overview_session) override { + UpdateLastAnimationWasSlide(overview_session); } void OnOverviewModeStartingAnimationComplete(bool canceled) override { if (!should_monitor_animation_state_) @@ -104,11 +104,11 @@ bool last_animation_was_slide() const { return last_animation_was_slide_; } private: - void UpdateLastAnimationWasSlide(WindowSelector* selector) { + void UpdateLastAnimationWasSlide(OverviewSession* selector) { DCHECK(selector); last_animation_was_slide_ = selector->enter_exit_overview_type() == - WindowSelector::EnterExitOverviewType::kWindowsMinimized; + OverviewSession::EnterExitOverviewType::kWindowsMinimized; } AnimationState starting_animation_state_ = UNKNOWN; @@ -136,11 +136,11 @@ } // namespace -using WindowSelectorControllerTest = AshTestBase; +using OverviewControllerTest = AshTestBase; // Tests that press the overview key in keyboard when a window is being dragged // in clamshell mode should not toggle overview. -TEST_F(WindowSelectorControllerTest, +TEST_F(OverviewControllerTest, PressOverviewKeyDuringWindowDragInClamshellMode) { ASSERT_FALSE(TabletModeControllerTestApi().IsTabletModeStarted()); std::unique_ptr<aura::Window> dragged_window = CreateTestWindow(); @@ -150,22 +150,22 @@ resizer->Drag(CalculateDragPoint(*resizer, 10, 0), 0); EXPECT_TRUE(wm::GetWindowState(dragged_window.get())->is_dragged()); GetEventGenerator()->PressKey(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_NONE); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); resizer->CompleteDrag(); } -TEST_F(WindowSelectorControllerTest, AnimationCallbacks) { +TEST_F(OverviewControllerTest, AnimationCallbacks) { ui::ScopedAnimationDurationScaleMode non_zero( ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); TestShellObserver observer(/*should_monitor_animation_state = */ true); // Enter without windows. - Shell::Get()->window_selector_controller()->ToggleOverview(); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + Shell::Get()->overview_controller()->ToggleOverview(); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(TestShellObserver::COMPLETED, observer.starting_animation_state()); // Exit winhtout windows still creates an animation. - Shell::Get()->window_selector_controller()->ToggleOverview(); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + Shell::Get()->overview_controller()->ToggleOverview(); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(TestShellObserver::UNKNOWN, observer.ending_animation_state()); observer.WaitForEndingAnimationComplete(); @@ -182,55 +182,55 @@ ASSERT_EQ(TestShellObserver::UNKNOWN, observer.ending_animation_state()); // Enter with windows. - Shell::Get()->window_selector_controller()->ToggleOverview(); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + Shell::Get()->overview_controller()->ToggleOverview(); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(TestShellObserver::UNKNOWN, observer.starting_animation_state()); // Exit with windows before starting animation ends. - Shell::Get()->window_selector_controller()->ToggleOverview(); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + Shell::Get()->overview_controller()->ToggleOverview(); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(TestShellObserver::CANCELED, observer.starting_animation_state()); EXPECT_EQ(TestShellObserver::UNKNOWN, observer.ending_animation_state()); observer.Reset(); // Enter again before exit animation ends. - Shell::Get()->window_selector_controller()->ToggleOverview(); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + Shell::Get()->overview_controller()->ToggleOverview(); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(TestShellObserver::CANCELED, observer.ending_animation_state()); EXPECT_EQ(TestShellObserver::UNKNOWN, observer.starting_animation_state()); // Activating window while entering animation should cancel the overview. wm::ActivateWindow(window1.get()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(TestShellObserver::CANCELED, observer.starting_animation_state()); } // Tests the slide animation for overview is never used in clamshell. -TEST_F(WindowSelectorControllerTest, OverviewEnterExitAnimationClamshell) { +TEST_F(OverviewControllerTest, OverviewEnterExitAnimationClamshell) { TestShellObserver observer(/*should_monitor_animation_state = */ false); const gfx::Rect bounds(200, 200); std::unique_ptr<aura::Window> window( CreateTestWindowInShellWithBounds(bounds)); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_FALSE(observer.last_animation_was_slide()); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_FALSE(observer.last_animation_was_slide()); // Even with all window minimized, there should not be a slide animation. - ASSERT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); wm::GetWindowState(window.get())->Minimize(); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_FALSE(observer.last_animation_was_slide()); } // Tests the slide animation for overview is used in tablet if all windows // are minimized, and that if overview is exited from the home launcher all // windows are minimized. -TEST_F(WindowSelectorControllerTest, OverviewEnterExitAnimationTablet) { +TEST_F(OverviewControllerTest, OverviewEnterExitAnimationTablet) { TestShellObserver observer(/*should_monitor_animation_state = */ false); // Ensure calls to EnableTabletModeWindowManager complete. @@ -242,27 +242,27 @@ std::unique_ptr<aura::Window> window( CreateTestWindowInShellWithBounds(bounds)); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_FALSE(observer.last_animation_was_slide()); // Exit to home launcher. Slide animation should be used, and all windows // should be minimized. - Shell::Get()->window_selector_controller()->ToggleOverview( - WindowSelector::EnterExitOverviewType::kWindowsMinimized); + Shell::Get()->overview_controller()->ToggleOverview( + OverviewSession::EnterExitOverviewType::kWindowsMinimized); EXPECT_TRUE(observer.last_animation_was_slide()); - ASSERT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_TRUE(wm::GetWindowState(window.get())->IsMinimized()); // All windows are minimized, so we should use the slide animation. - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_TRUE(observer.last_animation_was_slide()); } -TEST_F(WindowSelectorControllerTest, OcclusionTest) { +TEST_F(OverviewControllerTest, OcclusionTest) { using OcclusionState = aura::Window::OcclusionState; Shell::Get() - ->window_selector_controller() + ->overview_controller() ->set_occlusion_pause_duration_for_end_ms_for_test(100); TestShellObserver observer(/*should_monitor_animation_state = */ true); ui::ScopedAnimationDurationScaleMode non_zero( @@ -283,7 +283,7 @@ EXPECT_EQ(OcclusionState::VISIBLE, window2->occlusion_state()); // Enter with windows. - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_EQ(OcclusionState::OCCLUDED, window1->occlusion_state()); EXPECT_EQ(OcclusionState::VISIBLE, window2->occlusion_state()); @@ -295,7 +295,7 @@ EXPECT_EQ(OcclusionState::VISIBLE, window1->occlusion_state()); // Exit with windows. - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_EQ(OcclusionState::VISIBLE, window1->occlusion_state()); EXPECT_EQ(OcclusionState::VISIBLE, window2->occlusion_state()); observer.WaitForEndingAnimationComplete(); @@ -307,7 +307,7 @@ observer.Reset(); // Enter again. - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_EQ(OcclusionState::OCCLUDED, window1->occlusion_state()); EXPECT_EQ(OcclusionState::VISIBLE, window2->occlusion_state()); auto* active = wm::GetActiveWindow(); @@ -326,7 +326,7 @@ observer.WaitForEndingAnimationComplete(); // Windows are visible because tracker is paused. - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(OcclusionState::VISIBLE, window2->occlusion_state()); EXPECT_EQ(OcclusionState::VISIBLE, window1->occlusion_state()); WaitForOcclusionStateChange(window2.get()); @@ -335,23 +335,23 @@ } // Tests that beginning window selection hides the app list. -TEST_F(WindowSelectorControllerTest, SelectingHidesAppList) { +TEST_F(OverviewControllerTest, SelectingHidesAppList) { std::unique_ptr<aura::Window> window(CreateTestWindow()); GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplay().id()); GetAppListTestHelper()->CheckVisibility(true); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); GetAppListTestHelper()->WaitUntilIdle(); GetAppListTestHelper()->CheckVisibility(false); } -class OverviewVirtualKeyboardTest : public WindowSelectorControllerTest { +class OverviewVirtualKeyboardTest : public OverviewControllerTest { protected: void SetUp() override { base::CommandLine::ForCurrentProcess()->AppendSwitch( keyboard::switches::kEnableVirtualKeyboard); - WindowSelectorControllerTest::SetUp(); + OverviewControllerTest::SetUp(); TabletModeControllerTestApi().EnterTabletMode(); base::RunLoop().RunUntilIdle(); @@ -374,7 +374,7 @@ keyboard_controller()->ShowKeyboard(false /* locked */); ASSERT_TRUE(keyboard::WaitUntilShown()); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); // Timeout failure here if the keyboard does not hide. keyboard::WaitUntilHidden(); @@ -385,7 +385,7 @@ keyboard_controller()->ShowKeyboard(true /* locked */); ASSERT_TRUE(keyboard::WaitUntilShown()); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_FALSE(keyboard::IsKeyboardHiding()); }
diff --git a/ash/wm/overview/window_selector_delegate.h b/ash/wm/overview/overview_delegate.h similarity index 82% rename from ash/wm/overview/window_selector_delegate.h rename to ash/wm/overview/overview_delegate.h index 8534cab9..036fbb0 100644 --- a/ash/wm/overview/window_selector_delegate.h +++ b/ash/wm/overview/overview_delegate.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_WM_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_ -#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_ +#ifndef ASH_WM_OVERVIEW_OVERVIEW_DELEGATE_H_ +#define ASH_WM_OVERVIEW_OVERVIEW_DELEGATE_H_ #include <memory> @@ -12,7 +12,7 @@ namespace ash { -class WindowSelectorDelegate; +class OverviewDelegate; class ASH_EXPORT DelayedAnimationObserver { public: @@ -20,7 +20,7 @@ // Sets an |owner| that can be notified when the animation that |this| // observes completes. - virtual void SetOwner(WindowSelectorDelegate* owner) = 0; + virtual void SetOwner(OverviewDelegate* owner) = 0; // Can be called by the |owner| to delete the owned widget. The |owner| is // then responsible for deleting |this| instance of the @@ -28,8 +28,8 @@ virtual void Shutdown() = 0; }; -// Implement this class to handle the selection event from WindowSelector. -class ASH_EXPORT WindowSelectorDelegate { +// Implement this class to handle the selection event from OverviewSession. +class ASH_EXPORT OverviewDelegate { public: // Invoked if selection is ended. virtual void OnSelectionEnded() = 0; @@ -58,9 +58,9 @@ DelayedAnimationObserver* animation_observer) = 0; protected: - virtual ~WindowSelectorDelegate() {} + virtual ~OverviewDelegate() {} }; } // namespace ash -#endif // ASH_WM_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_ +#endif // ASH_WM_OVERVIEW_OVERVIEW_DELEGATE_H_
diff --git a/ash/wm/overview/window_grid.cc b/ash/wm/overview/overview_grid.cc similarity index 81% rename from ash/wm/overview/window_grid.cc rename to ash/wm/overview/overview_grid.cc index 37f4b747..fd6ec70f 100644 --- a/ash/wm/overview/window_grid.cc +++ b/ash/wm/overview/overview_grid.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/overview/window_grid.h" +#include "ash/wm/overview/overview_grid.h" #include <algorithm> #include <functional> @@ -27,13 +27,13 @@ #include "ash/wm/overview/cleanup_animation_observer.h" #include "ash/wm/overview/drop_target_view.h" #include "ash/wm/overview/overview_constants.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_delegate.h" +#include "ash/wm/overview/overview_item.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/overview/overview_utils.h" #include "ash/wm/overview/rounded_rect_view.h" #include "ash/wm/overview/scoped_overview_animation_settings.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_delegate.h" -#include "ash/wm/overview/window_selector_item.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_drag_indicators.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" @@ -108,16 +108,16 @@ constexpr int kDropTargetTransitionMilliseconds = 250; // Returns the vector for the fade in animation. -gfx::Vector2d GetSlideVectorForFadeIn(WindowSelector::Direction direction, +gfx::Vector2d GetSlideVectorForFadeIn(OverviewSession::Direction direction, const gfx::Rect& bounds) { gfx::Vector2d vector; switch (direction) { - case WindowSelector::UP: - case WindowSelector::LEFT: + case OverviewSession::UP: + case OverviewSession::LEFT: vector.set_x(-bounds.width()); break; - case WindowSelector::DOWN: - case WindowSelector::RIGHT: + case OverviewSession::DOWN: + case OverviewSession::RIGHT: vector.set_x(bounds.width()); break; } @@ -138,7 +138,7 @@ params.accept_events = false; params.parent = dragged_window->parent(); params.bounds = dragged_window->bounds(); - std::unique_ptr<views::Widget> widget = std::make_unique<views::Widget>(); + auto widget = std::make_unique<views::Widget>(); widget->set_focus_on_creation(false); widget->Init(params); @@ -201,7 +201,7 @@ // ShieldView contains the background for overview mode. It also contains text // which is shown if there are no windows to be displayed. -class WindowGrid::ShieldView : public views::View { +class OverviewGrid::ShieldView : public views::View { public: ShieldView() { background_view_ = new views::View(); @@ -284,7 +284,7 @@ // into. After the dragged tabs merge into the overview window, and if the // overview window represents a minimized window, we need to update the // overview minimized widget's content view so that it reflects the merge. -class WindowGrid::TargetWindowObserver : public aura::WindowObserver { +class OverviewGrid::TargetWindowObserver : public aura::WindowObserver { public: TargetWindowObserver() = default; ~TargetWindowObserver() override { StopObserving(); } @@ -318,18 +318,18 @@ private: void UpdateWindowItemInOverviewContaining(aura::Window* window) { - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - if (!window_selector_controller->IsSelecting()) + OverviewController* overview_controller = + Shell::Get()->overview_controller(); + if (!overview_controller->IsSelecting()) return; - WindowGrid* grid = - window_selector_controller->window_selector()->GetGridWithRootWindow( + OverviewGrid* grid = + overview_controller->overview_session()->GetGridWithRootWindow( window->GetRootWindow()); if (!grid) return; - WindowSelectorItem* item = grid->GetWindowSelectorItemContaining(window); + OverviewItem* item = grid->GetOverviewItemContaining(window); if (!item) return; @@ -347,12 +347,12 @@ DISALLOW_COPY_AND_ASSIGN(TargetWindowObserver); }; -WindowGrid::WindowGrid(aura::Window* root_window, - const std::vector<aura::Window*>& windows, - WindowSelector* window_selector, - const gfx::Rect& bounds_in_screen) +OverviewGrid::OverviewGrid(aura::Window* root_window, + const std::vector<aura::Window*>& windows, + OverviewSession* overview_session, + const gfx::Rect& bounds_in_screen) : root_window_(root_window), - window_selector_(window_selector), + overview_session_(overview_session), window_observer_(this), window_state_observer_(this), bounds_(bounds_in_screen) { @@ -372,14 +372,14 @@ window_observer_.Add(window); window_state_observer_.Add(wm::GetWindowState(window)); window_list_.push_back( - std::make_unique<WindowSelectorItem>(window, window_selector_, this)); + std::make_unique<OverviewItem>(window, overview_session_, this)); } } -WindowGrid::~WindowGrid() = default; +OverviewGrid::~OverviewGrid() = default; // static -SkColor WindowGrid::GetShieldColor() { +SkColor OverviewGrid::GetShieldColor() { SkColor shield_color = kShieldColor; // Extract the dark muted color from the wallpaper and mix it with // |kShieldBaseColor|. Just use |kShieldBaseColor| if the dark muted color @@ -394,18 +394,19 @@ return shield_color; } -void WindowGrid::Shutdown() { +void OverviewGrid::Shutdown() { for (const auto& window : window_list_) window->Shutdown(); - // Shutdown() implies |window_selector_| is about to be deleted, so reset it. - auto exit_overview_type = window_selector_->enter_exit_overview_type(); - window_selector_ = nullptr; + // Shutdown() implies |overview_session_| is about to be deleted, so reset it. + auto exit_overview_session_type = + overview_session_->enter_exit_overview_type(); + overview_session_ = nullptr; // HomeLauncherGestureHandler will handle fading/sliding |shield_widget_| in // this exit mode. - if (exit_overview_type == - WindowSelector::EnterExitOverviewType::kSwipeFromShelf) { + if (exit_overview_session_type == + OverviewSession::EnterExitOverviewType::kSwipeFromShelf) { return; } @@ -418,21 +419,21 @@ } } -void WindowGrid::PrepareForOverview() { +void OverviewGrid::PrepareForOverview() { InitShieldWidget(); for (const auto& window : window_list_) window->PrepareForOverview(); prepared_for_overview_ = true; } -void WindowGrid::PositionWindows( +void OverviewGrid::PositionWindows( bool animate, - WindowSelectorItem* ignored_item, - WindowSelector::OverviewTransition transition) { - if (!window_selector_) + OverviewItem* ignored_item, + OverviewSession::OverviewTransition transition) { + if (!overview_session_) return; - DCHECK_NE(transition, WindowSelector::OverviewTransition::kExit); + DCHECK_NE(transition, OverviewSession::OverviewTransition::kExit); DCHECK(shield_widget_.get()); // Keep the background shield widget covering the whole screen. A grid without // any windows still needs the shield widget bounds updated. @@ -451,11 +452,11 @@ // position |ignored_item| if it is not nullptr and matches a item in // |window_list_|. OverviewAnimationType animation_type = - transition == WindowSelector::OverviewTransition::kEnter + transition == OverviewSession::OverviewTransition::kEnter ? OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS_ON_ENTER : OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS_IN_OVERVIEW; for (size_t i = 0; i < window_list_.size(); ++i) { - WindowSelectorItem* window_item = window_list_[i].get(); + OverviewItem* window_item = window_list_[i].get(); if (window_item->animating_to_close() || (ignored_item != nullptr && window_item == ignored_item)) { continue; @@ -465,7 +466,7 @@ bool should_animate_item = animate; // If we're in entering overview process, not all window items in the grid // might need animation even if the grid needs animation. - if (animate && transition == WindowSelector::OverviewTransition::kEnter) + if (animate && transition == OverviewSession::OverviewTransition::kEnter) should_animate_item = window_item->should_animate_when_entering(); // Do not do the bounds animation for the drop target. We'll do the opacity // animation by ourselves. @@ -482,7 +483,7 @@ MoveSelectionWidgetToTarget(animate); } -bool WindowGrid::Move(WindowSelector::Direction direction, bool animate) { +bool OverviewGrid::Move(OverviewSession::Direction direction, bool animate) { if (empty()) return true; @@ -500,12 +501,12 @@ // [right] key. if (!selection_widget_) { switch (direction) { - case WindowSelector::UP: - case WindowSelector::LEFT: + case OverviewSession::UP: + case OverviewSession::LEFT: selected_index_ = window_list_.size() - 1; break; - case WindowSelector::DOWN: - case WindowSelector::RIGHT: + case OverviewSession::DOWN: + case OverviewSession::RIGHT: selected_index_ = 0; break; } @@ -513,14 +514,14 @@ } while (!changed_selection_index) { switch (direction) { - case WindowSelector::UP: - case WindowSelector::LEFT: + case OverviewSession::UP: + case OverviewSession::LEFT: if (selected_index_ == 0) out_of_bounds = true; selected_index_--; break; - case WindowSelector::DOWN: - case WindowSelector::RIGHT: + case OverviewSession::DOWN: + case OverviewSession::RIGHT: if (selected_index_ >= window_list_.size() - 1) out_of_bounds = true; selected_index_++; @@ -541,14 +542,14 @@ return out_of_bounds; } -WindowSelectorItem* WindowGrid::SelectedWindow() const { +OverviewItem* OverviewGrid::SelectedWindow() const { if (!selection_widget_) return nullptr; CHECK(selected_index_ < window_list_.size()); return window_list_[selected_index_].get(); } -WindowSelectorItem* WindowGrid::GetWindowSelectorItemContaining( +OverviewItem* OverviewGrid::GetOverviewItemContaining( const aura::Window* window) const { for (const auto& window_item : window_list_) { if (window_item && window_item->Contains(window)) @@ -557,14 +558,16 @@ return nullptr; } -void WindowGrid::AddItem(aura::Window* window, bool reposition, bool animate) { - DCHECK(!GetWindowSelectorItemContaining(window)); +void OverviewGrid::AddItem(aura::Window* window, + bool reposition, + bool animate) { + DCHECK(!GetOverviewItemContaining(window)); window_observer_.Add(window); window_state_observer_.Add(wm::GetWindowState(window)); window_list_.insert( window_list_.begin(), - std::make_unique<WindowSelectorItem>(window, window_selector_, this)); + std::make_unique<OverviewItem>(window, overview_session_, this)); window_list_.front()->PrepareForOverview(); // The item is added after overview enter animation is complete, so // just call OnStartingAnimationComplete. @@ -574,17 +577,15 @@ PositionWindows(animate); } -void WindowGrid::RemoveItem(WindowSelectorItem* selector_item, - bool reposition) { - auto iter = - GetWindowSelectorItemIterContainingWindow(selector_item->GetWindow()); +void OverviewGrid::RemoveItem(OverviewItem* selector_item, bool reposition) { + auto iter = GetOverviewItemIterContainingWindow(selector_item->GetWindow()); if (iter != window_list_.end()) { window_observer_.Remove(selector_item->GetWindow()); window_state_observer_.Remove( wm::GetWindowState(selector_item->GetWindow())); - // Erase from the list first because deleting WindowSelectorItem can - // lead to iterating through the |window_list_|. - std::unique_ptr<WindowSelectorItem> tmp = std::move(*iter); + // Erase from the list first because deleting OverviewItem can lead to + // iterating through the |window_list_|. + std::unique_ptr<OverviewItem> tmp = std::move(*iter); window_list_.erase(iter); } @@ -592,20 +593,20 @@ PositionWindows(/*animate=*/true); } -void WindowGrid::SetBoundsAndUpdatePositions(const gfx::Rect& bounds) { +void OverviewGrid::SetBoundsAndUpdatePositions(const gfx::Rect& bounds) { SetBoundsAndUpdatePositionsIgnoringWindow(bounds, nullptr); } -void WindowGrid::SetBoundsAndUpdatePositionsIgnoringWindow( +void OverviewGrid::SetBoundsAndUpdatePositionsIgnoringWindow( const gfx::Rect& bounds, - WindowSelectorItem* ignored_item) { + OverviewItem* ignored_item) { bounds_ = bounds; if (shield_view_) shield_view_->SetGridBounds(bounds_); PositionWindows(/*animate=*/true, ignored_item); } -void WindowGrid::SetSelectionWidgetVisibility(bool visible) { +void OverviewGrid::SetSelectionWidgetVisibility(bool visible) { if (!selection_widget_) return; @@ -615,7 +616,7 @@ selection_widget_->Hide(); } -void WindowGrid::ShowNoRecentsWindowMessage(bool visible) { +void OverviewGrid::ShowNoRecentsWindowMessage(bool visible) { // Only show the warning on the grid associated with primary root. if (root_window_ != Shell::GetPrimaryRootWindow()) return; @@ -624,28 +625,28 @@ shield_view_->SetLabelVisibility(visible); } -void WindowGrid::UpdateCannotSnapWarningVisibility() { - for (auto& window_selector_item : window_list_) - window_selector_item->UpdateCannotSnapWarningVisibility(); +void OverviewGrid::UpdateCannotSnapWarningVisibility() { + for (auto& overview_mode_item : window_list_) + overview_mode_item->UpdateCannotSnapWarningVisibility(); } -void WindowGrid::OnSelectorItemDragStarted(WindowSelectorItem* item) { - for (auto& window_selector_item : window_list_) - window_selector_item->OnSelectorItemDragStarted(item); +void OverviewGrid::OnSelectorItemDragStarted(OverviewItem* item) { + for (auto& overview_mode_item : window_list_) + overview_mode_item->OnSelectorItemDragStarted(item); } -void WindowGrid::OnSelectorItemDragEnded() { - for (auto& window_selector_item : window_list_) - window_selector_item->OnSelectorItemDragEnded(); +void OverviewGrid::OnSelectorItemDragEnded() { + for (auto& overview_mode_item : window_list_) + overview_mode_item->OnSelectorItemDragEnded(); } -void WindowGrid::OnWindowDragStarted(aura::Window* dragged_window, - bool animate) { +void OverviewGrid::OnWindowDragStarted(aura::Window* dragged_window, + bool animate) { DCHECK_EQ(dragged_window->GetRootWindow(), root_window_); DCHECK(!drop_target_widget_); drop_target_widget_ = CreateDropTargetWidget(dragged_window, animate); - window_selector_->AddItem(drop_target_widget_->GetNativeWindow(), - /*reposition=*/true, animate); + overview_session_->AddItem(drop_target_widget_->GetNativeWindow(), + /*reposition=*/true, animate); // Stack the |dragged_window| at top during drag. dragged_window->parent()->StackChildAtTop(dragged_window); @@ -654,15 +655,15 @@ OnSelectorItemDragStarted(/*item=*/nullptr); } -void WindowGrid::OnWindowDragContinued(aura::Window* dragged_window, - const gfx::Point& location_in_screen, - IndicatorState indicator_state) { +void OverviewGrid::OnWindowDragContinued(aura::Window* dragged_window, + const gfx::Point& location_in_screen, + IndicatorState indicator_state) { DCHECK_EQ(dragged_window->GetRootWindow(), root_window_); // Adjust the window grid's bounds and the drop target's visibility // according to |indicator_state| if split view is not active at the moment. if (!Shell::Get()->split_view_controller()->IsSplitViewModeActive()) { - WindowSelectorItem* drop_target = GetDropTarget(); + OverviewItem* drop_target = GetDropTarget(); const bool should_visible = (indicator_state != IndicatorState::kPreviewAreaLeft && indicator_state != IndicatorState::kPreviewAreaRight); @@ -713,7 +714,7 @@ if (target_window && target_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey)) { size_t previous_selected_index = selected_index_; - selected_index_ = GetWindowSelectorItemIterContainingWindow(target_window) - + selected_index_ = GetOverviewItemIterContainingWindow(target_window) - window_list_.begin(); if (previous_selected_index == selected_index_ && selection_widget_) return; @@ -721,9 +722,9 @@ if (previous_selected_index != selected_index_) selection_widget_.reset(); - const WindowSelector::Direction direction = - (selected_index_ - previous_selected_index > 0) ? WindowSelector::RIGHT - : WindowSelector::LEFT; + const OverviewSession::Direction direction = + (selected_index_ - previous_selected_index > 0) ? OverviewSession::RIGHT + : OverviewSession::LEFT; MoveSelectionWidget(direction, /*recreate_selection_widget=*/true, /*out_of_bounds=*/false, @@ -737,9 +738,9 @@ } } -void WindowGrid::OnWindowDragEnded(aura::Window* dragged_window, - const gfx::Point& location_in_screen, - bool should_drop_window_into_overview) { +void OverviewGrid::OnWindowDragEnded(aura::Window* dragged_window, + const gfx::Point& location_in_screen, + bool should_drop_window_into_overview) { DCHECK_EQ(dragged_window->GetRootWindow(), root_window_); DCHECK(drop_target_widget_.get()); @@ -755,15 +756,15 @@ AddDraggedWindowIntoOverviewOnDragEnd(dragged_window); } - WindowSelectorItem* drop_target_item = - GetWindowSelectorItemContaining(drop_target_widget_->GetNativeWindow()); + OverviewItem* drop_target_item = + GetOverviewItemContaining(drop_target_widget_->GetNativeWindow()); // TODO(http://crbug.com/916856): Disable tab and app dragging that doesn't // happen in the primary display. // The |drop_target_widget_| may not in the same display as // |dragged_window|, which will cause |drop_target_item| to be null. if (drop_target_item) { - window_selector_->RemoveWindowSelectorItem(drop_target_item, - /*reposition=*/false); + overview_session_->RemoveOverviewItem(drop_target_item, + /*reposition=*/false); } drop_target_widget_.reset(); @@ -791,23 +792,23 @@ GetGridBoundsInScreenAfterDragging(dragged_window)); } -bool WindowGrid::IsDropTargetWindow(aura::Window* window) const { +bool OverviewGrid::IsDropTargetWindow(aura::Window* window) const { return drop_target_widget_ && drop_target_widget_->GetNativeWindow() == window; } -WindowSelectorItem* WindowGrid::GetDropTarget() { +OverviewItem* OverviewGrid::GetDropTarget() { if (!drop_target_widget_ || window_list_.empty()) return nullptr; - WindowSelectorItem* first_item = window_list_.front().get(); + OverviewItem* first_item = window_list_.front().get(); return IsDropTargetWindow(first_item->GetWindow()) ? first_item : nullptr; } -void WindowGrid::OnWindowDestroying(aura::Window* window) { +void OverviewGrid::OnWindowDestroying(aura::Window* window) { window_observer_.Remove(window); window_state_observer_.Remove(wm::GetWindowState(window)); - auto iter = GetWindowSelectorItemIterContainingWindow(window); + auto iter = GetOverviewItemIterContainingWindow(window); DCHECK(iter != window_list_.end()); // Windows that are animating to a close state already call PositionWindows, @@ -815,9 +816,9 @@ const bool needs_repositioning = !((*iter)->animating_to_close()); size_t removed_index = iter - window_list_.begin(); - // Erase from the list first because deleting WindowSelectorItem can - // lead to iterating through the |window_list_|. - std::unique_ptr<WindowSelectorItem> tmp = std::move(*iter); + // Erase from the list first because deleting OverviewItem can lead to + // iterating through the |window_list_|. + std::unique_ptr<OverviewItem> tmp = std::move(*iter); window_list_.erase(iter); tmp.reset(); @@ -825,8 +826,8 @@ selection_widget_.reset(); // If the grid is now empty, notify the window selector so that it erases us // from its grid list. - if (window_selector_) - window_selector_->OnGridEmpty(this); + if (overview_session_) + overview_session_->OnGridEmpty(this); return; } @@ -844,16 +845,16 @@ PositionWindows(true); } -void WindowGrid::OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds, - ui::PropertyChangeReason reason) { +void OverviewGrid::OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds, + ui::PropertyChangeReason reason) { // During preparation, window bounds can change. Ignore bounds // change notifications in this case; we'll reposition soon. if (!prepared_for_overview_) return; - auto iter = GetWindowSelectorItemIterContainingWindow(window); + auto iter = GetOverviewItemIterContainingWindow(window); DCHECK(iter != window_list_.end()); // Immediately finish any active bounds animation. @@ -863,8 +864,9 @@ PositionWindows(false); } -void WindowGrid::OnPostWindowStateTypeChange(wm::WindowState* window_state, - mojom::WindowStateType old_type) { +void OverviewGrid::OnPostWindowStateTypeChange( + wm::WindowState* window_state, + mojom::WindowStateType old_type) { // During preparation, window state can change, e.g. updating shelf // visibility may show the temporarily hidden (minimized) panels. if (!prepared_for_overview_) @@ -872,8 +874,8 @@ // When swiping away overview mode via shelf, windows will get minimized, but // we do not want to create minimized widgets in their place. - if (window_selector_->enter_exit_overview_type() == - WindowSelector::EnterExitOverviewType::kSwipeFromShelf) { + if (overview_session_->enter_exit_overview_type() == + OverviewSession::EnterExitOverviewType::kSwipeFromShelf) { return; } @@ -883,33 +885,32 @@ return; } - auto iter = - std::find_if(window_list_.begin(), window_list_.end(), - [window_state](std::unique_ptr<WindowSelectorItem>& item) { - return item->Contains(window_state->window()); - }); + auto iter = std::find_if(window_list_.begin(), window_list_.end(), + [window_state](std::unique_ptr<OverviewItem>& item) { + return item->Contains(window_state->window()); + }); if (iter != window_list_.end()) { (*iter)->OnMinimizedStateChanged(); PositionWindows(/*animate=*/false); } } -bool WindowGrid::IsNoItemsIndicatorLabelVisibleForTesting() { +bool OverviewGrid::IsNoItemsIndicatorLabelVisibleForTesting() { return shield_view_ && shield_view_->IsLabelVisible(); } -gfx::Rect WindowGrid::GetNoItemsIndicatorLabelBoundsForTesting() const { +gfx::Rect OverviewGrid::GetNoItemsIndicatorLabelBoundsForTesting() const { if (!shield_view_) return gfx::Rect(); return shield_view_->GetLabelBounds(); } -void WindowGrid::CalculateWindowListAnimationStates( - WindowSelectorItem* selected_item, - WindowSelector::OverviewTransition transition) { +void OverviewGrid::CalculateWindowListAnimationStates( + OverviewItem* selected_item, + OverviewSession::OverviewTransition transition) { // |selected_item| is nullptr during entering animation. - DCHECK(transition == WindowSelector::OverviewTransition::kExit || + DCHECK(transition == OverviewSession::OverviewTransition::kExit || selected_item == nullptr); bool has_covered_available_workspace = false; @@ -930,24 +931,23 @@ rend = top_windows.rend(); it != rend; ++it) { aura::Window* top_window = *it; - WindowSelectorItem* container_item = - GetWindowSelectorItemContaining(top_window); + OverviewItem* container_item = GetOverviewItemContaining(top_window); if (!container_item) continue; const bool is_selected_item = (selected_item == container_item); if (!has_checked_selected_item && is_selected_item) has_checked_selected_item = true; - CalculateWindowSelectorItemAnimationState( + CalculateOverviewItemAnimationState( container_item, &has_covered_available_workspace, /*selected=*/is_selected_item, transition); } } if (!has_checked_selected_item) { - CalculateWindowSelectorItemAnimationState(selected_item, - &has_covered_available_workspace, - /*selected=*/true, transition); + CalculateOverviewItemAnimationState(selected_item, + &has_covered_available_workspace, + /*selected=*/true, transition); } for (const auto& item : window_list_) { // Has checked the |selected_item|. @@ -956,19 +956,19 @@ // Has checked all always on top windows. if (item->GetWindow()->GetProperty(aura::client::kAlwaysOnTopKey)) continue; - CalculateWindowSelectorItemAnimationState(item.get(), - &has_covered_available_workspace, - /*selected=*/false, transition); + CalculateOverviewItemAnimationState(item.get(), + &has_covered_available_workspace, + /*selected=*/false, transition); } } -void WindowGrid::SetWindowListNotAnimatedWhenExiting() { +void OverviewGrid::SetWindowListNotAnimatedWhenExiting() { should_animate_when_exiting_ = false; for (const auto& item : window_list_) item->set_should_animate_when_exiting(false); } -void WindowGrid::StartNudge(WindowSelectorItem* item) { +void OverviewGrid::StartNudge(OverviewItem* item) { // When there is one window left, there is no need to nudge. if (window_list_.size() <= 1) { nudge_data_.clear(); @@ -997,11 +997,10 @@ // Get the index of |item|. size_t index = - std::find_if( - window_list_.begin(), window_list_.end(), - [&item](const std::unique_ptr<WindowSelectorItem>& item_ptr) { - return item == item_ptr.get(); - }) - + std::find_if(window_list_.begin(), window_list_.end(), + [&item](const std::unique_ptr<OverviewItem>& item_ptr) { + return item == item_ptr.get(); + }) - window_list_.begin(); DCHECK_LT(index, window_list_.size()); @@ -1107,11 +1106,11 @@ } } -void WindowGrid::UpdateNudge(WindowSelectorItem* item, double value) { +void OverviewGrid::UpdateNudge(OverviewItem* item, double value) { for (const auto& data : nudge_data_) { DCHECK_LT(data.index, window_list_.size()); - WindowSelectorItem* nudged_item = window_list_[data.index].get(); + OverviewItem* nudged_item = window_list_[data.index].get(); double nudge_param = value * value / 30.0; nudge_param = base::ClampToRange(nudge_param, 0.0, 1.0); gfx::Rect bounds = @@ -1120,20 +1119,20 @@ } } -void WindowGrid::EndNudge() { +void OverviewGrid::EndNudge() { nudge_data_.clear(); } -void WindowGrid::SlideWindowsIn() { +void OverviewGrid::SlideWindowsIn() { for (const auto& window_item : window_list_) window_item->SlideWindowIn(); } -void WindowGrid::UpdateYPositionAndOpacity( +void OverviewGrid::UpdateYPositionAndOpacity( int new_y, float opacity, const gfx::Rect& work_area, - WindowSelector::UpdateAnimationSettingsCallback callback) { + OverviewSession::UpdateAnimationSettingsCallback callback) { // Translate |shield_widget_| to |new_y|. The shield widget covers the shelf // so scale it down while moving it, so that it does not cover the launcher, // which is showing as this is disappearing. @@ -1158,19 +1157,19 @@ } } -aura::Window* WindowGrid::GetTargetWindowOnLocation( +aura::Window* OverviewGrid::GetTargetWindowOnLocation( const gfx::Point& location_in_screen) { // Find the window selector item that contains |location_in_screen|. - auto iter = std::find_if( - window_list_.begin(), window_list_.end(), - [&location_in_screen](std::unique_ptr<WindowSelectorItem>& item) { - return item->target_bounds().Contains(location_in_screen); - }); + auto iter = + std::find_if(window_list_.begin(), window_list_.end(), + [&location_in_screen](std::unique_ptr<OverviewItem>& item) { + return item->target_bounds().Contains(location_in_screen); + }); return (iter != window_list_.end()) ? (*iter)->GetWindow() : nullptr; } -void WindowGrid::InitShieldWidget() { +void OverviewGrid::InitShieldWidget() { // TODO(varkha): The code assumes that SHELF_BACKGROUND_MAXIMIZED is // synonymous with a black shelf background. Update this code if that // assumption is no longer valid. @@ -1206,7 +1205,7 @@ shield_widget_->SetOpacity(1.f); } -void WindowGrid::InitSelectionWidget(WindowSelector::Direction direction) { +void OverviewGrid::InitSelectionWidget(OverviewSession::Direction direction) { selection_widget_ = CreateBackgroundWidget( root_window_, ui::LAYER_TEXTURED, kWindowSelectionColor, 0, kWindowSelectionRadius, SK_ColorTRANSPARENT, 0.f, /*parent=*/nullptr, @@ -1227,10 +1226,10 @@ selector_shadow_->SetContentBounds(gfx::Rect(target_bounds.size())); } -void WindowGrid::MoveSelectionWidget(WindowSelector::Direction direction, - bool recreate_selection_widget, - bool out_of_bounds, - bool animate) { +void OverviewGrid::MoveSelectionWidget(OverviewSession::Direction direction, + bool recreate_selection_widget, + bool out_of_bounds, + bool animate) { // If the selection widget is already active, fade it out in the selection // direction. if (selection_widget_ && (recreate_selection_widget || out_of_bounds)) { @@ -1249,13 +1248,13 @@ animation_settings.SetTweenType(gfx::Tween::FAST_OUT_LINEAR_IN); // CleanupAnimationObserver will delete itself (and the widget) when the // motion animation is complete. - // Ownership over the observer is passed to the window_selector_->delegate() - // which has longer lifetime so that animations can continue even after the - // overview mode is shut down. + // Ownership over the observer is passed to the + // overview_session_->delegate() which has longer lifetime so that + // animations can continue even after the overview mode is shut down. std::unique_ptr<CleanupAnimationObserver> observer( new CleanupAnimationObserver(std::move(selection_widget_))); animation_settings.AddObserver(observer.get()); - window_selector_->delegate()->AddDelayedAnimationObserver( + overview_session_->delegate()->AddDelayedAnimationObserver( std::move(observer)); old_selection->SetOpacity(0.f); old_selection_window->SetBounds(old_selection_window->bounds() + @@ -1275,7 +1274,7 @@ MoveSelectionWidgetToTarget(animate); } -void WindowGrid::MoveSelectionWidgetToTarget(bool animate) { +void OverviewGrid::MoveSelectionWidgetToTarget(bool animate) { gfx::Rect bounds = SelectedWindow()->target_bounds(); ::wm::ConvertRectFromScreen(root_window_, &bounds); if (animate) { @@ -1315,8 +1314,8 @@ } } -std::vector<gfx::Rect> WindowGrid::GetWindowRects( - WindowSelectorItem* ignored_item) { +std::vector<gfx::Rect> OverviewGrid::GetWindowRects( + OverviewItem* ignored_item) { gfx::Rect total_bounds = bounds_; // Windows occupy vertically centered area with additional vertical insets. int horizontal_inset = @@ -1367,10 +1366,10 @@ // which is acceptable since there is an unused margin on the right. bool make_last_adjustment = false; while (true) { - gfx::Rect overview_bounds(total_bounds); - overview_bounds.set_width(right_bound - total_bounds.x()); + gfx::Rect overview_mode_bounds(total_bounds); + overview_mode_bounds.set_width(right_bound - total_bounds.x()); bool windows_fit = FitWindowRectsInBounds( - overview_bounds, std::min(kMaxHeight + 2 * kWindowMargin, height), + overview_mode_bounds, std::min(kMaxHeight + 2 * kWindowMargin, height), ignored_item, &rects, &max_bottom, &min_right, &max_right); if (height_fixed) { @@ -1414,10 +1413,10 @@ // Once the windows in |window_list_| no longer fit, the change to // |right_bound| was reverted. Perform one last pass to position the |rects|. if (make_last_adjustment) { - gfx::Rect overview_bounds(total_bounds); - overview_bounds.set_width(right_bound - total_bounds.x()); + gfx::Rect overview_mode_bounds(total_bounds); + overview_mode_bounds.set_width(right_bound - total_bounds.x()); FitWindowRectsInBounds( - overview_bounds, std::min(kMaxHeight + 2 * kWindowMargin, height), + overview_mode_bounds, std::min(kMaxHeight + 2 * kWindowMargin, height), ignored_item, &rects, &max_bottom, &min_right, &max_right); } @@ -1427,13 +1426,13 @@ return rects; } -bool WindowGrid::FitWindowRectsInBounds(const gfx::Rect& bounds, - int height, - WindowSelectorItem* ignored_item, - std::vector<gfx::Rect>* out_rects, - int* out_max_bottom, - int* out_min_right, - int* out_max_right) { +bool OverviewGrid::FitWindowRectsInBounds(const gfx::Rect& bounds, + int height, + OverviewItem* ignored_item, + std::vector<gfx::Rect>* out_rects, + int* out_max_bottom, + int* out_min_right, + int* out_max_right) { out_rects->resize(window_list_.size()); bool windows_fit = true; @@ -1467,13 +1466,13 @@ window->GetItemScale(item_size)) + 2 * kWindowMargin); switch (window->GetWindowDimensionsType()) { - case ScopedTransformOverviewWindow::GridWindowFillMode::kLetterBoxed: - width = ScopedTransformOverviewWindow::kExtremeWindowRatioThreshold * + case ScopedOverviewTransformWindow::GridWindowFillMode::kLetterBoxed: + width = ScopedOverviewTransformWindow::kExtremeWindowRatioThreshold * height; break; - case ScopedTransformOverviewWindow::GridWindowFillMode::kPillarBoxed: + case ScopedOverviewTransformWindow::GridWindowFillMode::kPillarBoxed: width = height / - ScopedTransformOverviewWindow::kExtremeWindowRatioThreshold; + ScopedOverviewTransformWindow::kExtremeWindowRatioThreshold; break; default: break; @@ -1522,41 +1521,41 @@ return windows_fit; } -void WindowGrid::CalculateWindowSelectorItemAnimationState( - WindowSelectorItem* selector_item, +void OverviewGrid::CalculateOverviewItemAnimationState( + OverviewItem* selector_item, bool* has_covered_available_workspace, bool selected, - WindowSelector::OverviewTransition transition) { + OverviewSession::OverviewTransition transition) { if (!selector_item) return; aura::Window* window = selector_item->GetWindow(); // |selector_item| should be contained in the |window_list_|. - DCHECK(GetWindowSelectorItemContaining(window)); + DCHECK(GetOverviewItemContaining(window)); bool can_cover_available_workspace = CanCoverAvailableWorkspace(window); const bool should_animate = selected || !(*has_covered_available_workspace); - if (transition == WindowSelector::OverviewTransition::kEnter) + if (transition == OverviewSession::OverviewTransition::kEnter) selector_item->set_should_animate_when_entering(should_animate); - if (transition == WindowSelector::OverviewTransition::kExit) + if (transition == OverviewSession::OverviewTransition::kExit) selector_item->set_should_animate_when_exiting(should_animate); if (!(*has_covered_available_workspace) && can_cover_available_workspace) *has_covered_available_workspace = true; } -std::vector<std::unique_ptr<WindowSelectorItem>>::iterator -WindowGrid::GetWindowSelectorItemIterContainingWindow(aura::Window* window) { +std::vector<std::unique_ptr<OverviewItem>>::iterator +OverviewGrid::GetOverviewItemIterContainingWindow(aura::Window* window) { return std::find_if(window_list_.begin(), window_list_.end(), - [window](std::unique_ptr<WindowSelectorItem>& item) { + [window](std::unique_ptr<OverviewItem>& item) { return item->GetWindow() == window; }); } -void WindowGrid::AddDraggedWindowIntoOverviewOnDragEnd( +void OverviewGrid::AddDraggedWindowIntoOverviewOnDragEnd( aura::Window* dragged_window) { - DCHECK(window_selector_); - if (window_selector_->IsWindowInOverview(dragged_window)) + DCHECK(overview_session_); + if (overview_session_->IsWindowInOverview(dragged_window)) return; // Update the dragged window's bounds before adding it to overview. The @@ -1575,15 +1574,15 @@ if (old_bounds != new_bounds) { // It's for smoother animation. gfx::Transform transform = - ScopedTransformOverviewWindow::GetTransformForRect(new_bounds, + ScopedOverviewTransformWindow::GetTransformForRect(new_bounds, old_bounds); dragged_window->SetTransform(transform); } dragged_window->ClearProperty(ash::kCanAttachToAnotherWindowKey); } - window_selector_->AddItem(dragged_window, /*reposition=*/false, - /*animate=*/false); + overview_session_->AddItem(dragged_window, /*reposition=*/false, + /*animate=*/false); } } // namespace ash
diff --git a/ash/wm/overview/window_grid.h b/ash/wm/overview/overview_grid.h similarity index 80% rename from ash/wm/overview/window_grid.h rename to ash/wm/overview/overview_grid.h index d529a39..3d167eb9 100644 --- a/ash/wm/overview/window_grid.h +++ b/ash/wm/overview/overview_grid.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_WM_OVERVIEW_WINDOW_GRID_H_ -#define ASH_WM_OVERVIEW_WINDOW_GRID_H_ +#ifndef ASH_WM_OVERVIEW_OVERVIEW_GRID_H_ +#define ASH_WM_OVERVIEW_OVERVIEW_GRID_H_ #include <stddef.h> @@ -11,7 +11,7 @@ #include <set> #include <vector> -#include "ash/wm/overview/window_selector.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/window_state_observer.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" @@ -29,7 +29,7 @@ namespace ash { -class WindowSelectorItem; +class OverviewItem; // Represents a grid of windows in the Overview Mode in a particular root // window, and manages a selection widget that can be moved with the arrow keys. @@ -49,14 +49,14 @@ // 0, 1, 2, 3, 4, 5, 6 // The selector is switched to the next window grid (if available) or wrapped if // it reaches the end of its movement sequence. -class ASH_EXPORT WindowGrid : public aura::WindowObserver, - public wm::WindowStateObserver { +class ASH_EXPORT OverviewGrid : public aura::WindowObserver, + public wm::WindowStateObserver { public: - WindowGrid(aura::Window* root_window, - const std::vector<aura::Window*>& window_list, - WindowSelector* window_selector, - const gfx::Rect& bounds_in_screen); - ~WindowGrid() override; + OverviewGrid(aura::Window* root_window, + const std::vector<aura::Window*>& window_list, + OverviewSession* overview_session, + const gfx::Rect& bounds_in_screen); + ~OverviewGrid() override; // Returns the shield color that is used to darken the background of the grid. static SkColor GetShieldColor(); @@ -74,23 +74,22 @@ // |window_list_|, that item is not positioned. This is for split screen. // |transition| specifies the overview state when this function is called. void PositionWindows(bool animate, - WindowSelectorItem* ignored_item = nullptr, - WindowSelector::OverviewTransition transition = - WindowSelector::OverviewTransition::kInOverview); + OverviewItem* ignored_item = nullptr, + OverviewSession::OverviewTransition transition = + OverviewSession::OverviewTransition::kInOverview); // Updates |selected_index_| according to the specified |direction| and calls // MoveSelectionWidget(). Returns |true| if the new selection index is out of // this window grid bounds. - bool Move(WindowSelector::Direction direction, bool animate); + bool Move(OverviewSession::Direction direction, bool animate); // Returns the target selected window, or NULL if there is none selected. - WindowSelectorItem* SelectedWindow() const; + OverviewItem* SelectedWindow() const; - // Returns the WindowSelectorItem if a window is contained in any of the - // WindowSelectorItems this grid owns. Returns nullptr if no such a - // WindowSelectorItem exist. - WindowSelectorItem* GetWindowSelectorItemContaining( - const aura::Window* window) const; + // Returns the OverviewItem if a window is contained in any of the + // OverviewItems this grid owns. Returns nullptr if no such a OverviewItem + // exist. + OverviewItem* GetOverviewItemContaining(const aura::Window* window) const; // Adds |window| to the grid. Intended to be used by split view. |window| // cannot already be on the grid. If |reposition| is true, reposition all @@ -100,13 +99,12 @@ // Removes |selector_item| from the grid. If |reprosition| is ture, reposition // all window items in the grid after removing the item. - void RemoveItem(WindowSelectorItem* selector_item, bool reposition); + void RemoveItem(OverviewItem* selector_item, bool reposition); // Sets bounds for the window grid and positions all windows in the grid. void SetBoundsAndUpdatePositions(const gfx::Rect& bounds_in_screen); - void SetBoundsAndUpdatePositionsIgnoringWindow( - const gfx::Rect& bounds, - WindowSelectorItem* ignored_item); + void SetBoundsAndUpdatePositionsIgnoringWindow(const gfx::Rect& bounds, + OverviewItem* ignored_item); // Shows or hides the selection widget. To be called by a window selector item // when it is dragged. @@ -116,9 +114,9 @@ void UpdateCannotSnapWarningVisibility(); - // Called when any WindowSelectorItem on any WindowGrid has started/ended - // being dragged. - void OnSelectorItemDragStarted(WindowSelectorItem* item); + // Called when any OverviewItem on any OverviewGrid has started/ended being + // dragged. + void OnSelectorItemDragStarted(OverviewItem* item); void OnSelectorItemDragEnded(); // Called when a window (either it's browser window or an app window) @@ -136,11 +134,11 @@ // Returns the selector item that accociates with |drop_target_widget_|. // Returns nullptr if overview does not have the drop target. - WindowSelectorItem* GetDropTarget(); + OverviewItem* GetDropTarget(); // aura::WindowObserver: void OnWindowDestroying(aura::Window* window) override; - // TODO(flackr): Handle window bounds changed in WindowSelectorItem. + // TODO(flackr): Handle window bounds changed in OverviewItem. void OnWindowBoundsChanged(aura::Window* window, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds, @@ -160,13 +158,13 @@ // |selector_item| is not nullptr if |selector_item| is the selected item when // exiting overview mode. void CalculateWindowListAnimationStates( - WindowSelectorItem* selected_item, - WindowSelector::OverviewTransition transition); + OverviewItem* selected_item, + OverviewSession::OverviewTransition transition); // Do not animate the entire window list during exiting the overview. It's // used when splitview and overview mode are both active, selecting a window // will put the window in splitview mode and also end the overview mode. In - // this case the windows in WindowGrid should not animate when exiting the + // this case the windows in OverviewGrid should not animate when exiting the // overivew mode. These windows will use ZERO tween so that transforms will // reset at the end of animation. void SetWindowListNotAnimatedWhenExiting(); @@ -174,11 +172,11 @@ // Starts a nudge, with |item| being the item that may be deleted. This method // calculates which items in |window_list_| are to be updated, and their // destination bounds and fills |nudge_data_| accordingly. - void StartNudge(WindowSelectorItem* item); + void StartNudge(OverviewItem* item); // Moves items in |nudge_data_| towards their destination bounds based on // |value|, which must be between 0.0 and 1.0. - void UpdateNudge(WindowSelectorItem* item, double value); + void UpdateNudge(OverviewItem* item, double value); // Clears |nudge_data_|. void EndNudge(); @@ -196,7 +194,7 @@ int new_y, float opacity, const gfx::Rect& work_area, - WindowSelector::UpdateAnimationSettingsCallback callback); + OverviewSession::UpdateAnimationSettingsCallback callback); // Returns the window of the window selector item that contains // |location_in_screen|. @@ -214,11 +212,11 @@ // Returns the root window in which the grid displays the windows. const aura::Window* root_window() const { return root_window_; } - const std::vector<std::unique_ptr<WindowSelectorItem>>& window_list() const { + const std::vector<std::unique_ptr<OverviewItem>>& window_list() const { return window_list_; } - WindowSelector* window_selector() { return window_selector_; } + OverviewSession* overview_session() { return overview_session_; } const gfx::Rect bounds() const { return bounds_; } @@ -235,7 +233,7 @@ private: class ShieldView; class TargetWindowObserver; - friend class WindowSelectorTest; + friend class OverviewSessionTest; // Struct which holds data required to perform nudges. struct NudgeData { @@ -248,10 +246,10 @@ void InitShieldWidget(); // Internal function to initialize the selection widget. - void InitSelectionWidget(WindowSelector::Direction direction); + void InitSelectionWidget(OverviewSession::Direction direction); // Moves the selection widget to the specified |direction|. - void MoveSelectionWidget(WindowSelector::Direction direction, + void MoveSelectionWidget(OverviewSession::Direction direction, bool recreate_selection_widget, bool out_of_bounds, bool animate); @@ -269,7 +267,7 @@ // Overall this achieves the goals of maximum size for previews (or maximum // row height which is equivalent assuming fixed height), balanced rows and // minimal wasted space. - std::vector<gfx::Rect> GetWindowRects(WindowSelectorItem* ignored_item); + std::vector<gfx::Rect> GetWindowRects(OverviewItem* ignored_item); // Attempts to fit all |out_rects| inside |bounds|. The method ensures that // the |out_rects| vector has appropriate size and populates it with the @@ -283,7 +281,7 @@ // true on success and false otherwise. bool FitWindowRectsInBounds(const gfx::Rect& bounds, int height, - WindowSelectorItem* ignored_item, + OverviewItem* ignored_item, std::vector<gfx::Rect>* out_rects, int* out_max_bottom, int* out_min_right, @@ -292,15 +290,15 @@ // Calculates |selector_item|'s |should_animate_when_entering_|, // |should_animate_when_exiting_|. |selected| is true if if |selector_item| is // the selected item when exiting overview mode. - void CalculateWindowSelectorItemAnimationState( - WindowSelectorItem* selector_item, + void CalculateOverviewItemAnimationState( + OverviewItem* selector_item, bool* has_fullscreen_coverred, bool selected, - WindowSelector::OverviewTransition transition); + OverviewSession::OverviewTransition transition); // Returns the window selector item iterator that contains |window|. - std::vector<std::unique_ptr<WindowSelectorItem>>::iterator - GetWindowSelectorItemIterContainingWindow(aura::Window* window); + std::vector<std::unique_ptr<OverviewItem>>::iterator + GetOverviewItemIterContainingWindow(aura::Window* window); // Adds the |dragged_window| into overview on drag ended. Might need to update // the window's bounds if it has been resized. @@ -310,13 +308,13 @@ aura::Window* root_window_; // Pointer to the window selector that spawned this grid. - WindowSelector* window_selector_; + OverviewSession* overview_session_; // Vector containing all the windows in this grid. - std::vector<std::unique_ptr<WindowSelectorItem>> window_list_; + std::vector<std::unique_ptr<OverviewItem>> window_list_; - ScopedObserver<aura::Window, WindowGrid> window_observer_; - ScopedObserver<wm::WindowState, WindowGrid> window_state_observer_; + ScopedObserver<aura::Window, OverviewGrid> window_observer_; + ScopedObserver<wm::WindowState, OverviewGrid> window_state_observer_; // Widget that darkens the screen background. std::unique_ptr<views::Widget> shield_widget_; @@ -352,23 +350,23 @@ // True only after all windows have been prepared for overview. bool prepared_for_overview_ = false; - // True if the window grid should animate when exiting overview mode. Note + // True if the overview grid should animate when exiting overview mode. Note // even if it's true, it doesn't mean all window items in the grid should // animate when exiting overview, instead each window item's animation status // is controlled by its own |should_animate_when_exiting_|. But if it's false, // all window items in the grid don't have animation. bool should_animate_when_exiting_ = true; - // This WindowGrid's total bounds in screen coordinates. + // This OverviewGrid's total bounds in screen coordinates. gfx::Rect bounds_; // Collection of the items which should be nudged. This should only be // non-empty if a nudge is in progress. std::vector<NudgeData> nudge_data_; - DISALLOW_COPY_AND_ASSIGN(WindowGrid); + DISALLOW_COPY_AND_ASSIGN(OverviewGrid); }; } // namespace ash -#endif // ASH_WM_OVERVIEW_WINDOW_GRID_H_ +#endif // ASH_WM_OVERVIEW_OVERVIEW_GRID_H_
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/overview_item.cc similarity index 77% rename from ash/wm/overview/window_selector_item.cc rename to ash/wm/overview/overview_item.cc index def8ad01e..425a0f79 100644 --- a/ash/wm/overview/window_selector_item.cc +++ b/ash/wm/overview/overview_item.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/overview/window_selector_item.h" +#include "ash/wm/overview/overview_item.h" #include <algorithm> #include <vector> @@ -13,13 +13,13 @@ #include "ash/wm/overview/caption_container_view.h" #include "ash/wm/overview/overview_animation_type.h" #include "ash/wm/overview/overview_constants.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_grid.h" #include "ash/wm/overview/overview_utils.h" #include "ash/wm/overview/overview_window_drag_controller.h" #include "ash/wm/overview/scoped_overview_animation_settings.h" -#include "ash/wm/overview/scoped_transform_overview_window.h" +#include "ash/wm/overview/scoped_overview_transform_window.h" #include "ash/wm/overview/start_animation_observer.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector_controller.h" #include "ash/wm/splitview/split_view_utils.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" @@ -76,28 +76,28 @@ } // namespace -WindowSelectorItem::WindowSelectorItem(aura::Window* window, - WindowSelector* window_selector, - WindowGrid* window_grid) +OverviewItem::OverviewItem(aura::Window* window, + OverviewSession* overview_session, + OverviewGrid* overview_grid) : root_window_(window->GetRootWindow()), transform_window_(this, window), - window_selector_(window_selector), - window_grid_(window_grid) { + overview_session_(overview_session), + overview_grid_(overview_grid) { CreateWindowLabel(); GetWindow()->AddObserver(this); GetWindow()->SetProperty(ash::kIsShowingInOverviewKey, true); } -WindowSelectorItem::~WindowSelectorItem() { +OverviewItem::~OverviewItem() { GetWindow()->RemoveObserver(this); GetWindow()->ClearProperty(ash::kIsShowingInOverviewKey); } -aura::Window* WindowSelectorItem::GetWindow() { +aura::Window* OverviewItem::GetWindow() { return transform_window_.window(); } -aura::Window* WindowSelectorItem::GetWindowForStacking() { +aura::Window* OverviewItem::GetWindowForStacking() { // If the window is minimized, stack |widget_window| above the minimized // window, otherwise the minimized window will cover |widget_window|. The // minimized is created with the same parent as the original window, just @@ -107,23 +107,23 @@ : GetWindow(); } -bool WindowSelectorItem::Contains(const aura::Window* target) const { +bool OverviewItem::Contains(const aura::Window* target) const { return transform_window_.Contains(target); } -void WindowSelectorItem::RestoreWindow(bool reset_transform) { +void OverviewItem::RestoreWindow(bool reset_transform) { caption_container_view_->ResetListener(); transform_window_.RestoreWindow( reset_transform, - window_selector_->enter_exit_overview_type() == - WindowSelector::EnterExitOverviewType::kWindowsMinimized); + overview_session_->enter_exit_overview_type() == + OverviewSession::EnterExitOverviewType::kWindowsMinimized); } -void WindowSelectorItem::EnsureVisible() { +void OverviewItem::EnsureVisible() { transform_window_.EnsureVisible(); } -void WindowSelectorItem::Shutdown() { +void OverviewItem::Shutdown() { if (transform_window_.GetTopInset()) { // Activating a window (even when it is the window that was active before // overview) results in stacking it at the top. Maintain the label window @@ -144,23 +144,22 @@ // On swiping from the shelf, the caller handles the animation via calls to // UpdateYAndOpacity, so do not additional fade out or slide animation to the // window. - if (window_selector_->enter_exit_overview_type() == - WindowSelector::EnterExitOverviewType::kSwipeFromShelf) { + if (overview_session_->enter_exit_overview_type() == + OverviewSession::EnterExitOverviewType::kSwipeFromShelf) { return; } - // Close the item widget without animation to reduce the load during exit - // animation. - ScopedAnimationDisabler(item_widget_->GetNativeWindow()); + // TODO(sammiequon|xdai): Close the item widget without animation to reduce + // the load during exit animation. item_widget_.reset(); } -void WindowSelectorItem::PrepareForOverview() { +void OverviewItem::PrepareForOverview() { transform_window_.PrepareForOverview(); RestackItemWidget(); } -void WindowSelectorItem::SlideWindowIn() { +void OverviewItem::SlideWindowIn() { // |transform_window_|'s |minimized_widget| is non null because this only gets // called if we see the home launcher on enter (all windows are minimized). DCHECK(transform_window_.minimized_widget()); @@ -170,10 +169,10 @@ /*slide=*/true); } -void WindowSelectorItem::UpdateYPositionAndOpacity( +void OverviewItem::UpdateYPositionAndOpacity( int new_grid_y, float opacity, - WindowSelector::UpdateAnimationSettingsCallback callback) { + OverviewSession::UpdateAnimationSettingsCallback callback) { // Animate the window selector widget and the window itself. // TODO(sammiequon): Investigate if we can combine with // FadeInWidgetAndMaybeSlideOnEnter. Also when animating we should remove @@ -214,27 +213,27 @@ } } -void WindowSelectorItem::UpdateItemContentViewForMinimizedWindow() { +void OverviewItem::UpdateItemContentViewForMinimizedWindow() { transform_window_.UpdateMinimizedWidget(); } -float WindowSelectorItem::GetItemScale(const gfx::Size& size) { +float OverviewItem::GetItemScale(const gfx::Size& size) { gfx::Size inset_size(size.width(), size.height() - 2 * kWindowMargin); - return ScopedTransformOverviewWindow::GetItemScale( + return ScopedOverviewTransformWindow::GetItemScale( GetTargetBoundsInScreen().size(), inset_size, transform_window_.GetTopInset(), kHeaderHeightDp); } -gfx::Rect WindowSelectorItem::GetTargetBoundsInScreen() const { +gfx::Rect OverviewItem::GetTargetBoundsInScreen() const { return ::ash::GetTargetBoundsInScreen(transform_window_.GetOverviewWindow()); } -gfx::Rect WindowSelectorItem::GetTransformedBounds() const { +gfx::Rect OverviewItem::GetTransformedBounds() const { return transform_window_.GetTransformedBounds(); } -void WindowSelectorItem::SetBounds(const gfx::Rect& target_bounds, - OverviewAnimationType animation_type) { +void OverviewItem::SetBounds(const gfx::Rect& target_bounds, + OverviewAnimationType animation_type) { if (in_bounds_update_) return; @@ -273,7 +272,7 @@ // and UpdateHeaderLayout. Do not apply the shadow for drop target. if (new_animation_type == OVERVIEW_ANIMATION_NONE) { SetShadowBounds( - window_grid_->IsDropTargetWindow(GetWindow()) + overview_grid_->IsDropTargetWindow(GetWindow()) ? base::nullopt : base::make_optional(transform_window_.GetTransformedBounds())); } @@ -281,16 +280,16 @@ UpdateBackdropBounds(); } -void WindowSelectorItem::SendAccessibleSelectionEvent() { +void OverviewItem::SendAccessibleSelectionEvent() { caption_container_view_->GetListenerButton()->NotifyAccessibilityEvent( ax::mojom::Event::kSelection, true); } -void WindowSelectorItem::AnimateAndCloseWindow(bool up) { +void OverviewItem::AnimateAndCloseWindow(bool up) { base::RecordAction(base::UserMetricsAction("WindowSelector_SwipeToClose")); animating_to_close_ = true; - window_selector_->PositionWindows(/*animate=*/true); + overview_session_->PositionWindows(/*animate=*/true); caption_container_view_->ResetListener(); int translation_y = kSwipeToCloseCloseTranslationDp * (up ? -1 : 1); @@ -313,7 +312,7 @@ animate_window(GetWindowForStacking(), transform, true); } -void WindowSelectorItem::CloseWindow() { +void OverviewItem::CloseWindow() { gfx::Rect inset_bounds(target_bounds_); inset_bounds.Inset(target_bounds_.width() * kPreCloseScale, target_bounds_.height() * kPreCloseScale); @@ -328,15 +327,15 @@ transform_window_.Close(); } -void WindowSelectorItem::OnMinimizedStateChanged() { +void OverviewItem::OnMinimizedStateChanged() { transform_window_.UpdateMirrorWindowForMinimizedState(); } -void WindowSelectorItem::UpdateCannotSnapWarningVisibility() { +void OverviewItem::UpdateCannotSnapWarningVisibility() { // Windows which can snap will never show this warning. Or if the window is // the drop target window, also do not show this warning. if (CanSnapInSplitview(GetWindow()) || - window_grid_->IsDropTargetWindow(GetWindow())) { + overview_grid_->IsDropTargetWindow(GetWindow())) { caption_container_view_->SetCannotSnapLabelVisibility(false); return; } @@ -348,28 +347,28 @@ caption_container_view_->SetCannotSnapLabelVisibility(visible); } -void WindowSelectorItem::OnSelectorItemDragStarted(WindowSelectorItem* item) { +void OverviewItem::OnSelectorItemDragStarted(OverviewItem* item) { caption_container_view_->SetHeaderVisibility( item == this ? CaptionContainerView::HeaderVisibility::kInvisible : CaptionContainerView::HeaderVisibility::kCloseButtonInvisibleOnly); } -void WindowSelectorItem::OnSelectorItemDragEnded() { +void OverviewItem::OnSelectorItemDragEnded() { caption_container_view_->SetHeaderVisibility( CaptionContainerView::HeaderVisibility::kVisible); } -ScopedTransformOverviewWindow::GridWindowFillMode -WindowSelectorItem::GetWindowDimensionsType() const { +ScopedOverviewTransformWindow::GridWindowFillMode +OverviewItem::GetWindowDimensionsType() const { return transform_window_.type(); } -void WindowSelectorItem::UpdateWindowDimensionsType() { +void OverviewItem::UpdateWindowDimensionsType() { // TODO(oshima|sammiequan|xdai): Use EnableBackdropIfNeeded. transform_window_.UpdateWindowDimensionsType(); if (GetWindowDimensionsType() == - ScopedTransformOverviewWindow::GridWindowFillMode::kNormal) { + ScopedOverviewTransformWindow::GridWindowFillMode::kNormal) { // Delete the backdrop widget, if it exists for normal windows. if (backdrop_widget_) backdrop_widget_.reset(); @@ -382,9 +381,9 @@ } } -void WindowSelectorItem::EnableBackdropIfNeeded() { +void OverviewItem::EnableBackdropIfNeeded() { if (GetWindowDimensionsType() == - ScopedTransformOverviewWindow::GridWindowFillMode::kNormal) { + ScopedOverviewTransformWindow::GridWindowFillMode::kNormal) { DisableBackdrop(); return; } @@ -395,12 +394,12 @@ UpdateBackdropBounds(); } -void WindowSelectorItem::DisableBackdrop() { +void OverviewItem::DisableBackdrop() { if (backdrop_widget_) backdrop_widget_->Hide(); } -void WindowSelectorItem::UpdateBackdropBounds() { +void OverviewItem::UpdateBackdropBounds() { if (!backdrop_widget_) return; @@ -410,7 +409,7 @@ backdrop_widget_->Show(); } -gfx::Rect WindowSelectorItem::GetBoundsOfSelectedItem() { +gfx::Rect OverviewItem::GetBoundsOfSelectedItem() { gfx::Rect original_bounds = target_bounds(); ScaleUpSelectedItem(OVERVIEW_ANIMATION_NONE); gfx::Rect selected_bounds = transform_window_.GetTransformedBounds(); @@ -418,83 +417,79 @@ return selected_bounds; } -void WindowSelectorItem::ScaleUpSelectedItem( - OverviewAnimationType animation_type) { +void OverviewItem::ScaleUpSelectedItem(OverviewAnimationType animation_type) { gfx::Rect scaled_bounds(target_bounds()); scaled_bounds.Inset(-scaled_bounds.width() * kDragWindowScale, -scaled_bounds.height() * kDragWindowScale); SetBounds(scaled_bounds, animation_type); } -void WindowSelectorItem::RestackItemWidget() { +void OverviewItem::RestackItemWidget() { aura::Window* widget_window = item_widget_->GetNativeWindow(); widget_window->parent()->StackChildAbove(widget_window, GetWindowForStacking()); } -void WindowSelectorItem::HandlePressEvent( - const gfx::Point& location_in_screen) { - // We allow switching finger while dragging, but do not allow dragging two or more items. - if (window_selector_->window_drag_controller() && - window_selector_->window_drag_controller()->item()) { +void OverviewItem::HandlePressEvent(const gfx::Point& location_in_screen) { + // We allow switching finger while dragging, but do not allow dragging two or + // more items. + if (overview_session_->window_drag_controller() && + overview_session_->window_drag_controller()->item()) { return; } StartDrag(); - window_selector_->InitiateDrag(this, location_in_screen); + overview_session_->InitiateDrag(this, location_in_screen); } -void WindowSelectorItem::HandleReleaseEvent( - const gfx::Point& location_in_screen) { +void OverviewItem::HandleReleaseEvent(const gfx::Point& location_in_screen) { if (!IsDragItem()) return; - window_grid_->SetSelectionWidgetVisibility(true); - window_selector_->CompleteDrag(this, location_in_screen); + overview_grid_->SetSelectionWidgetVisibility(true); + overview_session_->CompleteDrag(this, location_in_screen); } -void WindowSelectorItem::HandleDragEvent(const gfx::Point& location_in_screen) { +void OverviewItem::HandleDragEvent(const gfx::Point& location_in_screen) { if (!IsDragItem()) return; - window_selector_->Drag(this, location_in_screen); + overview_session_->Drag(this, location_in_screen); } -void WindowSelectorItem::HandleLongPressEvent( - const gfx::Point& location_in_screen) { +void OverviewItem::HandleLongPressEvent(const gfx::Point& location_in_screen) { if (!ShouldAllowSplitView()) return; - window_selector_->StartSplitViewDragMode(location_in_screen); + overview_session_->StartSplitViewDragMode(location_in_screen); } -void WindowSelectorItem::HandleFlingStartEvent( - const gfx::Point& location_in_screen, - float velocity_x, - float velocity_y) { - window_selector_->Fling(this, location_in_screen, velocity_x, velocity_y); +void OverviewItem::HandleFlingStartEvent(const gfx::Point& location_in_screen, + float velocity_x, + float velocity_y) { + overview_session_->Fling(this, location_in_screen, velocity_x, velocity_y); } -void WindowSelectorItem::ActivateDraggedWindow() { +void OverviewItem::ActivateDraggedWindow() { if (!IsDragItem()) return; - window_selector_->ActivateDraggedWindow(); + overview_session_->ActivateDraggedWindow(); } -void WindowSelectorItem::ResetDraggedWindowGesture() { +void OverviewItem::ResetDraggedWindowGesture() { if (!IsDragItem()) return; OnSelectorItemDragEnded(); - window_selector_->ResetDraggedWindowGesture(); + overview_session_->ResetDraggedWindowGesture(); } -bool WindowSelectorItem::IsDragItem() { - return window_selector_->window_drag_controller() && - window_selector_->window_drag_controller()->item() == this; +bool OverviewItem::IsDragItem() { + return overview_session_->window_drag_controller() && + overview_session_->window_drag_controller()->item() == this; } -void WindowSelectorItem::OnDragAnimationCompleted() { +void OverviewItem::OnDragAnimationCompleted() { // This is function is called whenever the grid repositions its windows, but // we only need to restack the windows if an item was being dragged around // and then released. @@ -520,8 +515,8 @@ // Then find the window which was stacked right above this selector item's // window before dragging and stack this selector item's window below it. - const std::vector<std::unique_ptr<WindowSelectorItem>>& selector_items = - window_grid_->window_list(); + const std::vector<std::unique_ptr<OverviewItem>>& selector_items = + overview_grid_->window_list(); aura::Window* stacking_target = nullptr; for (size_t index = 0; index < selector_items.size(); index++) { if (index > 0) { @@ -539,8 +534,7 @@ } } -void WindowSelectorItem::SetShadowBounds( - base::Optional<gfx::Rect> bounds_in_screen) { +void OverviewItem::SetShadowBounds(base::Optional<gfx::Rect> bounds_in_screen) { // Shadow is normally turned off during animations and reapplied when they // are finished. On destruction, |shadow_| is cleaned up before // |transform_window_|, which may call this function, so early exit if @@ -556,18 +550,18 @@ shadow_->layer()->SetVisible(true); gfx::Rect bounds_in_item = gfx::Rect(item_widget_->GetNativeWindow()->GetTargetBounds().size()); - bounds_in_item.Inset(kWindowSelectorMargin, kWindowSelectorMargin); + bounds_in_item.Inset(kOverviewMargin, kOverviewMargin); bounds_in_item.Inset(0, kHeaderHeightDp, 0, 0); bounds_in_item.ClampToCenteredSize(bounds_in_screen.value().size()); shadow_->SetContentBounds(bounds_in_item); } -void WindowSelectorItem::UpdateMaskAndShadow(bool show) { +void OverviewItem::UpdateMaskAndShadow(bool show) { transform_window_.UpdateMask(show); // Do not apply the shadow for the drop target in overview. - if (!show || window_grid_->IsDropTargetWindow(GetWindow())) { + if (!show || overview_grid_->IsDropTargetWindow(GetWindow())) { SetShadowBounds(base::nullopt); DisableBackdrop(); return; @@ -577,7 +571,7 @@ EnableBackdropIfNeeded(); } -void WindowSelectorItem::OnStartingAnimationComplete() { +void OverviewItem::OnStartingAnimationComplete() { DCHECK(item_widget_.get()); FadeInWidgetAndMaybeSlideOnEnter( item_widget_.get(), OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN, @@ -585,28 +579,28 @@ EnableBackdropIfNeeded(); } -void WindowSelectorItem::SetOpacity(float opacity) { +void OverviewItem::SetOpacity(float opacity) { item_widget_->SetOpacity(opacity); transform_window_.SetOpacity(opacity); } -float WindowSelectorItem::GetOpacity() { +float OverviewItem::GetOpacity() { return item_widget_->GetNativeWindow()->layer()->opacity(); } -OverviewAnimationType WindowSelectorItem::GetExitOverviewAnimationType() { +OverviewAnimationType OverviewItem::GetExitOverviewAnimationType() { return should_animate_when_exiting_ ? OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS_ON_EXIT : OVERVIEW_ANIMATION_NONE; } -OverviewAnimationType WindowSelectorItem::GetExitTransformAnimationType() { +OverviewAnimationType OverviewItem::GetExitTransformAnimationType() { return should_animate_when_exiting_ ? OVERVIEW_ANIMATION_RESTORE_WINDOW : OVERVIEW_ANIMATION_RESTORE_WINDOW_ZERO; } -void WindowSelectorItem::ButtonPressed(views::Button* sender, - const ui::Event& event) { +void OverviewItem::ButtonPressed(views::Button* sender, + const ui::Event& event) { if (IsSlidingOutOverviewFromShelf()) return; @@ -627,50 +621,49 @@ // For other cases, the event is handled in OverviewWindowDragController. if (!ShouldAllowSplitView()) - window_selector_->SelectWindow(this); + overview_session_->SelectWindow(this); } -void WindowSelectorItem::OnWindowBoundsChanged( - aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds, - ui::PropertyChangeReason reason) { +void OverviewItem::OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds, + ui::PropertyChangeReason reason) { if (reason == ui::PropertyChangeReason::NOT_FROM_ANIMATION) transform_window_.ResizeMinimizedWidgetIfNeeded(); } -void WindowSelectorItem::OnWindowDestroying(aura::Window* window) { +void OverviewItem::OnWindowDestroying(aura::Window* window) { window->RemoveObserver(this); transform_window_.OnWindowDestroyed(); } -void WindowSelectorItem::OnWindowTitleChanged(aura::Window* window) { +void OverviewItem::OnWindowTitleChanged(aura::Window* window) { // TODO(flackr): Maybe add the new title to a vector of titles so that we can // filter any of the titles the window had while in the overview session. caption_container_view_->SetTitle(window->GetTitle()); } -void WindowSelectorItem::OnImplicitAnimationsCompleted() { +void OverviewItem::OnImplicitAnimationsCompleted() { transform_window_.Close(); } -float WindowSelectorItem::GetCloseButtonVisibilityForTesting() const { +float OverviewItem::GetCloseButtonVisibilityForTesting() const { return caption_container_view_->GetCloseButton()->layer()->opacity(); } -float WindowSelectorItem::GetTitlebarOpacityForTesting() const { +float OverviewItem::GetTitlebarOpacityForTesting() const { return caption_container_view_->header_view()->layer()->opacity(); } -gfx::Rect WindowSelectorItem::GetShadowBoundsForTesting() { +gfx::Rect OverviewItem::GetShadowBoundsForTesting() { if (!shadow_ || !shadow_->layer()->visible()) return gfx::Rect(); return shadow_->content_bounds(); } -void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds, - OverviewAnimationType animation_type) { +void OverviewItem::SetItemBounds(const gfx::Rect& target_bounds, + OverviewAnimationType animation_type) { aura::Window* window = GetWindow(); DCHECK(root_window_ == window->GetRootWindow()); gfx::Rect screen_rect = GetTargetBoundsInScreen(); @@ -685,20 +678,20 @@ transform_window_.ShrinkRectToFitPreservingAspectRatio( screen_rect, target_bounds, top_view_inset, kHeaderHeightDp); // Do not set transform for drop target, set bounds instead. - if (window_grid_->IsDropTargetWindow(window)) { + if (overview_grid_->IsDropTargetWindow(window)) { window->layer()->SetBounds(selector_item_bounds); transform_window_.GetOverviewWindow()->SetTransform(gfx::Transform()); return; } - gfx::Transform transform = ScopedTransformOverviewWindow::GetTransformForRect( + gfx::Transform transform = ScopedOverviewTransformWindow::GetTransformForRect( screen_rect, selector_item_bounds); - ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings; + ScopedOverviewTransformWindow::ScopedAnimationSettings animation_settings; transform_window_.BeginScopedAnimation(animation_type, &animation_settings); SetTransform(transform_window_.GetOverviewWindow(), transform); } -void WindowSelectorItem::CreateWindowLabel() { +void OverviewItem::CreateWindowLabel() { views::Widget::InitParams params_label; params_label.type = views::Widget::InitParams::TYPE_POPUP; params_label.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; @@ -731,10 +724,9 @@ item_widget_->GetLayer()->SetMasksToBounds(false); } -void WindowSelectorItem::UpdateHeaderLayout( - OverviewAnimationType animation_type) { +void OverviewItem::UpdateHeaderLayout(OverviewAnimationType animation_type) { gfx::Rect transformed_window_bounds = - transform_window_.window_selector_bounds().value_or( + transform_window_.overview_bounds().value_or( transform_window_.GetTransformedBounds()); ::wm::ConvertRectFromScreen(root_window_, &transformed_window_bounds); @@ -753,7 +745,7 @@ if (animation_type == OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS_ON_ENTER) { auto start_observer = std::make_unique<StartAnimationObserver>(); animation_settings.AddObserver(start_observer.get()); - Shell::Get()->window_selector_controller()->AddStartAnimationObserver( + Shell::Get()->overview_controller()->AddStartAnimationObserver( std::move(start_observer)); } @@ -761,7 +753,7 @@ // as well as the gap between the windows to prevent events from reaching // the window including its sizing borders. label_rect.set_height(kHeaderHeightDp + transformed_window_bounds.height()); - label_rect.Inset(-kWindowSelectorMargin, -kWindowSelectorMargin); + label_rect.Inset(-kOverviewMargin, -kOverviewMargin); widget_window->SetBounds(label_rect); gfx::Transform label_transform; label_transform.Translate(transformed_window_bounds.x(), @@ -769,11 +761,11 @@ widget_window->SetTransform(label_transform); } -void WindowSelectorItem::AnimateOpacity(float opacity, - OverviewAnimationType animation_type) { +void OverviewItem::AnimateOpacity(float opacity, + OverviewAnimationType animation_type) { DCHECK_GE(opacity, 0.f); DCHECK_LE(opacity, 1.f); - ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings; + ScopedOverviewTransformWindow::ScopedAnimationSettings animation_settings; transform_window_.BeginScopedAnimation(animation_type, &animation_settings); transform_window_.SetOpacity(opacity); @@ -784,12 +776,12 @@ widget_window->layer()->SetOpacity(header_opacity); } -aura::Window* WindowSelectorItem::GetOverviewWindowForMinimizedStateForTest() { +aura::Window* OverviewItem::GetOverviewWindowForMinimizedStateForTest() { return transform_window_.GetOverviewWindowForMinimizedState(); } -void WindowSelectorItem::StartDrag() { - window_grid_->SetSelectionWidgetVisibility(false); +void OverviewItem::StartDrag() { + overview_grid_->SetSelectionWidgetVisibility(false); // |transform_window_| handles hiding shadow and rounded edges mask while // animating, and applies them after animation is complete. Prevent the
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/overview_item.h similarity index 88% rename from ash/wm/overview/window_selector_item.h rename to ash/wm/overview/overview_item.h index d816765..6ff486bc 100644 --- a/ash/wm/overview/window_selector_item.h +++ b/ash/wm/overview/overview_item.h
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_WM_OVERVIEW_WINDOW_SELECTOR_ITEM_H_ -#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_ITEM_H_ +#ifndef ASH_WM_OVERVIEW_OVERVIEW_ITEM_H_ +#define ASH_WM_OVERVIEW_OVERVIEW_ITEM_H_ #include <memory> #include "ash/ash_export.h" -#include "ash/wm/overview/scoped_transform_overview_window.h" -#include "ash/wm/overview/window_selector.h" +#include "ash/wm/overview/overview_session.h" +#include "ash/wm/overview/scoped_overview_transform_window.h" #include "base/macros.h" #include "ui/aura/window_observer.h" #include "ui/compositor/layer_animation_observer.h" @@ -27,17 +27,17 @@ namespace ash { class CaptionContainerView; -class WindowGrid; +class OverviewGrid; // This class represents an item in overview mode. -class ASH_EXPORT WindowSelectorItem : public views::ButtonListener, - public aura::WindowObserver, - public ui::ImplicitAnimationObserver { +class ASH_EXPORT OverviewItem : public views::ButtonListener, + public aura::WindowObserver, + public ui::ImplicitAnimationObserver { public: - WindowSelectorItem(aura::Window* window, - WindowSelector* window_selector, - WindowGrid* window_grid); - ~WindowSelectorItem() override; + OverviewItem(aura::Window* window, + OverviewSession* overview, + OverviewGrid* overview_grid); + ~OverviewItem() override; aura::Window* GetWindow(); @@ -49,7 +49,7 @@ // Returns the root window on which this item is shown. aura::Window* root_window() { return root_window_; } - // Returns true if |target| is contained in this WindowSelectorItem. + // Returns true if |target| is contained in this OverviewItem. bool Contains(const aura::Window* target) const; // Restores and animates the managed window to its non overview mode state. @@ -115,13 +115,13 @@ // window cannot be snapped. void UpdateCannotSnapWarningVisibility(); - // Called when a WindowSelectorItem on any grid is dragged. Hides the close - // button when a drag is started, and reshows it when a drag is finished. + // Called when a OverviewItem on any grid is dragged. Hides the close button + // when a drag is started, and reshows it when a drag is finished. // Additionally hides the title and window icon if |item| is this. - void OnSelectorItemDragStarted(WindowSelectorItem* item); + void OnSelectorItemDragStarted(OverviewItem* item); void OnSelectorItemDragEnded(); - ScopedTransformOverviewWindow::GridWindowFillMode GetWindowDimensionsType() + ScopedOverviewTransformWindow::GridWindowFillMode GetWindowDimensionsType() const; // Recalculates the window dimensions type of |transform_window_|. Called when @@ -162,7 +162,7 @@ void UpdateYPositionAndOpacity( int new_grid_y, float opacity, - WindowSelector::UpdateAnimationSettingsCallback callback); + OverviewSession::UpdateAnimationSettingsCallback callback); // If the window item represents a minimized window, update its content view. void UpdateItemContentViewForMinimizedWindow(); @@ -219,7 +219,7 @@ // ui::ImplicitAnimationObserver: void OnImplicitAnimationsCompleted() override; - WindowGrid* window_grid() { return window_grid_; } + OverviewGrid* overview_grid() { return overview_grid_; } void set_should_animate_when_entering(bool should_animate) { should_animate_when_entering_ = should_animate; @@ -247,8 +247,8 @@ gfx::Rect GetShadowBoundsForTesting(); private: - friend class WindowSelectorTest; - FRIEND_TEST_ALL_PREFIXES(SplitViewWindowSelectorTest, + friend class OverviewSessionTest; + FRIEND_TEST_ALL_PREFIXES(SplitViewOverviewSessionTest, OverviewUnsnappableIndicatorVisibility); // Sets the bounds of this selector's items to |target_bounds| in @@ -282,7 +282,7 @@ aura::Window* root_window_; // The contained Window's wrapper. - ScopedTransformOverviewWindow transform_window_; + ScopedOverviewTransformWindow transform_window_; // The target bounds this selector item is fit within. gfx::Rect target_bounds_; @@ -313,13 +313,13 @@ // title. CaptionContainerView* caption_container_view_ = nullptr; - // Pointer to the WindowSelector that owns the WindowGrid containing |this|. + // Pointer to the Overview that owns the OverviewGrid containing |this|. // Guaranteed to be non-null for the lifetime of |this|. - WindowSelector* window_selector_; + OverviewSession* overview_session_; - // Pointer to the WindowGrid that contains |this|. Guaranteed to be non-null + // Pointer to the OverviewGrid that contains |this|. Guaranteed to be non-null // for the lifetime of |this|. - WindowGrid* window_grid_; + OverviewGrid* overview_grid_; // True if the contained window should animate during the entering animation. bool should_animate_when_entering_ = true; @@ -333,7 +333,7 @@ // True if the windows are still alive so they can have a closing animation. // These windows should not be used in calculations for - // WindowGrid::PositionWindows. + // OverviewGrid::PositionWindows. bool animating_to_close_ = false; // The shadow around the overview window. Shadows the original window, not @@ -341,9 +341,9 @@ // rounded edges mask applied on entering overview window. std::unique_ptr<ui::Shadow> shadow_; - DISALLOW_COPY_AND_ASSIGN(WindowSelectorItem); + DISALLOW_COPY_AND_ASSIGN(OverviewItem); }; } // namespace ash -#endif // ASH_WM_OVERVIEW_WINDOW_SELECTOR_ITEM_H_ +#endif // ASH_WM_OVERVIEW_OVERVIEW_ITEM_H_
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/overview_session.cc similarity index 78% rename from ash/wm/overview/window_selector.cc rename to ash/wm/overview/overview_session.cc index bac7095..917d42d1 100644 --- a/ash/wm/overview/window_selector.cc +++ b/ash/wm/overview/overview_session.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/overview/window_selector.h" +#include "ash/wm/overview/overview_session.h" #include <algorithm> #include <functional> @@ -16,12 +16,12 @@ #include "ash/shelf/shelf_constants.h" #include "ash/shell.h" #include "ash/wm/mru_window_tracker.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_delegate.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_item.h" #include "ash/wm/overview/overview_utils.h" #include "ash/wm/overview/overview_window_drag_controller.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_delegate.h" -#include "ash/wm/overview/window_selector_item.h" #include "ash/wm/splitview/split_view_drag_indicators.h" #include "ash/wm/splitview/split_view_utils.h" #include "ash/wm/switchable_windows.h" @@ -132,7 +132,7 @@ } // namespace -WindowSelector::WindowSelector(WindowSelectorDelegate* delegate) +OverviewSession::OverviewSession(OverviewDelegate* delegate) : delegate_(delegate), restore_focus_window_(wm::GetFocusedWindow()), overview_start_time_(base::Time::Now()) { @@ -140,12 +140,12 @@ Shell::Get()->AddPreTargetHandler(this); } -WindowSelector::~WindowSelector() { +OverviewSession::~OverviewSession() { DCHECK(observed_windows_.empty()); // Don't delete |window_drag_controller_| yet since the stack might be still // using it. if (window_drag_controller_) { - window_drag_controller_->ResetWindowSelector(); + window_drag_controller_->ResetOverviewSession(); base::ThreadTaskRunnerHandle::Get()->DeleteSoon( FROM_HERE, window_drag_controller_.release()); } @@ -154,10 +154,10 @@ // NOTE: The work done in Init() is not done in the constructor because it may // cause other, unrelated classes, to make indirect method calls on a partially // constructed object. -void WindowSelector::Init(const WindowList& windows, - const WindowList& hide_windows) { +void OverviewSession::Init(const WindowList& windows, + const WindowList& hide_windows) { hide_overview_windows_ = - std::make_unique<ScopedHideOverviewWindows>(std::move(hide_windows)); + std::make_unique<ScopedOverviewHideWindows>(std::move(hide_windows)); if (restore_focus_window_) restore_focus_window_->AddObserver(this); @@ -185,41 +185,42 @@ observed_windows_.insert(container); } - auto grid = std::make_unique<WindowGrid>( + auto grid = std::make_unique<OverviewGrid>( root, windows, this, GetGridBoundsInScreen(root, /*divider_changed=*/false)); num_items_ += grid->size(); grid_list_.push_back(std::move(grid)); } - // The calls to WindowGrid::PrepareForOverview() requires some LayoutManagers - // to perform layouts so that windows are correctly visible and properly - // animated in overview mode. Otherwise these layouts should be suppressed - // during overview mode so they don't conflict with overview mode animations. + // The calls to OverviewGrid::PrepareForOverview() requires some + // LayoutManagers to perform layouts so that windows are correctly visible and + // properly animated in overview mode. Otherwise these layouts should be + // suppressed during overview mode so they don't conflict with overview mode + // animations. // Do not call PrepareForOverview until all items are added to window_list_ // as we don't want to cause any window updates until all windows in // overview are observed. See http://crbug.com/384495. - for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) { - window_grid->PrepareForOverview(); + for (std::unique_ptr<OverviewGrid>& overview_grid : grid_list_) { + overview_grid->PrepareForOverview(); // Do not animate if there is any window that is being dragged in the // grid. if (enter_exit_overview_type_ == EnterExitOverviewType::kWindowDragged) { - window_grid->PositionWindows(/*animate=*/false); + overview_grid->PositionWindows(/*animate=*/false); } else if (enter_exit_overview_type_ == EnterExitOverviewType::kWindowsMinimized) { - window_grid->PositionWindows(/*animate=*/false); - window_grid->SlideWindowsIn(); + overview_grid->PositionWindows(/*animate=*/false); + overview_grid->SlideWindowsIn(); } else { // EnterExitOverviewType::kSwipeFromShelf is an exit only type, so it // should not appear here. DCHECK_NE(enter_exit_overview_type_, EnterExitOverviewType::kSwipeFromShelf); - window_grid->CalculateWindowListAnimationStates( + overview_grid->CalculateWindowListAnimationStates( /*selected_item=*/nullptr, OverviewTransition::kEnter); - window_grid->PositionWindows(/*animate=*/true, /*ignore_item=*/nullptr, - OverviewTransition::kEnter); + overview_grid->PositionWindows(/*animate=*/true, /*ignore_item=*/nullptr, + OverviewTransition::kEnter); } } @@ -256,7 +257,7 @@ // NOTE: The work done in Shutdown() is not done in the destructor because it // may cause other, unrelated classes, to make indirect calls to // restoring_minimized_windows() on a partially destructed object. -void WindowSelector::Shutdown() { +void OverviewSession::Shutdown() { Shell::Get()->RemovePreTargetHandler(this); // Stop observing screen metrics changes first to avoid auto-positioning @@ -269,19 +270,20 @@ Shell::Get()->split_view_controller()->RemoveObserver(this); size_t remaining_items = 0; - for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) { + for (std::unique_ptr<OverviewGrid>& overview_grid : grid_list_) { // During shutdown, do not animate all windows in overview if we need to // animate the snapped window. - if (window_grid->should_animate_when_exiting()) { - window_grid->CalculateWindowListAnimationStates( - selected_item_ && selected_item_->window_grid() == window_grid.get() + if (overview_grid->should_animate_when_exiting()) { + overview_grid->CalculateWindowListAnimationStates( + selected_item_ && + selected_item_->overview_grid() == overview_grid.get() ? selected_item_ : nullptr, OverviewTransition::kExit); } - for (const auto& window_selector_item : window_grid->window_list()) - window_selector_item->RestoreWindow(/*reset_transform=*/true); - remaining_items += window_grid->size(); + for (const auto& overview_item : overview_grid->window_list()) + overview_item->RestoreWindow(/*reset_transform=*/true); + remaining_items += overview_grid->size(); } // Setting focus after restoring windows' state avoids unnecessary animations. @@ -291,8 +293,8 @@ EnterExitOverviewType::kNormal); RemoveAllObservers(); - for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) - window_grid->Shutdown(); + for (std::unique_ptr<OverviewGrid>& overview_grid : grid_list_) + overview_grid->Shutdown(); DCHECK(num_items_ >= remaining_items); UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.OverviewClosedItems", @@ -300,17 +302,16 @@ UMA_HISTOGRAM_MEDIUM_TIMES("Ash.WindowSelector.TimeInOverview", base::Time::Now() - overview_start_time_); - // Clearing the window list resets the ignored_by_shelf flag on the windows. grid_list_.clear(); UpdateShelfVisibility(); } -void WindowSelector::CancelSelection() { +void OverviewSession::CancelSelection() { delegate_->OnSelectionEnded(); } -void WindowSelector::OnGridEmpty(WindowGrid* grid) { +void OverviewSession::OnGridEmpty(OverviewGrid* grid) { size_t index = 0; // If there are no longer any items on any of the grids, shutdown, // otherwise the empty grids will remain blurred but will have no items. @@ -348,21 +349,20 @@ PositionWindows(/*animate=*/false); } -void WindowSelector::IncrementSelection(int increment) { - const Direction direction = - increment > 0 ? WindowSelector::RIGHT : WindowSelector::LEFT; +void OverviewSession::IncrementSelection(int increment) { + const Direction direction = increment > 0 ? RIGHT : LEFT; for (int step = 0; step < abs(increment); ++step) Move(direction, true); } -bool WindowSelector::AcceptSelection() { +bool OverviewSession::AcceptSelection() { if (!grid_list_[selected_grid_index_]->is_selecting()) return false; SelectWindow(grid_list_[selected_grid_index_]->SelectedWindow()); return true; } -void WindowSelector::SelectWindow(WindowSelectorItem* item) { +void OverviewSession::SelectWindow(OverviewItem* item) { aura::Window* window = item->GetWindow(); aura::Window::Windows window_list = Shell::Get()->mru_window_tracker()->BuildMruWindowList(); @@ -387,14 +387,14 @@ ::wm::ActivateWindow(window); } -void WindowSelector::SetBoundsForWindowGridsInScreenIgnoringWindow( +void OverviewSession::SetBoundsForOverviewGridsInScreenIgnoringWindow( const gfx::Rect& bounds, - WindowSelectorItem* ignored_item) { - for (std::unique_ptr<WindowGrid>& grid : grid_list_) + OverviewItem* ignored_item) { + for (std::unique_ptr<OverviewGrid>& grid : grid_list_) grid->SetBoundsAndUpdatePositionsIgnoringWindow(bounds, ignored_item); } -void WindowSelector::SetSplitViewDragIndicatorsIndicatorState( +void OverviewSession::SetSplitViewDragIndicatorsIndicatorState( IndicatorState indicator_state, const gfx::Point& event_location) { DCHECK(split_view_drag_indicators_); @@ -402,8 +402,9 @@ event_location); } -WindowGrid* WindowSelector::GetGridWithRootWindow(aura::Window* root_window) { - for (std::unique_ptr<WindowGrid>& grid : grid_list_) { +OverviewGrid* OverviewSession::GetGridWithRootWindow( + aura::Window* root_window) { + for (std::unique_ptr<OverviewGrid>& grid : grid_list_) { if (grid->root_window() == root_window) return grid.get(); } @@ -411,12 +412,12 @@ return nullptr; } -void WindowSelector::AddItem(aura::Window* window, - bool reposition, - bool animate) { +void OverviewSession::AddItem(aura::Window* window, + bool reposition, + bool animate) { // Early exit if a grid already contains |window|. - WindowGrid* grid = GetGridWithRootWindow(window->GetRootWindow()); - if (!grid || grid->GetWindowSelectorItemContaining(window)) + OverviewGrid* grid = GetGridWithRootWindow(window->GetRootWindow()); + if (!grid || grid->GetOverviewItemContaining(window)) return; grid->AddItem(window, reposition, animate); @@ -428,8 +429,7 @@ ::wm::ActivateWindow(GetOverviewFocusWindow()); } -void WindowSelector::RemoveWindowSelectorItem(WindowSelectorItem* item, - bool reposition) { +void OverviewSession::RemoveOverviewItem(OverviewItem* item, bool reposition) { if (item->GetWindow()->HasObserver(this)) { item->GetWindow()->RemoveObserver(this); observed_windows_.erase(item->GetWindow()); @@ -438,8 +438,8 @@ } // Remove |item| from the corresponding grid. - for (std::unique_ptr<WindowGrid>& grid : grid_list_) { - if (grid->GetWindowSelectorItemContaining(item->GetWindow())) { + for (std::unique_ptr<OverviewGrid>& grid : grid_list_) { + if (grid->GetOverviewItemContaining(item->GetWindow())) { grid->RemoveItem(item, reposition); --num_items_; break; @@ -447,83 +447,84 @@ } } -void WindowSelector::InitiateDrag(WindowSelectorItem* item, - const gfx::Point& location_in_screen) { +void OverviewSession::InitiateDrag(OverviewItem* item, + const gfx::Point& location_in_screen) { window_drag_controller_ = std::make_unique<OverviewWindowDragController>(this); window_drag_controller_->InitiateDrag(item, location_in_screen); - for (std::unique_ptr<WindowGrid>& grid : grid_list_) + for (std::unique_ptr<OverviewGrid>& grid : grid_list_) grid->OnSelectorItemDragStarted(item); } -void WindowSelector::Drag(WindowSelectorItem* item, - const gfx::Point& location_in_screen) { +void OverviewSession::Drag(OverviewItem* item, + const gfx::Point& location_in_screen) { DCHECK(window_drag_controller_); DCHECK_EQ(item, window_drag_controller_->item()); window_drag_controller_->Drag(location_in_screen); } -void WindowSelector::CompleteDrag(WindowSelectorItem* item, - const gfx::Point& location_in_screen) { +void OverviewSession::CompleteDrag(OverviewItem* item, + const gfx::Point& location_in_screen) { DCHECK(window_drag_controller_); DCHECK_EQ(item, window_drag_controller_->item()); window_drag_controller_->CompleteDrag(location_in_screen); - for (std::unique_ptr<WindowGrid>& grid : grid_list_) + for (std::unique_ptr<OverviewGrid>& grid : grid_list_) grid->OnSelectorItemDragEnded(); } -void WindowSelector::StartSplitViewDragMode( +void OverviewSession::StartSplitViewDragMode( const gfx::Point& location_in_screen) { window_drag_controller_->StartSplitViewDragMode(location_in_screen); } -void WindowSelector::Fling(WindowSelectorItem* item, - const gfx::Point& location_in_screen, - float velocity_x, - float velocity_y) { +void OverviewSession::Fling(OverviewItem* item, + const gfx::Point& location_in_screen, + float velocity_x, + float velocity_y) { // Its possible a fling event is not paired with a tap down event. Ignore // these flings. if (!window_drag_controller_ || item != window_drag_controller_->item()) return; window_drag_controller_->Fling(location_in_screen, velocity_x, velocity_y); - for (std::unique_ptr<WindowGrid>& grid : grid_list_) + for (std::unique_ptr<OverviewGrid>& grid : grid_list_) grid->OnSelectorItemDragEnded(); } -void WindowSelector::ActivateDraggedWindow() { +void OverviewSession::ActivateDraggedWindow() { window_drag_controller_->ActivateDraggedWindow(); } -void WindowSelector::ResetDraggedWindowGesture() { +void OverviewSession::ResetDraggedWindowGesture() { window_drag_controller_->ResetGesture(); } -void WindowSelector::OnWindowDragStarted(aura::Window* dragged_window, - bool animate) { - WindowGrid* target_grid = +void OverviewSession::OnWindowDragStarted(aura::Window* dragged_window, + bool animate) { + OverviewGrid* target_grid = GetGridWithRootWindow(dragged_window->GetRootWindow()); if (!target_grid) return; target_grid->OnWindowDragStarted(dragged_window, animate); } -void WindowSelector::OnWindowDragContinued(aura::Window* dragged_window, - const gfx::Point& location_in_screen, - IndicatorState indicator_state) { - WindowGrid* target_grid = +void OverviewSession::OnWindowDragContinued( + aura::Window* dragged_window, + const gfx::Point& location_in_screen, + IndicatorState indicator_state) { + OverviewGrid* target_grid = GetGridWithRootWindow(dragged_window->GetRootWindow()); if (!target_grid) return; target_grid->OnWindowDragContinued(dragged_window, location_in_screen, indicator_state); } -void WindowSelector::OnWindowDragEnded(aura::Window* dragged_window, - const gfx::Point& location_in_screen, - bool should_drop_window_into_overview) { - WindowGrid* target_grid = +void OverviewSession::OnWindowDragEnded(aura::Window* dragged_window, + const gfx::Point& location_in_screen, + bool should_drop_window_into_overview) { + OverviewGrid* target_grid = GetGridWithRootWindow(dragged_window->GetRootWindow()); if (!target_grid) return; @@ -531,15 +532,15 @@ should_drop_window_into_overview); } -void WindowSelector::PositionWindows(bool animate, - WindowSelectorItem* ignored_item) { - for (std::unique_ptr<WindowGrid>& grid : grid_list_) +void OverviewSession::PositionWindows(bool animate, + OverviewItem* ignored_item) { + for (std::unique_ptr<OverviewGrid>& grid : grid_list_) grid->PositionWindows(animate, ignored_item); } -bool WindowSelector::ShouldAnimateWallpaper(aura::Window* root_window) { +bool OverviewSession::ShouldAnimateWallpaper(aura::Window* root_window) { // Find the grid associated with |root_window|. - WindowGrid* grid = GetGridWithRootWindow(root_window); + OverviewGrid* grid = GetGridWithRootWindow(root_window); if (!grid) return false; @@ -552,42 +553,42 @@ return true; } -bool WindowSelector::IsWindowInOverview(const aura::Window* window) { - for (const std::unique_ptr<WindowGrid>& grid : grid_list_) { - if (grid->GetWindowSelectorItemContaining(window)) +bool OverviewSession::IsWindowInOverview(const aura::Window* window) { + for (const std::unique_ptr<OverviewGrid>& grid : grid_list_) { + if (grid->GetOverviewItemContaining(window)) return true; } return false; } -void WindowSelector::SetWindowListNotAnimatedWhenExiting( +void OverviewSession::SetWindowListNotAnimatedWhenExiting( aura::Window* root_window) { // Find the grid accociated with |root_window|. - WindowGrid* grid = GetGridWithRootWindow(root_window); + OverviewGrid* grid = GetGridWithRootWindow(root_window); if (grid) grid->SetWindowListNotAnimatedWhenExiting(); } -void WindowSelector::UpdateGridAtLocationYPositionAndOpacity( +void OverviewSession::UpdateGridAtLocationYPositionAndOpacity( int64_t display_id, int new_y, float opacity, const gfx::Rect& work_area, UpdateAnimationSettingsCallback callback) { - WindowGrid* grid = GetGridWithRootWindow( + OverviewGrid* grid = GetGridWithRootWindow( ash::Shell::Get()->GetRootWindowForDisplayId(display_id)); if (grid) grid->UpdateYPositionAndOpacity(new_y, opacity, work_area, callback); } -void WindowSelector::UpdateMaskAndShadow(bool show) { +void OverviewSession::UpdateMaskAndShadow(bool show) { for (auto& grid : grid_list_) { for (auto& window : grid->window_list()) window->UpdateMaskAndShadow(show); } } -void WindowSelector::OnStartingAnimationComplete(bool canceled) { +void OverviewSession::OnStartingAnimationComplete(bool canceled) { if (!canceled) { UpdateMaskAndShadow(!canceled); if (overview_focus_widget_) @@ -599,7 +600,7 @@ } } -bool WindowSelector::IsWindowGridAnimating() { +bool OverviewSession::IsOverviewGridAnimating() { for (auto& grid : grid_list_) { if (grid->shield_widget() ->GetNativeWindow() @@ -612,7 +613,7 @@ return false; } -void WindowSelector::OnWindowActivating( +void OverviewSession::OnWindowActivating( ::wm::ActivationChangeObserver::ActivationReason reason, aura::Window* gained_active, aura::Window* lost_active) { @@ -640,7 +641,7 @@ const auto& windows = grid->window_list(); auto iter = std::find_if( windows.begin(), windows.end(), - [gained_active](const std::unique_ptr<WindowSelectorItem>& window) { + [gained_active](const std::unique_ptr<OverviewItem>& window) { return window->Contains(gained_active); }); @@ -649,20 +650,20 @@ CancelSelection(); } -aura::Window* WindowSelector::GetOverviewFocusWindow() { +aura::Window* OverviewSession::GetOverviewFocusWindow() { if (overview_focus_widget_) return overview_focus_widget_->GetNativeWindow(); return nullptr; } -void WindowSelector::OnDisplayRemoved(const display::Display& display) { +void OverviewSession::OnDisplayRemoved(const display::Display& display) { // TODO(flackr): Keep window selection active on remaining displays. CancelSelection(); } -void WindowSelector::OnDisplayMetricsChanged(const display::Display& display, - uint32_t metrics) { +void OverviewSession::OnDisplayMetricsChanged(const display::Display& display, + uint32_t metrics) { // For metrics changes that happen when the split view mode is active, the // display bounds will be adjusted in OnSplitViewDividerPositionChanged(). if (Shell::Get()->IsSplitViewModeActive()) @@ -670,7 +671,7 @@ OnDisplayBoundsChanged(); } -void WindowSelector::OnWindowHierarchyChanged( +void OverviewSession::OnWindowHierarchyChanged( const HierarchyChangeParams& params) { // Only care about newly added children of |observed_windows_|. if (!observed_windows_.count(params.receiver) || @@ -704,14 +705,14 @@ } } -void WindowSelector::OnWindowDestroying(aura::Window* window) { +void OverviewSession::OnWindowDestroying(aura::Window* window) { window->RemoveObserver(this); observed_windows_.erase(window); if (window == restore_focus_window_) restore_focus_window_ = nullptr; } -void WindowSelector::OnKeyEvent(ui::KeyEvent* event) { +void OverviewSession::OnKeyEvent(ui::KeyEvent* event) { if (event->type() != ui::ET_KEY_PRESSED) return; @@ -723,24 +724,24 @@ break; case ui::VKEY_UP: num_key_presses_++; - Move(WindowSelector::UP, true); + Move(UP, true); break; case ui::VKEY_DOWN: num_key_presses_++; - Move(WindowSelector::DOWN, true); + Move(DOWN, true); break; case ui::VKEY_RIGHT: case ui::VKEY_TAB: if (event->key_code() == ui::VKEY_RIGHT || !(event->flags() & ui::EF_SHIFT_DOWN)) { num_key_presses_++; - Move(WindowSelector::RIGHT, true); + Move(RIGHT, true); break; } FALLTHROUGH; case ui::VKEY_LEFT: num_key_presses_++; - Move(WindowSelector::LEFT, true); + Move(LEFT, true); break; case ui::VKEY_W: if (!(event->flags() & ui::EF_CONTROL_DOWN) || @@ -772,7 +773,7 @@ event->StopPropagation(); } -void WindowSelector::OnSplitViewStateChanged( +void OverviewSession::OnSplitViewStateChanged( SplitViewController::State previous_state, SplitViewController::State state) { const bool unsnappable_window_activated = @@ -800,10 +801,10 @@ } } -void WindowSelector::OnSplitViewDividerPositionChanged() { +void OverviewSession::OnSplitViewDividerPositionChanged() { DCHECK(Shell::Get()->IsSplitViewModeActive()); // Re-calculate the bounds for the window grids and position all the windows. - for (std::unique_ptr<WindowGrid>& grid : grid_list_) { + for (std::unique_ptr<OverviewGrid>& grid : grid_list_) { grid->SetBoundsAndUpdatePositions( GetGridBoundsInScreen(const_cast<aura::Window*>(grid->root_window()), /*divider_changed=*/true)); @@ -811,7 +812,7 @@ PositionWindows(/*animate=*/false); } -void WindowSelector::ResetFocusRestoreWindow(bool focus) { +void OverviewSession::ResetFocusRestoreWindow(bool focus) { if (!restore_focus_window_) return; @@ -830,7 +831,7 @@ restore_focus_window_ = nullptr; } -void WindowSelector::Move(Direction direction, bool animate) { +void OverviewSession::Move(Direction direction, bool animate) { // Direction to move if moving past the end of a display. int display_direction = (direction == RIGHT || direction == DOWN) ? 1 : -1; @@ -852,7 +853,7 @@ } } -void WindowSelector::RemoveAllObservers() { +void OverviewSession::RemoveAllObservers() { for (auto* window : observed_windows_) window->RemoveObserver(this); observed_windows_.clear(); @@ -862,9 +863,9 @@ restore_focus_window_->RemoveObserver(this); } -void WindowSelector::OnDisplayBoundsChanged() { +void OverviewSession::OnDisplayBoundsChanged() { // Re-calculate the bounds for the window grids and position all the windows. - for (std::unique_ptr<WindowGrid>& grid : grid_list_) { + for (std::unique_ptr<OverviewGrid>& grid : grid_list_) { grid->SetBoundsAndUpdatePositions( GetGridBoundsInScreen(const_cast<aura::Window*>(grid->root_window()), /*divider_changed=*/false)); @@ -874,7 +875,7 @@ split_view_drag_indicators_->OnDisplayBoundsChanged(); } -bool WindowSelector::IsEmpty() { +bool OverviewSession::IsEmpty() { for (const auto& grid : grid_list_) { if (!grid->empty()) return false;
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/overview_session.h similarity index 84% rename from ash/wm/overview/window_selector.h rename to ash/wm/overview/overview_session.h index c1f886e..2ae3af7 100644 --- a/ash/wm/overview/window_selector.h +++ b/ash/wm/overview/overview_session.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_WM_OVERVIEW_WINDOW_SELECTOR_H_ -#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_H_ +#ifndef ASH_WM_OVERVIEW_OVERVIEW_SESSION_H_ +#define ASH_WM_OVERVIEW_OVERVIEW_SESSION_H_ #include <stddef.h> #include <stdint.h> @@ -12,7 +12,7 @@ #include <vector> #include "ash/ash_export.h" -#include "ash/wm/overview/scoped_hide_overview_windows.h" +#include "ash/wm/overview/scoped_overview_hide_windows.h" #include "ash/wm/splitview/split_view_controller.h" #include "base/containers/flat_set.h" #include "base/macros.h" @@ -39,19 +39,18 @@ class OverviewWindowDragController; class SplitViewDragIndicators; -class WindowGrid; -class WindowSelectorDelegate; -class WindowSelectorItem; -class WindowSelectorTest; +class OverviewGrid; +class OverviewDelegate; +class OverviewItem; enum class IndicatorState; -// The WindowSelector shows a grid of all of your windows, allowing to select +// The Overview shows a grid of all of your windows, allowing to select // one by clicking or tapping on it. -class ASH_EXPORT WindowSelector : public display::DisplayObserver, - public aura::WindowObserver, - public ui::EventHandler, - public SplitViewController::Observer { +class ASH_EXPORT OverviewSession : public display::DisplayObserver, + public aura::WindowObserver, + public ui::EventHandler, + public SplitViewController::Observer { public: enum Direction { LEFT, UP, RIGHT, DOWN }; @@ -94,8 +93,8 @@ using WindowList = std::vector<aura::Window*>; - explicit WindowSelector(WindowSelectorDelegate* delegate); - ~WindowSelector() override; + explicit OverviewSession(OverviewDelegate* delegate); + ~OverviewSession() override; // Initialize with the windows that can be selected. void Init(const WindowList& windows, const WindowList& hide_windows); @@ -107,7 +106,7 @@ void CancelSelection(); // Called when the last window selector item from a grid is deleted. - void OnGridEmpty(WindowGrid* grid); + void OnGridEmpty(OverviewGrid* grid); // Moves the current selection by |increment| items. Positive values of // |increment| move the selection forward, negative values move it backward. @@ -118,12 +117,12 @@ bool AcceptSelection(); // Activates |item's| window. - void SelectWindow(WindowSelectorItem* item); + void SelectWindow(OverviewItem* item); // Called to set bounds for window grids. Used for split view. - void SetBoundsForWindowGridsInScreenIgnoringWindow( + void SetBoundsForOverviewGridsInScreenIgnoringWindow( const gfx::Rect& bounds, - WindowSelectorItem* ignored_item); + OverviewItem* ignored_item); // Called to show or hide the split view drag indicators. This will do // nothing if split view is not enabled. |event_location| is used to reparent @@ -134,7 +133,7 @@ // Retrieves the window grid whose root window matches |root_window|. Returns // nullptr if the window grid is not found. - WindowGrid* GetGridWithRootWindow(aura::Window* root_window); + OverviewGrid* GetGridWithRootWindow(aura::Window* root_window); // Add |window| to the grid in |grid_list_| with the same root window. Does // nothing if the grid already contains |window|. And if |reposition| is true, @@ -155,15 +154,13 @@ // overview grid; 2) when a window (not from overview) ends its dragging while // overview is open, the drop target should be removed. Note in both cases, // the windows in the window grid do not need to be repositioned. - void RemoveWindowSelectorItem(WindowSelectorItem* item, bool reposition); + void RemoveOverviewItem(OverviewItem* item, bool reposition); - void InitiateDrag(WindowSelectorItem* item, - const gfx::Point& location_in_screen); - void Drag(WindowSelectorItem* item, const gfx::Point& location_in_screen); - void CompleteDrag(WindowSelectorItem* item, - const gfx::Point& location_in_screen); + void InitiateDrag(OverviewItem* item, const gfx::Point& location_in_screen); + void Drag(OverviewItem* item, const gfx::Point& location_in_screen); + void CompleteDrag(OverviewItem* item, const gfx::Point& location_in_screen); void StartSplitViewDragMode(const gfx::Point& location_in_screen); - void Fling(WindowSelectorItem* item, + void Fling(OverviewItem* item, const gfx::Point& location_in_screen, float velocity_x, float velocity_y); @@ -182,8 +179,7 @@ bool should_drop_window_into_overview); // Positions all of the windows in the overview, except |ignored_item|. - void PositionWindows(bool animate, - WindowSelectorItem* ignored_item = nullptr); + void PositionWindows(bool animate, OverviewItem* ignored_item = nullptr); // Checks if the grid associated with a given |root_window| needs to have the // wallpaper animated. Returns false if one of the grids windows covers the @@ -218,7 +214,7 @@ // Returns true if any of the grids in |grid_list_| shield widgets are still // animating. - bool IsWindowGridAnimating(); + bool IsOverviewGridAnimating(); // Called when windows are being activated/deactivated during // overview mode. @@ -230,7 +226,7 @@ // Gets the window which keeps focus for the duration of overview mode. aura::Window* GetOverviewFocusWindow(); - WindowSelectorDelegate* delegate() { return delegate_; } + OverviewDelegate* delegate() { return delegate_; } SplitViewDragIndicators* split_view_drag_indicators() { return split_view_drag_indicators_.get(); @@ -247,7 +243,7 @@ return window_drag_controller_.get(); } - const std::vector<std::unique_ptr<WindowGrid>>& grid_list_for_testing() + const std::vector<std::unique_ptr<OverviewGrid>>& grid_list_for_testing() const { return grid_list_; } @@ -270,7 +266,7 @@ void OnSplitViewDividerPositionChanged() override; private: - friend class WindowSelectorTest; + friend class OverviewSessionTest; // |focus|, restores focus to the stored window. void ResetFocusRestoreWindow(bool focus); @@ -294,7 +290,7 @@ // Weak pointer to the selector delegate which will be called when a // selection is made. - WindowSelectorDelegate* delegate_; + OverviewDelegate* delegate_; // A weak pointer to the window which was focused on beginning window // selection. If window selection is canceled the focus should be restored to @@ -306,9 +302,9 @@ // use one of the overview windows otherwise ::wm::ActivateWindow will not // work. // TODO(sammiequon): Investigate if we can focus the |selection_widget_| in - // WindowGrid when it is created, or if we can focus a widget from the virtual - // desks UI when that is complete, or we may be able to add some mechanism to - // trigger accessibility events without a focused window. + // OverviewGrid when it is created, or if we can focus a widget from the + // virtual desks UI when that is complete, or we may be able to add some + // mechanism to trigger accessibility events without a focused window. std::unique_ptr<views::Widget> overview_focus_widget_; // True when performing operations that may cause window activations. This is @@ -317,7 +313,7 @@ bool ignore_activations_ = true; // List of all the window overview grids, one for each root window. - std::vector<std::unique_ptr<WindowGrid>> grid_list_; + std::vector<std::unique_ptr<OverviewGrid>> grid_list_; // The owner of the widget which displays splitview related information in // overview mode. This will be nullptr if split view is not enabled. @@ -344,16 +340,16 @@ // The selected item when exiting overview mode. nullptr if no window // selected. - WindowSelectorItem* selected_item_ = nullptr; + OverviewItem* selected_item_ = nullptr; // The drag controller for a window in the overview mode. std::unique_ptr<OverviewWindowDragController> window_drag_controller_; - std::unique_ptr<ScopedHideOverviewWindows> hide_overview_windows_; + std::unique_ptr<ScopedOverviewHideWindows> hide_overview_windows_; - DISALLOW_COPY_AND_ASSIGN(WindowSelector); + DISALLOW_COPY_AND_ASSIGN(OverviewSession); }; } // namespace ash -#endif // ASH_WM_OVERVIEW_WINDOW_SELECTOR_H_ +#endif // ASH_WM_OVERVIEW_OVERVIEW_SESSION_H_
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/overview_session_unittest.cc similarity index 86% rename from ash/wm/overview/window_selector_unittest.cc rename to ash/wm/overview/overview_session_unittest.cc index 303e13e..ad3696d 100644 --- a/ash/wm/overview/window_selector_unittest.cc +++ b/ash/wm/overview/overview_session_unittest.cc
@@ -21,12 +21,12 @@ #include "ash/test/ash_test_base.h" #include "ash/wm/overview/caption_container_view.h" #include "ash/wm/overview/overview_constants.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_item.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/overview/overview_utils.h" #include "ash/wm/overview/overview_window_drag_controller.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_item.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_divider.h" #include "ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h" @@ -118,10 +118,10 @@ // TODO(bruthig): Move all non-simple method definitions out of class // declaration. -class WindowSelectorTest : public AshTestBase { +class OverviewSessionTest : public AshTestBase { public: - WindowSelectorTest() = default; - ~WindowSelectorTest() override = default; + OverviewSessionTest() = default; + ~OverviewSessionTest() override = default; void SetUp() override { AshTestBase::SetUp(); @@ -129,8 +129,8 @@ shelf_view_test_api_ = std::make_unique<ShelfViewTestAPI>( GetPrimaryShelf()->GetShelfViewForTesting()); shelf_view_test_api_->SetAnimationDuration(1); - ScopedTransformOverviewWindow::SetImmediateCloseForTests(); - WindowSelectorController::SetDoNotChangeWallpaperBlurForTests(); + ScopedOverviewTransformWindow::SetImmediateCloseForTests(); + OverviewController::SetDoNotChangeWallpaperBlurForTests(); } // Enters tablet mode. Needed by tests that test dragging and or splitview, @@ -148,22 +148,22 @@ return window1_bounds.Intersects(window2_bounds); } - WindowSelectorController* window_selector_controller() { - return Shell::Get()->window_selector_controller(); + OverviewController* overview_controller() { + return Shell::Get()->overview_controller(); } - WindowSelector* window_selector() { - return window_selector_controller()->window_selector_.get(); + OverviewSession* overview_session() { + return overview_controller()->overview_session_.get(); } - void ToggleOverview(WindowSelector::EnterExitOverviewType type = - WindowSelector::EnterExitOverviewType::kNormal) { - window_selector_controller()->ToggleOverview(type); + void ToggleOverview(OverviewSession::EnterExitOverviewType type = + OverviewSession::EnterExitOverviewType::kNormal) { + overview_controller()->ToggleOverview(type); } aura::Window* GetOverviewWindowForMinimizedState(int index, aura::Window* window) { - WindowSelectorItem* item = GetWindowItemForWindow(index, window); + OverviewItem* item = GetWindowItemForWindow(index, window); return item->GetOverviewWindowForMinimizedStateForTest(); } @@ -213,20 +213,19 @@ GetEventGenerator()->ReleaseKey(key, flags); } - bool IsSelecting() { return window_selector_controller()->IsSelecting(); } + bool IsSelecting() { return overview_controller()->IsSelecting(); } - const std::vector<std::unique_ptr<WindowSelectorItem>>& GetWindowItemsForRoot( + const std::vector<std::unique_ptr<OverviewItem>>& GetWindowItemsForRoot( int index) { - return window_selector()->grid_list_[index]->window_list(); + return overview_session()->grid_list_[index]->window_list(); } - WindowSelectorItem* GetWindowItemForWindow(int grid_index, - aura::Window* window) { - const std::vector<std::unique_ptr<WindowSelectorItem>>& windows = + OverviewItem* GetWindowItemForWindow(int grid_index, aura::Window* window) { + const std::vector<std::unique_ptr<OverviewItem>>& windows = GetWindowItemsForRoot(grid_index); auto iter = std::find_if(windows.cbegin(), windows.cend(), - [window](const std::unique_ptr<WindowSelectorItem>& item) { + [window](const std::unique_ptr<OverviewItem>& item) { return item->Contains(window); }); if (iter == windows.end()) @@ -251,36 +250,35 @@ } const aura::Window* GetSelectedWindow() { - WindowSelector* ws = window_selector(); - WindowSelectorItem* item = - ws->grid_list_[ws->selected_grid_index_]->SelectedWindow(); + OverviewSession* os = overview_session(); + OverviewItem* item = + os->grid_list_[os->selected_grid_index_]->SelectedWindow(); if (!item) return nullptr; return item->GetWindow(); } bool selection_widget_active() { - WindowSelector* ws = window_selector(); - return ws->grid_list_[ws->selected_grid_index_]->is_selecting(); + OverviewSession* os = overview_session(); + return os->grid_list_[os->selected_grid_index_]->is_selecting(); } - views::ImageButton* GetCloseButton(WindowSelectorItem* window) { + views::ImageButton* GetCloseButton(OverviewItem* window) { return window->caption_container_view_->GetCloseButton(); } - views::Label* GetLabelView(WindowSelectorItem* window) { + views::Label* GetLabelView(OverviewItem* window) { return window->caption_container_view_->title_label(); } - views::Label* GetCannotSnapLabelView(WindowSelectorItem* window) { + views::Label* GetCannotSnapLabelView(OverviewItem* window) { return window->caption_container_view_->cannot_snap_label(); } - // Tests that a window is contained within a given WindowSelectorItem, and - // that both the window and its matching close button are within the same - // screen. + // Tests that a window is contained within a given OverviewItem, and that both + // the window and its matching close button are within the same screen. void CheckWindowAndCloseButtonInScreen(aura::Window* window, - WindowSelectorItem* window_item) { + OverviewItem* window_item) { const gfx::Rect screen_bounds = window_item->root_window()->GetBoundsInScreen(); EXPECT_TRUE(window_item->Contains(window)); @@ -289,41 +287,41 @@ GetCloseButton(window_item)->GetBoundsInScreen())); } - void SetGridBounds(WindowGrid* grid, const gfx::Rect& bounds) { + void SetGridBounds(OverviewGrid* grid, const gfx::Rect& bounds) { grid->bounds_ = bounds; } gfx::Rect GetGridBounds() { - if (window_selector()) - return window_selector()->grid_list_[0]->bounds_; + if (overview_session()) + return overview_session()->grid_list_[0]->bounds_; return gfx::Rect(); } - views::Widget* item_widget(WindowSelectorItem* item) { + views::Widget* item_widget(OverviewItem* item) { return item->item_widget_.get(); } - views::Widget* minimized_widget(WindowSelectorItem* item) { + views::Widget* minimized_widget(OverviewItem* item) { return item->transform_window_.minimized_widget(); } - views::Widget* backdrop_widget(WindowSelectorItem* item) { + views::Widget* backdrop_widget(OverviewItem* item) { return item->backdrop_widget_.get(); } - bool HasMaskForItem(WindowSelectorItem* item) const { + bool HasMaskForItem(OverviewItem* item) const { return !!item->transform_window_.mask_; } private: std::unique_ptr<ShelfViewTestAPI> shelf_view_test_api_; - DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest); + DISALLOW_COPY_AND_ASSIGN(OverviewSessionTest); }; // Tests that an a11y alert is sent on entering overview mode. -TEST_F(WindowSelectorTest, A11yAlertOnOverviewMode) { +TEST_F(OverviewSessionTest, A11yAlertOnOverviewMode) { TestAccessibilityControllerClient client; AccessibilityController* controller = Shell::Get()->accessibility_controller(); @@ -339,7 +337,7 @@ // Tests that there are no crashes when there is not enough screen space // available to show all of the windows. -TEST_F(WindowSelectorTest, SmallDisplay) { +TEST_F(OverviewSessionTest, SmallDisplay) { UpdateDisplay("3x1"); gfx::Rect bounds(0, 0, 1, 1); std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds)); @@ -354,7 +352,7 @@ } // Tests entering overview mode with two windows and selecting one by clicking. -TEST_F(WindowSelectorTest, Basic) { +TEST_F(OverviewSessionTest, Basic) { // Overview disabled by default. EXPECT_FALSE(IsSelecting()); @@ -374,7 +372,7 @@ // In overview mode the windows should no longer overlap and the overview // focus window should be focused. ToggleOverview(); - EXPECT_EQ(window_selector()->GetOverviewFocusWindow(), + EXPECT_EQ(overview_session()->GetOverviewFocusWindow(), wm::GetFocusedWindow()); EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get())); @@ -389,7 +387,7 @@ } // Tests activating minimized window. -TEST_F(WindowSelectorTest, ActivateMinimized) { +TEST_F(OverviewSessionTest, ActivateMinimized) { std::unique_ptr<aura::Window> window(CreateTestWindow()); wm::WindowState* window_state = wm::GetWindowState(window.get()); @@ -424,7 +422,7 @@ // Tests that the ordering of windows is stable across different overview // sessions even when the windows have the same bounds. -TEST_F(WindowSelectorTest, WindowsOrder) { +TEST_F(OverviewSessionTest, WindowsOrder) { std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1)); std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(2)); std::unique_ptr<aura::Window> window3(CreateTestWindowInShellWithId(3)); @@ -432,7 +430,7 @@ // The order of windows in overview mode is MRU. wm::GetWindowState(window1.get())->Activate(); ToggleOverview(); - const std::vector<std::unique_ptr<WindowSelectorItem>>& overview1 = + const std::vector<std::unique_ptr<OverviewItem>>& overview1 = GetWindowItemsForRoot(0); EXPECT_EQ(1, overview1[0]->GetWindow()->id()); EXPECT_EQ(3, overview1[1]->GetWindow()->id()); @@ -442,7 +440,7 @@ // Activate the second window. wm::GetWindowState(window2.get())->Activate(); ToggleOverview(); - const std::vector<std::unique_ptr<WindowSelectorItem>>& overview2 = + const std::vector<std::unique_ptr<OverviewItem>>& overview2 = GetWindowItemsForRoot(0); // The order should be MRU. @@ -453,13 +451,13 @@ } // Tests selecting a window by tapping on it. -TEST_F(WindowSelectorTest, BasicGesture) { +TEST_F(OverviewSessionTest, BasicGesture) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); ::wm::ActivateWindow(window1.get()); EXPECT_EQ(window1.get(), wm::GetFocusedWindow()); ToggleOverview(); - EXPECT_EQ(window_selector()->GetOverviewFocusWindow(), + EXPECT_EQ(overview_session()->GetOverviewFocusWindow(), wm::GetFocusedWindow()); GetEventGenerator()->GestureTapAt( GetTransformedTargetBounds(window2.get()).CenterPoint()); @@ -469,7 +467,7 @@ // Tests that the user action WindowSelector_ActiveWindowChanged is // recorded when the mouse/touchscreen/keyboard are used to select a window // in overview mode which is different from the previously-active window. -TEST_F(WindowSelectorTest, ActiveWindowChangedUserActionRecorded) { +TEST_F(OverviewSessionTest, ActiveWindowChangedUserActionRecorded) { base::UserActionTester user_action_tester; std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); @@ -503,7 +501,7 @@ // recorded when the mouse/touchscreen/keyboard are used to select the // already-active window from overview mode. Also verifies that entering and // exiting overview without selecting a window does not record the action. -TEST_F(WindowSelectorTest, ActiveWindowChangedUserActionNotRecorded) { +TEST_F(OverviewSessionTest, ActiveWindowChangedUserActionNotRecorded) { base::UserActionTester user_action_tester; std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); @@ -541,7 +539,7 @@ // Tests that the user action WindowSelector_ActiveWindowChanged is not // recorded when overview mode exits as a result of closing its only window. -TEST_F(WindowSelectorTest, ActiveWindowChangedUserActionWindowClose) { +TEST_F(OverviewSessionTest, ActiveWindowChangedUserActionWindowClose) { base::UserActionTester user_action_tester; std::unique_ptr<views::Widget> widget(CreateTestWidget( nullptr, kShellWindowId_DefaultContainer, gfx::Rect(400, 400))); @@ -561,7 +559,7 @@ // Tests that we do not crash and overview mode remains engaged if the desktop // is tapped while a finger is already down over a window. -TEST_F(WindowSelectorTest, NoCrashWithDesktopTap) { +TEST_F(OverviewSessionTest, NoCrashWithDesktopTap) { std::unique_ptr<aura::Window> window( CreateTestWindow(gfx::Rect(200, 300, 250, 450))); @@ -584,7 +582,7 @@ // Tests that we do not crash and a window is selected when appropriate when // we click on a window during touch. -TEST_F(WindowSelectorTest, ClickOnWindowDuringTouch) { +TEST_F(OverviewSessionTest, ClickOnWindowDuringTouch) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); ::wm::ActivateWindow(window2.get()); @@ -618,7 +616,7 @@ } // Tests that a window does not receive located events when in overview mode. -TEST_F(WindowSelectorTest, WindowDoesNotReceiveEvents) { +TEST_F(OverviewSessionTest, WindowDoesNotReceiveEvents) { std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(400, 400))); const gfx::Point point1 = window->bounds().CenterPoint(); ui::MouseEvent event1(ui::ET_MOUSE_PRESSED, point1, point1, @@ -646,7 +644,7 @@ } // Tests that clicking on the close button effectively closes the window. -TEST_F(WindowSelectorTest, CloseButton) { +TEST_F(OverviewSessionTest, CloseButton) { std::unique_ptr<views::Widget> widget(CreateTestWidget()); std::unique_ptr<views::Widget> minimized_widget(CreateTestWidget()); minimized_widget->Minimize(); @@ -683,7 +681,7 @@ } // Tests minimizing/unminimizing in overview mode. -TEST_F(WindowSelectorTest, MinimizeUnminimize) { +TEST_F(OverviewSessionTest, MinimizeUnminimize) { std::unique_ptr<views::Widget> widget(CreateTestWidget()); aura::Window* window = widget->GetNativeWindow(); @@ -703,7 +701,7 @@ // Tests that clicking on the close button on a secondary display effectively // closes the window. -TEST_F(WindowSelectorTest, CloseButtonOnMultipleDisplay) { +TEST_F(OverviewSessionTest, CloseButtonOnMultipleDisplay) { UpdateDisplay("600x400,600x400"); // We need a widget for the close button to work because windows are closed @@ -729,7 +727,7 @@ } // Tests entering overview mode with two windows and selecting one. -TEST_F(WindowSelectorTest, FullscreenWindow) { +TEST_F(OverviewSessionTest, FullscreenWindow) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); ::wm::ActivateWindow(window1.get()); @@ -753,7 +751,7 @@ // Tests that entering overview when a fullscreen window is active in maximized // mode correctly applies the transformations to the window and correctly // updates the window bounds on exiting overview mode: http://crbug.com/401664. -TEST_F(WindowSelectorTest, FullscreenWindowTabletMode) { +TEST_F(OverviewSessionTest, FullscreenWindowTabletMode) { UpdateDisplay("800x600"); const gfx::Rect bounds(400, 400); std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds)); @@ -810,7 +808,7 @@ screen->GetDisplayNearestWindow(window1.get()).work_area()); } -TEST_F(WindowSelectorTest, SkipOverviewWindow) { +TEST_F(OverviewSessionTest, SkipOverviewWindow) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); window2->SetProperty(ash::kHideInOverviewKey, true); @@ -829,7 +827,7 @@ // Tests that a minimized window's visibility and layer visibility // stay invisible (A minimized window is cloned during overview). -TEST_F(WindowSelectorTest, MinimizedWindowState) { +TEST_F(OverviewSessionTest, MinimizedWindowState) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); wm::GetWindowState(window1.get())->Minimize(); EXPECT_FALSE(window1->IsVisible()); @@ -845,7 +843,7 @@ } // Tests that a bounds change during overview is corrected for. -TEST_F(WindowSelectorTest, BoundsChangeDuringOverview) { +TEST_F(OverviewSessionTest, BoundsChangeDuringOverview) { std::unique_ptr<aura::Window> window( CreateTestWindowInShellWithDelegate(nullptr, -1, gfx::Rect(400, 400))); // Use overview headers above the window in this test. @@ -859,7 +857,7 @@ } // Tests that a newly created window aborts overview. -TEST_F(WindowSelectorTest, NewWindowCancelsOverview) { +TEST_F(OverviewSessionTest, NewWindowCancelsOverview) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); ToggleOverview(); EXPECT_TRUE(IsSelecting()); @@ -870,7 +868,7 @@ } // Tests that a window activation exits overview mode. -TEST_F(WindowSelectorTest, ActivationCancelsOverview) { +TEST_F(OverviewSessionTest, ActivationCancelsOverview) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); window2->Focus(); @@ -888,14 +886,14 @@ // Tests that exiting overview mode without selecting a window restores focus // to the previously focused window. -TEST_F(WindowSelectorTest, CancelRestoresFocus) { +TEST_F(OverviewSessionTest, CancelRestoresFocus) { std::unique_ptr<aura::Window> window(CreateTestWindow()); ::wm::ActivateWindow(window.get()); EXPECT_EQ(window.get(), wm::GetFocusedWindow()); // In overview mode, the overview focus window should be focused. ToggleOverview(); - EXPECT_EQ(window_selector()->GetOverviewFocusWindow(), + EXPECT_EQ(overview_session()->GetOverviewFocusWindow(), wm::GetFocusedWindow()); // If canceling overview mode, focus should be restored. @@ -904,7 +902,7 @@ } // Tests that overview mode is exited if the last remaining window is destroyed. -TEST_F(WindowSelectorTest, LastWindowDestroyed) { +TEST_F(OverviewSessionTest, LastWindowDestroyed) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); ToggleOverview(); @@ -916,7 +914,7 @@ // Regression test for crash when closing the last overview mode window under // SingleProcessMash. https://crbug.com/922293. -TEST_F(WindowSelectorTest, DontRestoreFocusToUnparentedWindow) { +TEST_F(OverviewSessionTest, DontRestoreFocusToUnparentedWindow) { const gfx::Rect bounds(400, 400); std::unique_ptr<aura::Window> parent = CreateTestWindow(bounds); std::unique_ptr<aura::Window> child = CreateChildWindow(parent.get(), bounds); @@ -939,7 +937,7 @@ // Tests that entering overview mode restores a window to its original // target location. -TEST_F(WindowSelectorTest, QuickReentryRestoresInitialTransform) { +TEST_F(OverviewSessionTest, QuickReentryRestoresInitialTransform) { std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(400, 400))); gfx::Rect initial_bounds = GetTransformedBounds(window.get()); ToggleOverview(); @@ -960,7 +958,7 @@ // Tests that windows with modal child windows are transformed with the modal // child even though not activatable themselves. -TEST_F(WindowSelectorTest, ModalChild) { +TEST_F(OverviewSessionTest, ModalChild) { const gfx::Rect bounds(400, 400); std::unique_ptr<aura::Window> window(CreateTestWindow(bounds)); std::unique_ptr<aura::Window> child(CreateTestWindow(bounds)); @@ -977,7 +975,7 @@ // Tests that clicking a modal window's parent activates the modal window in // overview. -TEST_F(WindowSelectorTest, ClickModalWindowParent) { +TEST_F(OverviewSessionTest, ClickModalWindowParent) { std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(180, 180))); std::unique_ptr<aura::Window> child( CreateTestWindow(gfx::Rect(200, 0, 180, 180))); @@ -998,7 +996,7 @@ // Tests that windows remain on the display they are currently on in overview // mode, and that the close buttons are on matching displays. -TEST_F(WindowSelectorTest, MultipleDisplays) { +TEST_F(OverviewSessionTest, MultipleDisplays) { UpdateDisplay("600x400,600x400"); aura::Window::Windows root_windows = Shell::GetAllRootWindows(); gfx::Rect bounds1(0, 0, 400, 400); @@ -1032,7 +1030,7 @@ } // Tests shutting down during overview. -TEST_F(WindowSelectorTest, Shutdown) { +TEST_F(OverviewSessionTest, Shutdown) { // These windows will be deleted when the test exits and the Shell instance // is shut down. std::unique_ptr<aura::Window> window1(CreateTestWindow()); @@ -1045,7 +1043,7 @@ } // Tests removing a display during overview. -TEST_F(WindowSelectorTest, RemoveDisplay) { +TEST_F(OverviewSessionTest, RemoveDisplay) { UpdateDisplay("400x400,400x400"); std::unique_ptr<aura::Window> window1(CreateTestWindow(gfx::Rect(100, 100))); std::unique_ptr<aura::Window> window2( @@ -1065,7 +1063,7 @@ } // Tests removing a display during overview with NON_ZERO_DURATION animation. -TEST_F(WindowSelectorTest, RemoveDisplayWithAnimation) { +TEST_F(OverviewSessionTest, RemoveDisplayWithAnimation) { UpdateDisplay("400x400,400x400"); std::unique_ptr<aura::Window> window1(CreateTestWindow(gfx::Rect(100, 100))); std::unique_ptr<aura::Window> window2( @@ -1106,7 +1104,7 @@ } // namespace // Tests that toggling overview on and off does not cancel drag. -TEST_F(WindowSelectorTest, DragDropInProgress) { +TEST_F(OverviewSessionTest, DragDropInProgress) { std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate( new TestDragWindowDelegate(), -1, gfx::Rect(100, 100))); @@ -1131,12 +1129,12 @@ } // Test that a label is created under the window on entering overview mode. -TEST_F(WindowSelectorTest, CreateLabelUnderWindow) { +TEST_F(OverviewSessionTest, CreateLabelUnderWindow) { std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(300, 500))); const base::string16 window_title = base::UTF8ToUTF16("My window"); window->SetTitle(window_title); ToggleOverview(); - WindowSelectorItem* window_item = GetWindowItemsForRoot(0).back().get(); + OverviewItem* window_item = GetWindowItemsForRoot(0).back().get(); views::Label* label = GetLabelView(window_item); ASSERT_TRUE(label); @@ -1157,7 +1155,7 @@ // Tests that overview updates the window positions if the display orientation // changes. -TEST_F(WindowSelectorTest, DisplayOrientationChanged) { +TEST_F(OverviewSessionTest, DisplayOrientationChanged) { aura::Window* root_window = Shell::Get()->GetPrimaryRootWindow(); UpdateDisplay("600x200"); EXPECT_EQ(gfx::Rect(600, 200), root_window->bounds()); @@ -1184,12 +1182,12 @@ } // Tests traversing some windows in overview mode with the tab key. -TEST_F(WindowSelectorTest, BasicTabKeyNavigation) { +TEST_F(OverviewSessionTest, BasicTabKeyNavigation) { std::unique_ptr<aura::Window> window2(CreateTestWindow()); std::unique_ptr<aura::Window> window1(CreateTestWindow()); ToggleOverview(); - const std::vector<std::unique_ptr<WindowSelectorItem>>& overview_windows = + const std::vector<std::unique_ptr<OverviewItem>>& overview_windows = GetWindowItemsForRoot(0); SendKey(ui::VKEY_TAB); EXPECT_EQ(GetSelectedWindow(), overview_windows[0]->GetWindow()); @@ -1200,7 +1198,7 @@ } // Tests that pressing Ctrl+W while a window is selected in overview closes it. -TEST_F(WindowSelectorTest, CloseWindowWithKey) { +TEST_F(OverviewSessionTest, CloseWindowWithKey) { std::unique_ptr<views::Widget> widget(CreateTestWidget()); ToggleOverview(); @@ -1212,7 +1210,7 @@ // Tests traversing some windows in overview mode with the arrow keys in every // possible direction. -TEST_F(WindowSelectorTest, BasicArrowKeyNavigation) { +TEST_F(OverviewSessionTest, BasicArrowKeyNavigation) { const size_t test_windows = 9; UpdateDisplay("800x600"); std::vector<std::unique_ptr<aura::Window>> windows; @@ -1234,7 +1232,7 @@ for (size_t key_index = 0; key_index < base::size(arrow_keys); key_index++) { ToggleOverview(); - const std::vector<std::unique_ptr<WindowSelectorItem>>& overview_windows = + const std::vector<std::unique_ptr<OverviewItem>>& overview_windows = GetWindowItemsForRoot(0); for (size_t i = 0; i < test_windows + 1; i++) { SendKey(arrow_keys[key_index]); @@ -1249,23 +1247,23 @@ } // Tests hitting the escape and back keys exit overview mode. -TEST_F(WindowSelectorTest, ExitOverviewWithKey) { +TEST_F(OverviewSessionTest, ExitOverviewWithKey) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); SendKey(ui::VKEY_ESCAPE); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); SendKey(ui::VKEY_BROWSER_BACK); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); } // Regression test for clusterfuzz crash. https://crbug.com/920568 -TEST_F(WindowSelectorTest, TypeThenPressEscapeTwice) { +TEST_F(OverviewSessionTest, TypeThenPressEscapeTwice) { std::unique_ptr<aura::Window> window(CreateTestWindow()); ToggleOverview(); @@ -1273,7 +1271,7 @@ SendKey(ui::VKEY_A); SendKey(ui::VKEY_B); SendKey(ui::VKEY_C); - EXPECT_TRUE(window_selector()->GetOverviewFocusWindow()); + EXPECT_TRUE(overview_session()->GetOverviewFocusWindow()); // Pressing escape twice should not crash. SendKey(ui::VKEY_ESCAPE); @@ -1281,7 +1279,7 @@ } // Tests basic selection across multiple monitors. -TEST_F(WindowSelectorTest, BasicMultiMonitorArrowKeyNavigation) { +TEST_F(OverviewSessionTest, BasicMultiMonitorArrowKeyNavigation) { UpdateDisplay("400x400,400x400"); const gfx::Rect bounds1(100, 100); const gfx::Rect bounds2(450, 0, 100, 100); @@ -1292,9 +1290,9 @@ ToggleOverview(); - const std::vector<std::unique_ptr<WindowSelectorItem>>& overview_root1 = + const std::vector<std::unique_ptr<OverviewItem>>& overview_root1 = GetWindowItemsForRoot(0); - const std::vector<std::unique_ptr<WindowSelectorItem>>& overview_root2 = + const std::vector<std::unique_ptr<OverviewItem>>& overview_root2 = GetWindowItemsForRoot(1); SendKey(ui::VKEY_RIGHT); EXPECT_EQ(GetSelectedWindow(), overview_root1[0]->GetWindow()); @@ -1308,7 +1306,7 @@ // Tests first monitor when display order doesn't match left to right screen // positions. -TEST_F(WindowSelectorTest, MultiMonitorReversedOrder) { +TEST_F(OverviewSessionTest, MultiMonitorReversedOrder) { UpdateDisplay("400x400,400x400"); Shell::Get()->display_manager()->SetLayoutForCurrentDisplays( display::test::CreateDisplayLayout(display_manager(), @@ -1338,7 +1336,7 @@ } // Tests three monitors where the grid becomes empty on one of the monitors. -TEST_F(WindowSelectorTest, ThreeMonitor) { +TEST_F(OverviewSessionTest, ThreeMonitor) { UpdateDisplay("400x400,400x400,400x400"); aura::Window::Windows root_windows = Shell::GetAllRootWindows(); std::unique_ptr<aura::Window> window3( @@ -1377,7 +1375,7 @@ } // Tests selecting a window in overview mode with the return key. -TEST_F(WindowSelectorTest, SelectWindowWithReturnKey) { +TEST_F(OverviewSessionTest, SelectWindowWithReturnKey) { std::unique_ptr<aura::Window> window2(CreateTestWindow()); std::unique_ptr<aura::Window> window1(CreateTestWindow()); ToggleOverview(); @@ -1400,7 +1398,7 @@ EXPECT_TRUE(wm::IsActiveWindow(window2.get())); } -TEST_F(WindowSelectorTest, CancelOverviewOnMouseClick) { +TEST_F(OverviewSessionTest, CancelOverviewOnMouseClick) { // Point and bounds selected so that they don't intersect. This causes // events located at the point to be passed to WallpaperController, // and not the window. @@ -1424,7 +1422,7 @@ } // Tests tapping on the desktop itself to cancel overview mode. -TEST_F(WindowSelectorTest, CancelOverviewOnTap) { +TEST_F(OverviewSessionTest, CancelOverviewOnTap) { // Point and bounds selected so that they don't intersect. This causes // events located at the point to be passed to WallpaperController, // and not the window. @@ -1446,7 +1444,7 @@ // Start dragging a window and activate overview mode. This test should not // crash or DCHECK inside aura::Window::StackChildRelativeTo(). -TEST_F(WindowSelectorTest, OverviewWhileDragging) { +TEST_F(OverviewSessionTest, OverviewWhileDragging) { std::unique_ptr<aura::Window> window(CreateTestWindow()); std::unique_ptr<WindowResizer> resizer(CreateWindowResizer( window.get(), gfx::Point(), HTCAPTION, ::wm::WINDOW_MOVE_SOURCE_MOUSE)); @@ -1460,19 +1458,19 @@ // Verify that the overview no windows indicator appears when entering overview // mode with no windows. -TEST_F(WindowSelectorTest, OverviewNoWindowsIndicator) { +TEST_F(OverviewSessionTest, OverviewNoWindowsIndicator) { // Verify that by entering overview mode without windows, the no items // indicator appears. ToggleOverview(); - ASSERT_TRUE(window_selector()); + ASSERT_TRUE(overview_session()); EXPECT_EQ(0u, GetWindowItemsForRoot(0).size()); - EXPECT_TRUE(window_selector() + EXPECT_TRUE(overview_session() ->grid_list_for_testing()[0] ->IsNoItemsIndicatorLabelVisibleForTesting()); } // Verify that the overview no windows indicator position is as expected. -TEST_F(WindowSelectorTest, OverviewNoWindowsIndicatorPosition) { +TEST_F(OverviewSessionTest, OverviewNoWindowsIndicatorPosition) { UpdateDisplay("400x300"); // Midpoint of height minus shelf. const int expected_y = (300 - ShelfConstants::shelf_size()) / 2; @@ -1485,10 +1483,10 @@ }; ToggleOverview(); - ASSERT_TRUE(window_selector()); + ASSERT_TRUE(overview_session()); // Verify that originally the label is in the center of the workspace. - WindowGrid* grid = window_selector()->grid_list_for_testing()[0].get(); + OverviewGrid* grid = overview_session()->grid_list_for_testing()[0].get(); check_point(gfx::Point(200, expected_y), grid->GetNoItemsIndicatorLabelBoundsForTesting().CenterPoint()); @@ -1520,12 +1518,12 @@ // Verify that when opening overview mode with multiple displays, the no items // indicator on the primary grid if there are no windows. Also verify that // we do not exit overview mode until all the grids are empty. -TEST_F(WindowSelectorTest, OverviewNoWindowsIndicatorMultiDisplay) { +TEST_F(OverviewSessionTest, OverviewNoWindowsIndicatorMultiDisplay) { // Helper function to help reduce lines of code. Returns the list of grids // in overview mode. - auto grids = [this]() -> const std::vector<std::unique_ptr<WindowGrid>>& { - EXPECT_TRUE(window_selector()); - return window_selector()->grid_list_for_testing(); + auto grids = [this]() -> const std::vector<std::unique_ptr<OverviewGrid>>& { + EXPECT_TRUE(overview_session()); + return overview_session()->grid_list_for_testing(); }; UpdateDisplay("400x400,400x400,400x400"); @@ -1534,7 +1532,7 @@ // primary display but not on the other two. ToggleOverview(); base::RunLoop().RunUntilIdle(); - ASSERT_TRUE(window_selector()); + ASSERT_TRUE(overview_session()); ASSERT_EQ(3u, grids().size()); EXPECT_TRUE(grids()[0]->IsNoItemsIndicatorLabelVisibleForTesting()); EXPECT_FALSE(grids()[1]->IsNoItemsIndicatorLabelVisibleForTesting()); @@ -1556,7 +1554,7 @@ // any display. ToggleOverview(); base::RunLoop().RunUntilIdle(); - ASSERT_TRUE(window_selector()); + ASSERT_TRUE(overview_session()); ASSERT_EQ(3u, grids().size()); EXPECT_FALSE(grids()[0]->IsNoItemsIndicatorLabelVisibleForTesting()); EXPECT_FALSE(grids()[1]->IsNoItemsIndicatorLabelVisibleForTesting()); @@ -1565,15 +1563,15 @@ EXPECT_FALSE(grids()[1]->empty()); EXPECT_TRUE(grids()[2]->empty()); - WindowSelectorItem* item1 = GetWindowItemForWindow(0, window1); - WindowSelectorItem* item2 = GetWindowItemForWindow(1, window2); + OverviewItem* item1 = GetWindowItemForWindow(0, window1); + OverviewItem* item2 = GetWindowItemForWindow(1, window2); ASSERT_TRUE(item1 && item2); // Close |item2|. Verify that we are still in overview mode because |window1| // is still open. The non primary root grids are empty however. item2->CloseWindow(); base::RunLoop().RunUntilIdle(); - ASSERT_TRUE(window_selector()); + ASSERT_TRUE(overview_session()); ASSERT_EQ(3u, grids().size()); EXPECT_FALSE(grids()[0]->IsNoItemsIndicatorLabelVisibleForTesting()); EXPECT_FALSE(grids()[1]->IsNoItemsIndicatorLabelVisibleForTesting()); @@ -1586,11 +1584,11 @@ // mode. item1->CloseWindow(); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(window_selector()); + EXPECT_FALSE(overview_session()); } // Tests window list animation states are correctly updated. -TEST_F(WindowSelectorTest, SetWindowListAnimationStates) { +TEST_F(OverviewSessionTest, SetWindowListAnimationStates) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); std::unique_ptr<aura::Window> window3(CreateTestWindow()); @@ -1622,7 +1620,7 @@ // Tests window list animation states are correctly updated with selected // window. -TEST_F(WindowSelectorTest, SetWindowListAnimationStatesWithSelectedWindow) { +TEST_F(OverviewSessionTest, SetWindowListAnimationStatesWithSelectedWindow) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); std::unique_ptr<aura::Window> window3(CreateTestWindow()); @@ -1659,7 +1657,7 @@ } // Tests OverviewWindowAnimationObserver can handle deleted window. -TEST_F(WindowSelectorTest, +TEST_F(OverviewSessionTest, OverviewWindowAnimationObserverCanHandleDeletedWindow) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); @@ -1703,7 +1701,7 @@ } // Tests can handle OverviewWindowAnimationObserver was deleted. -TEST_F(WindowSelectorTest, HandleOverviewWindowAnimationObserverWasDeleted) { +TEST_F(OverviewSessionTest, HandleOverviewWindowAnimationObserverWasDeleted) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); std::unique_ptr<aura::Window> window3(CreateTestWindow()); @@ -1736,9 +1734,9 @@ EXPECT_FALSE(window3->layer()->GetAnimator()->is_animating()); } -// Tests can handle |gained_active| window is not in the |window_grid| when +// Tests can handle |gained_active| window is not in the |overview_grid| when // OnWindowActivated. -TEST_F(WindowSelectorTest, HandleActiveWindowNotInWindowGrid) { +TEST_F(OverviewSessionTest, HandleActiveWindowNotInOverviewGrid) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); std::unique_ptr<aura::Window> window3(CreateTestWindow()); @@ -1780,7 +1778,7 @@ // Tests that AlwaysOnTopWindow can be handled correctly in new overview // animations. // Fails consistently; see https://crbug.com/812497. -TEST_F(WindowSelectorTest, DISABLED_HandleAlwaysOnTopWindow) { +TEST_F(OverviewSessionTest, DISABLED_HandleAlwaysOnTopWindow) { const gfx::Rect bounds(400, 400); std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds)); std::unique_ptr<aura::Window> window2(CreateTestWindow(bounds)); @@ -1960,7 +1958,7 @@ // Verify that the selector item can animate after the item is dragged and // released. -TEST_F(WindowSelectorTest, WindowItemCanAnimateOnDragRelease) { +TEST_F(OverviewSessionTest, WindowItemCanAnimateOnDragRelease) { UpdateDisplay("400x400"); std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); @@ -1969,7 +1967,7 @@ EnterTabletMode(); ToggleOverview(); - WindowSelectorItem* item2 = GetWindowItemForWindow(0, window2.get()); + OverviewItem* item2 = GetWindowItemForWindow(0, window2.get()); // Drag |item2| in a way so that |window2| does not get activated. ui::test::EventGenerator* generator = GetEventGenerator(); generator->MoveMouseTo(item2->target_bounds().CenterPoint()); @@ -1985,17 +1983,17 @@ base::RunLoop().RunUntilIdle(); } -// Verify that the window selector items titlebar and close button change -// visibility when a item is being dragged. -TEST_F(WindowSelectorTest, WindowItemTitleCloseVisibilityOnDrag) { +// Verify that the overview items titlebar and close button change visibility +// when a item is being dragged. +TEST_F(OverviewSessionTest, WindowItemTitleCloseVisibilityOnDrag) { UpdateDisplay("400x400"); std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); EnterTabletMode(); ToggleOverview(); - WindowSelectorItem* item1 = GetWindowItemForWindow(0, window1.get()); - WindowSelectorItem* item2 = GetWindowItemForWindow(0, window2.get()); + OverviewItem* item1 = GetWindowItemForWindow(0, window1.get()); + OverviewItem* item2 = GetWindowItemForWindow(0, window2.get()); // Start the drag on |item1|. Verify the dragged item, |item1| has both the // close button and titlebar hidden. The close button opacity however is // opaque as its a child of the header which handles fading away the whole @@ -2022,7 +2020,7 @@ } // Tests that overview widgets are stacked in the correct order. -TEST_F(WindowSelectorTest, OverviewWidgetStackingOrder) { +TEST_F(OverviewSessionTest, OverviewWidgetStackingOrder) { // Create three windows, including one minimized. std::unique_ptr<aura::Window> window(CreateTestWindow()); std::unique_ptr<aura::Window> minimized(CreateTestWindow()); @@ -2034,9 +2032,9 @@ EnterTabletMode(); ToggleOverview(); - WindowSelectorItem* item1 = GetWindowItemForWindow(0, window.get()); - WindowSelectorItem* item2 = GetWindowItemForWindow(0, minimized.get()); - WindowSelectorItem* item3 = GetWindowItemForWindow(0, window3.get()); + OverviewItem* item1 = GetWindowItemForWindow(0, window.get()); + OverviewItem* item2 = GetWindowItemForWindow(0, minimized.get()); + OverviewItem* item3 = GetWindowItemForWindow(0, window3.get()); views::Widget* widget1 = item_widget(item1); views::Widget* widget2 = item_widget(item2); @@ -2103,16 +2101,16 @@ } // Tests that overview widgets are stacked in the correct order. -TEST_F(WindowSelectorTest, OverviewWidgetStackingOrderWithDragging) { +TEST_F(OverviewSessionTest, OverviewWidgetStackingOrderWithDragging) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); std::unique_ptr<aura::Window> window3(CreateTestWindow()); EnterTabletMode(); ToggleOverview(); - WindowSelectorItem* item1 = GetWindowItemForWindow(0, window1.get()); - WindowSelectorItem* item2 = GetWindowItemForWindow(0, window2.get()); - WindowSelectorItem* item3 = GetWindowItemForWindow(0, window3.get()); + OverviewItem* item1 = GetWindowItemForWindow(0, window1.get()); + OverviewItem* item2 = GetWindowItemForWindow(0, window2.get()); + OverviewItem* item3 = GetWindowItemForWindow(0, window3.get()); views::Widget* widget1 = item_widget(item1); views::Widget* widget2 = item_widget(item2); views::Widget* widget3 = item_widget(item3); @@ -2149,7 +2147,7 @@ // Verify that a windows which enter overview mode have a visible backdrop, if // the window is to be letter or pillar fitted. -TEST_F(WindowSelectorTest, Backdrop) { +TEST_F(OverviewSessionTest, Backdrop) { // Add three windows which in overview mode will be considered wide, tall and // normal. Window |wide|, with size (400, 160) will be resized to (200, 160) // when the 400x200 is rotated to 200x400, and should be considered a normal @@ -2161,9 +2159,9 @@ ToggleOverview(); base::RunLoop().RunUntilIdle(); - WindowSelectorItem* wide_item = GetWindowItemForWindow(0, wide.get()); - WindowSelectorItem* tall_item = GetWindowItemForWindow(0, tall.get()); - WindowSelectorItem* normal_item = GetWindowItemForWindow(0, normal.get()); + OverviewItem* wide_item = GetWindowItemForWindow(0, wide.get()); + OverviewItem* tall_item = GetWindowItemForWindow(0, tall.get()); + OverviewItem* normal_item = GetWindowItemForWindow(0, normal.get()); // Only very tall and very wide windows will have a backdrop. EXPECT_TRUE(backdrop_widget(wide_item)); @@ -2188,7 +2186,7 @@ // Verify that the mask that is applied to add rounded corners in overview mode // is removed during animations and drags. -TEST_F(WindowSelectorTest, RoundedEdgeMaskVisibility) { +TEST_F(OverviewSessionTest, RoundedEdgeMaskVisibility) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); @@ -2198,8 +2196,8 @@ EnterTabletMode(); ToggleOverview(); base::RunLoop().RunUntilIdle(); - WindowSelectorItem* item1 = GetWindowItemForWindow(0, window1.get()); - WindowSelectorItem* item2 = GetWindowItemForWindow(0, window2.get()); + OverviewItem* item1 = GetWindowItemForWindow(0, window1.get()); + OverviewItem* item2 = GetWindowItemForWindow(0, window2.get()); EXPECT_TRUE(HasMaskForItem(item1)); EXPECT_TRUE(HasMaskForItem(item2)); @@ -2241,17 +2239,17 @@ } // Tests that the shadows in overview mode are placed correctly. -TEST_F(WindowSelectorTest, ShadowBounds) { +TEST_F(OverviewSessionTest, ShadowBounds) { // Helper function to check if the bounds of a shadow owned by |shadow_parent| // is contained within the bounds of |widget|. - auto contains = [](views::Widget* widget, WindowSelectorItem* shadow_parent) { + auto contains = [](views::Widget* widget, OverviewItem* shadow_parent) { return gfx::Rect(widget->GetNativeWindow()->bounds().size()) .Contains(shadow_parent->GetShadowBoundsForTesting()); }; // Helper function which returns the ratio of the shadow owned by // |shadow_parent| width and height. - auto shadow_ratio = [](WindowSelectorItem* shadow_parent) { + auto shadow_ratio = [](OverviewItem* shadow_parent) { gfx::RectF boundsf = gfx::RectF(shadow_parent->GetShadowBoundsForTesting()); return boundsf.width() / boundsf.height(); }; @@ -2272,15 +2270,15 @@ ToggleOverview(); base::RunLoop().RunUntilIdle(); - WindowSelectorItem* wide_item = GetWindowItemForWindow(0, wide.get()); - WindowSelectorItem* tall_item = GetWindowItemForWindow(0, tall.get()); - WindowSelectorItem* normal_item = GetWindowItemForWindow(0, normal.get()); + OverviewItem* wide_item = GetWindowItemForWindow(0, wide.get()); + OverviewItem* tall_item = GetWindowItemForWindow(0, tall.get()); + OverviewItem* normal_item = GetWindowItemForWindow(0, normal.get()); views::Widget* wide_widget = item_widget(wide_item); views::Widget* tall_widget = item_widget(tall_item); views::Widget* normal_widget = item_widget(normal_item); - WindowGrid* grid = window_selector()->grid_list_for_testing()[0].get(); + OverviewGrid* grid = overview_session()->grid_list_for_testing()[0].get(); // Verify all the shadows are within the bounds of their respective item // widgets when the overview windows are positioned without animations. @@ -2314,15 +2312,15 @@ // Verify that attempting to drag with a secondary finger works as expected. // Disabled due to flakiness: crbug.com/834708 -TEST_F(WindowSelectorTest, DISABLED_DraggingWithTwoFingers) { +TEST_F(OverviewSessionTest, DISABLED_DraggingWithTwoFingers) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); EnterTabletMode(); ToggleOverview(); base::RunLoop().RunUntilIdle(); - WindowSelectorItem* item1 = GetWindowItemForWindow(0, window1.get()); - WindowSelectorItem* item2 = GetWindowItemForWindow(0, window2.get()); + OverviewItem* item1 = GetWindowItemForWindow(0, window1.get()); + OverviewItem* item2 = GetWindowItemForWindow(0, window2.get()); const gfx::Rect original_bounds1 = item1->target_bounds(); const gfx::Rect original_bounds2 = item2->target_bounds(); @@ -2378,7 +2376,7 @@ } // Verify that shadows on windows disappear for the duration of overview mode. -TEST_F(WindowSelectorTest, ShadowDisappearsInOverview) { +TEST_F(OverviewSessionTest, ShadowDisappearsInOverview) { std::unique_ptr<aura::Window> window(CreateTestWindow()); // Verify that the shadow is initially visible. @@ -2395,7 +2393,7 @@ } // Verify that PIP windows will be excluded from the overview, but not hidden. -TEST_F(WindowSelectorTest, PipWindowShownButExcludedFromOverview) { +TEST_F(OverviewSessionTest, PipWindowShownButExcludedFromOverview) { std::unique_ptr<aura::Window> pip_window( CreateTestWindow(gfx::Rect(200, 200))); wm::WindowState* window_state = wm::GetWindowState(pip_window.get()); @@ -2411,40 +2409,40 @@ } // Tests the PositionWindows function works as expected. -TEST_F(WindowSelectorTest, PositionWindows) { +TEST_F(OverviewSessionTest, PositionWindows) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); std::unique_ptr<aura::Window> window3(CreateTestWindow()); ToggleOverview(); - WindowSelectorItem* item1 = GetWindowItemForWindow(0, window1.get()); - WindowSelectorItem* item2 = GetWindowItemForWindow(0, window2.get()); - WindowSelectorItem* item3 = GetWindowItemForWindow(0, window3.get()); + OverviewItem* item1 = GetWindowItemForWindow(0, window1.get()); + OverviewItem* item2 = GetWindowItemForWindow(0, window2.get()); + OverviewItem* item3 = GetWindowItemForWindow(0, window3.get()); const gfx::Rect bounds1 = item1->target_bounds(); const gfx::Rect bounds2 = item2->target_bounds(); const gfx::Rect bounds3 = item3->target_bounds(); // Verify that the bounds remain the same when calling PositionWindows again. - window_selector()->PositionWindows(/*animate=*/false); + overview_session()->PositionWindows(/*animate=*/false); EXPECT_EQ(bounds1, item1->target_bounds()); EXPECT_EQ(bounds2, item2->target_bounds()); EXPECT_EQ(bounds3, item3->target_bounds()); // Verify that |item2| and |item3| change bounds when calling PositionWindows // while ignoring |item1|. - window_selector()->PositionWindows(/*animate=*/false, item1); + overview_session()->PositionWindows(/*animate=*/false, item1); EXPECT_EQ(bounds1, item1->target_bounds()); EXPECT_NE(bounds2, item2->target_bounds()); EXPECT_NE(bounds3, item3->target_bounds()); // Return the windows to their original bounds. - window_selector()->PositionWindows(/*animate=*/false); + overview_session()->PositionWindows(/*animate=*/false); // Verify that items that are animating before closing are ignored by // PositionWindows. item1->set_animating_to_close(true); item2->set_animating_to_close(true); - window_selector()->PositionWindows(/*animate=*/false); + overview_session()->PositionWindows(/*animate=*/false); EXPECT_EQ(bounds1, item1->target_bounds()); EXPECT_EQ(bounds2, item2->target_bounds()); EXPECT_NE(bounds3, item3->target_bounds()); @@ -2452,7 +2450,7 @@ // Tests that overview mode is entered with kWindowDragged mode when an app is // dragged from the top of the screen. -TEST_F(WindowSelectorTest, DraggingFromTopAnimation) { +TEST_F(OverviewSessionTest, DraggingFromTopAnimation) { EnterTabletMode(); std::unique_ptr<views::Widget> widget(CreateTestWidget( nullptr, kShellWindowId_DefaultContainer, gfx::Rect(200, 200))); @@ -2467,13 +2465,13 @@ drag_controller->DragWindowFromTop(&event); ASSERT_TRUE(IsSelecting()); - EXPECT_EQ(WindowSelector::EnterExitOverviewType::kWindowDragged, - window_selector()->enter_exit_overview_type()); + EXPECT_EQ(OverviewSession::EnterExitOverviewType::kWindowDragged, + overview_session()->enter_exit_overview_type()); } // Tests the grid bounds are as expected with different shelf auto hide // behaviors and alignments. -TEST_F(WindowSelectorTest, GridBounds) { +TEST_F(OverviewSessionTest, GridBounds) { UpdateDisplay("600x600"); std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(200, 200))); @@ -2506,10 +2504,10 @@ ToggleOverview(); } -class SplitViewWindowSelectorTest : public WindowSelectorTest { +class SplitViewOverviewSessionTest : public OverviewSessionTest { public: - SplitViewWindowSelectorTest() = default; - ~SplitViewWindowSelectorTest() override = default; + SplitViewOverviewSessionTest() = default; + ~SplitViewOverviewSessionTest() override = default; enum class SelectorItemLocation { CENTER, @@ -2520,7 +2518,7 @@ }; void SetUp() override { - WindowSelectorTest::SetUp(); + OverviewSessionTest::SetUp(); EnterTabletMode(); } @@ -2568,15 +2566,15 @@ window); } - // Drags a window selector item |item| from its center or one of its corners + // Drags a overview item |item| from its center or one of its corners // to |end_location|. This should be used over - // DragWindowTo(WindowSelectorItem*, gfx::Point) when testing snapping a + // DragWindowTo(OverviewItem*, gfx::Point) when testing snapping a // window, but the windows centerpoint may be inside a snap region, thus the // window will not snapped. This function is mostly used to test splitview so // |long_press| is default to true. Set |long_press| to false if we do not // want to long press after every press, which enables dragging vertically to // close an item. - void DragWindowTo(WindowSelectorItem* item, + void DragWindowTo(OverviewItem* item, const gfx::Point& end_location, SelectorItemLocation location, bool long_press = true) { @@ -2601,16 +2599,15 @@ NOTREACHED(); break; } - window_selector()->InitiateDrag(item, start_location); + overview_session()->InitiateDrag(item, start_location); if (long_press) - window_selector()->StartSplitViewDragMode(start_location); - window_selector()->Drag(item, end_location); - window_selector()->CompleteDrag(item, end_location); + overview_session()->StartSplitViewDragMode(start_location); + overview_session()->Drag(item, end_location); + overview_session()->CompleteDrag(item, end_location); } - // Drags a window selector item |item| from its center point to - // |end_location|. - void DragWindowTo(WindowSelectorItem* item, const gfx::Point& end_location) { + // Drags a overview item |item| from its center point to |end_location|. + void DragWindowTo(OverviewItem* item, const gfx::Point& end_location) { DragWindowTo(item, end_location, SelectorItemLocation::CENTER, true); } @@ -2634,25 +2631,25 @@ void OnWindowDestroyed(aura::Window* window) override { delete this; } }; - DISALLOW_COPY_AND_ASSIGN(SplitViewWindowSelectorTest); + DISALLOW_COPY_AND_ASSIGN(SplitViewOverviewSessionTest); }; -// Tests that dragging a overview window selector item to the edge of the screen -// snaps the window. If two windows are snapped to left and right side of the -// screen, exit the overview mode. -TEST_F(SplitViewWindowSelectorTest, DragOverviewWindowToSnap) { +// Tests that dragging an overview item to the edge of the screen snaps the +// window. If two windows are snapped to left and right side of the screen, exit +// the overview mode. +TEST_F(SplitViewOverviewSessionTest, DragOverviewWindowToSnap) { const gfx::Rect bounds(400, 400); std::unique_ptr<aura::Window> window1(CreateWindow(bounds)); std::unique_ptr<aura::Window> window2(CreateWindow(bounds)); std::unique_ptr<aura::Window> window3(CreateWindow(bounds)); ToggleOverview(); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); // Drag |window1| selector item to snap to left. const int grid_index = 0; - WindowSelectorItem* selector_item1 = + OverviewItem* selector_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(selector_item1, gfx::Point(0, 0)); @@ -2664,19 +2661,18 @@ // Drag |window2| selector item to attempt to snap to left. Since there is // already one left snapped window |window1|, |window1| will be put in // overview mode. - WindowSelectorItem* selector_item2 = + OverviewItem* selector_item2 = GetWindowItemForWindow(grid_index, window2.get()); DragWindowTo(selector_item2, gfx::Point(0, 0)); EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); - EXPECT_TRUE( - window_selector_controller()->window_selector()->IsWindowInOverview( - window1.get())); + EXPECT_TRUE(overview_controller()->overview_session()->IsWindowInOverview( + window1.get())); // Drag |window3| selector item to snap to right. - WindowSelectorItem* selector_item3 = + OverviewItem* selector_item3 = GetWindowItemForWindow(grid_index, window3.get()); const gfx::Point end_location3(GetWorkAreaInScreen(window3.get()).width(), 0); DragWindowTo(selector_item3, end_location3); @@ -2684,21 +2680,21 @@ EXPECT_EQ(split_view_controller()->state(), SplitViewController::BOTH_SNAPPED); EXPECT_EQ(split_view_controller()->right_window(), window3.get()); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); } // Verify the correct behavior when dragging windows in overview mode. -TEST_F(SplitViewWindowSelectorTest, OverviewDragControllerBehavior) { +TEST_F(SplitViewOverviewSessionTest, OverviewDragControllerBehavior) { Shell::Get()->aura_env()->set_throttle_input_on_resize_for_testing(false); std::unique_ptr<aura::Window> window1 = CreateTestWindow(); std::unique_ptr<aura::Window> window2 = CreateTestWindow(); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); - WindowSelectorItem* window_item1 = GetWindowItemForWindow(0, window1.get()); - WindowSelectorItem* window_item2 = GetWindowItemForWindow(0, window2.get()); + OverviewItem* window_item1 = GetWindowItemForWindow(0, window1.get()); + OverviewItem* window_item2 = GetWindowItemForWindow(0, window2.get()); // Verify that if a drag is orginally horizontal, the drag behavior is drag to // snap. @@ -2708,7 +2704,7 @@ window_item1->target_bounds().CenterPoint()); generator->PressTouch(); OverviewWindowDragController* drag_controller = - window_selector()->window_drag_controller(); + overview_session()->window_drag_controller(); EXPECT_EQ(DragBehavior::kUndefined, drag_controller->current_drag_behavior()); generator->MoveTouchBy(20, 0); EXPECT_EQ(DragBehavior::kDragToSnap, @@ -2721,7 +2717,7 @@ generator->set_current_screen_location( window_item2->target_bounds().CenterPoint()); generator->PressTouch(); - drag_controller = window_selector()->window_drag_controller(); + drag_controller = overview_session()->window_drag_controller(); EXPECT_EQ(DragBehavior::kUndefined, drag_controller->current_drag_behavior()); // Use small increments otherwise a fling event will be fired. @@ -2733,70 +2729,68 @@ // Verify that if the window item has been dragged enough vertically, the window // will be closed. -TEST_F(SplitViewWindowSelectorTest, DragToClose) { +TEST_F(SplitViewOverviewSessionTest, DragToClose) { // This test requires a widget. std::unique_ptr<views::Widget> widget(CreateTestWidget()); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); - WindowSelectorItem* item = - GetWindowItemForWindow(0, widget->GetNativeWindow()); + OverviewItem* item = GetWindowItemForWindow(0, widget->GetNativeWindow()); const gfx::Point start = item->target_bounds().CenterPoint(); ASSERT_TRUE(item); // This drag has not covered enough distance, so the widget is not closed and // we remain in overview mode. - window_selector()->InitiateDrag(item, start); - window_selector()->Drag(item, start + gfx::Vector2d(0, 80)); - window_selector()->CompleteDrag(item, start + gfx::Vector2d(0, 80)); - ASSERT_TRUE(window_selector()); + overview_session()->InitiateDrag(item, start); + overview_session()->Drag(item, start + gfx::Vector2d(0, 80)); + overview_session()->CompleteDrag(item, start + gfx::Vector2d(0, 80)); + ASSERT_TRUE(overview_session()); // Verify that the second drag has enough vertical distance, so the widget // will be closed and overview mode will be exited. - window_selector()->InitiateDrag(item, start); - window_selector()->Drag(item, start + gfx::Vector2d(0, 180)); - window_selector()->CompleteDrag(item, start + gfx::Vector2d(0, 180)); + overview_session()->InitiateDrag(item, start); + overview_session()->Drag(item, start + gfx::Vector2d(0, 180)); + overview_session()->CompleteDrag(item, start + gfx::Vector2d(0, 180)); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(window_selector()); + EXPECT_FALSE(overview_session()); EXPECT_TRUE(widget->IsClosed()); } // Verify that if the window item has been flung enough vertically, the window // will be closed. -TEST_F(SplitViewWindowSelectorTest, FlingToClose) { +TEST_F(SplitViewOverviewSessionTest, FlingToClose) { // This test requires a widget. std::unique_ptr<views::Widget> widget(CreateTestWidget()); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); - EXPECT_EQ(1u, window_selector()->grid_list_for_testing()[0]->size()); + ASSERT_TRUE(overview_controller()->IsSelecting()); + EXPECT_EQ(1u, overview_session()->grid_list_for_testing()[0]->size()); - WindowSelectorItem* item = - GetWindowItemForWindow(0, widget->GetNativeWindow()); + OverviewItem* item = GetWindowItemForWindow(0, widget->GetNativeWindow()); const gfx::Point start = item->target_bounds().CenterPoint(); ASSERT_TRUE(item); // Verify that items flung horizontally do not close the item. - window_selector()->InitiateDrag(item, start); - window_selector()->Drag(item, start + gfx::Vector2d(0, 50)); - window_selector()->Fling(item, start, 2500, 0); - ASSERT_TRUE(window_selector()); + overview_session()->InitiateDrag(item, start); + overview_session()->Drag(item, start + gfx::Vector2d(0, 50)); + overview_session()->Fling(item, start, 2500, 0); + ASSERT_TRUE(overview_session()); // Verify that items flung vertically but without enough velocity do not // close the item. - window_selector()->InitiateDrag(item, start); - window_selector()->Drag(item, start + gfx::Vector2d(0, 50)); - window_selector()->Fling(item, start, 0, 1500); - ASSERT_TRUE(window_selector()); + overview_session()->InitiateDrag(item, start); + overview_session()->Drag(item, start + gfx::Vector2d(0, 50)); + overview_session()->Fling(item, start, 0, 1500); + ASSERT_TRUE(overview_session()); // Verify that flinging the item closes it, and since it is the last item in // overview mode, overview mode is exited. - window_selector()->InitiateDrag(item, start); - window_selector()->Drag(item, start + gfx::Vector2d(0, 50)); - window_selector()->Fling(item, start, 0, 2500); + overview_session()->InitiateDrag(item, start); + overview_session()->Drag(item, start + gfx::Vector2d(0, 50)); + overview_session()->Fling(item, start, 0, 2500); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(window_selector()); + EXPECT_FALSE(overview_session()); EXPECT_TRUE(widget->IsClosed()); } @@ -2804,7 +2798,7 @@ // and one item which is about to be deleted by dragging. If the item is deleted // we still only have one row, so the other items should nudge while the item is // being dragged. -TEST_F(SplitViewWindowSelectorTest, BasicNudging) { +TEST_F(SplitViewOverviewSessionTest, BasicNudging) { // Set up three equal windows, which take up one row on the overview grid. // When one of them is deleted we are still left with all the windows on one // row. @@ -2813,11 +2807,11 @@ std::unique_ptr<aura::Window> window3 = CreateTestWindow(); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); - WindowSelectorItem* item1 = GetWindowItemForWindow(0, window1.get()); - WindowSelectorItem* item2 = GetWindowItemForWindow(0, window2.get()); - WindowSelectorItem* item3 = GetWindowItemForWindow(0, window3.get()); + OverviewItem* item1 = GetWindowItemForWindow(0, window1.get()); + OverviewItem* item2 = GetWindowItemForWindow(0, window2.get()); + OverviewItem* item3 = GetWindowItemForWindow(0, window3.get()); const gfx::Rect item1_bounds = item1->target_bounds(); const gfx::Rect item2_bounds = item2->target_bounds(); @@ -2825,22 +2819,22 @@ // Drag |item1| vertically. |item2| and |item3| bounds should change as they // should be nudging towards their final bounds. - window_selector()->InitiateDrag(item1, item1_bounds.CenterPoint()); - window_selector()->Drag(item1, - item1_bounds.CenterPoint() + gfx::Vector2d(0, 160)); + overview_session()->InitiateDrag(item1, item1_bounds.CenterPoint()); + overview_session()->Drag(item1, + item1_bounds.CenterPoint() + gfx::Vector2d(0, 160)); EXPECT_NE(item2_bounds, item2->target_bounds()); EXPECT_NE(item3_bounds, item3->target_bounds()); // Drag |item1| back to its start drag location and release, so that it does // not get deleted. - window_selector()->Drag(item1, item1_bounds.CenterPoint()); - window_selector()->CompleteDrag(item1, item1_bounds.CenterPoint()); + overview_session()->Drag(item1, item1_bounds.CenterPoint()); + overview_session()->CompleteDrag(item1, item1_bounds.CenterPoint()); // Drag |item3| vertically. |item1| and |item2| bounds should change as they // should be nudging towards their final bounds. - window_selector()->InitiateDrag(item3, item3_bounds.CenterPoint()); - window_selector()->Drag(item3, - item3_bounds.CenterPoint() + gfx::Vector2d(0, 160)); + overview_session()->InitiateDrag(item3, item3_bounds.CenterPoint()); + overview_session()->Drag(item3, + item3_bounds.CenterPoint() + gfx::Vector2d(0, 160)); EXPECT_NE(item1_bounds, item1->target_bounds()); EXPECT_NE(item2_bounds, item2->target_bounds()); } @@ -2848,7 +2842,7 @@ // Tests that no nudging occurs when the number of rows in overview mode change // if the item to be deleted results in the overview grid to change number of // rows. -TEST_F(SplitViewWindowSelectorTest, NoNudgingWhenNumRowsChange) { +TEST_F(SplitViewOverviewSessionTest, NoNudgingWhenNumRowsChange) { // Set up four equal windows, which would split into two rows in overview // mode. Removing one window would leave us with three windows, which only // takes a single row in overview. @@ -2858,12 +2852,12 @@ std::unique_ptr<aura::Window> window4 = CreateTestWindow(); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); - WindowSelectorItem* item1 = GetWindowItemForWindow(0, window1.get()); - WindowSelectorItem* item2 = GetWindowItemForWindow(0, window2.get()); - WindowSelectorItem* item3 = GetWindowItemForWindow(0, window3.get()); - WindowSelectorItem* item4 = GetWindowItemForWindow(0, window4.get()); + OverviewItem* item1 = GetWindowItemForWindow(0, window1.get()); + OverviewItem* item2 = GetWindowItemForWindow(0, window2.get()); + OverviewItem* item3 = GetWindowItemForWindow(0, window3.get()); + OverviewItem* item4 = GetWindowItemForWindow(0, window4.get()); const gfx::Rect item1_bounds = item1->target_bounds(); const gfx::Rect item2_bounds = item2->target_bounds(); @@ -2872,9 +2866,9 @@ // Drag |item1| past the drag to swipe threshold. None of the other window // bounds should change, as none of them should be nudged. - window_selector()->InitiateDrag(item1, item1_bounds.CenterPoint()); - window_selector()->Drag(item1, - item1_bounds.CenterPoint() + gfx::Vector2d(0, 160)); + overview_session()->InitiateDrag(item1, item1_bounds.CenterPoint()); + overview_session()->Drag(item1, + item1_bounds.CenterPoint() + gfx::Vector2d(0, 160)); EXPECT_EQ(item2_bounds, item2->target_bounds()); EXPECT_EQ(item3_bounds, item3->target_bounds()); EXPECT_EQ(item4_bounds, item4->target_bounds()); @@ -2883,7 +2877,7 @@ // Tests that no nudging occurs when the item to be deleted results in an item // from the previous row to drop down to the current row, thus causing the items // to the right of the item to be shifted right, which is visually unacceptable. -TEST_F(SplitViewWindowSelectorTest, NoNudgingWhenLastItemOnPreviousRowDrops) { +TEST_F(SplitViewOverviewSessionTest, NoNudgingWhenLastItemOnPreviousRowDrops) { // Set up five equal windows, which would split into two rows in overview // mode. Removing one window would cause the rows to rearrange, with the third // item dropping down from the first row to the second row. Create the windows @@ -2895,9 +2889,9 @@ windows[i] = CreateTestWindow(); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); - WindowSelectorItem* items[kWindows]; + OverviewItem* items[kWindows]; gfx::Rect item_bounds[kWindows]; for (int i = 0; i < kWindows; ++i) { items[i] = GetWindowItemForWindow(0, windows[i].get()); @@ -2908,9 +2902,9 @@ // window bounds should change, as none of them should be nudged, because // deleting the fourth item will cause the third item to drop down from the // first row to the second. - window_selector()->InitiateDrag(items[3], item_bounds[3].CenterPoint()); - window_selector()->Drag(items[3], - item_bounds[3].CenterPoint() + gfx::Vector2d(0, 160)); + overview_session()->InitiateDrag(items[3], item_bounds[3].CenterPoint()); + overview_session()->Drag( + items[3], item_bounds[3].CenterPoint() + gfx::Vector2d(0, 160)); EXPECT_EQ(item_bounds[0], items[0]->target_bounds()); EXPECT_EQ(item_bounds[1], items[1]->target_bounds()); EXPECT_EQ(item_bounds[2], items[2]->target_bounds()); @@ -2918,16 +2912,16 @@ // Drag the fourth item back to its start drag location and release, so that // it does not get deleted. - window_selector()->Drag(items[3], item_bounds[3].CenterPoint()); - window_selector()->CompleteDrag(items[3], item_bounds[3].CenterPoint()); + overview_session()->Drag(items[3], item_bounds[3].CenterPoint()); + overview_session()->CompleteDrag(items[3], item_bounds[3].CenterPoint()); // Drag the first item past the drag to swipe threshold. The second and third // items should nudge as expected as there is no item dropping down to their // row. The fourth and fifth items should not nudge as they are in a different // row than the first item. - window_selector()->InitiateDrag(items[0], item_bounds[0].CenterPoint()); - window_selector()->Drag(items[0], - item_bounds[0].CenterPoint() + gfx::Vector2d(0, 160)); + overview_session()->InitiateDrag(items[0], item_bounds[0].CenterPoint()); + overview_session()->Drag( + items[0], item_bounds[0].CenterPoint() + gfx::Vector2d(0, 160)); EXPECT_NE(item_bounds[1], items[1]->target_bounds()); EXPECT_NE(item_bounds[2], items[2]->target_bounds()); EXPECT_EQ(item_bounds[3], items[3]->target_bounds()); @@ -2936,29 +2930,30 @@ // Verify the window grid size changes as expected when dragging items around in // overview mode when split view is enabled. -TEST_F(SplitViewWindowSelectorTest, WindowGridSizeWhileDraggingWithSplitView) { +TEST_F(SplitViewOverviewSessionTest, + OverviewGridSizeWhileDraggingWithSplitView) { // Add three windows and enter overview mode. std::unique_ptr<aura::Window> window1(CreateTestWindow()); std::unique_ptr<aura::Window> window2(CreateTestWindow()); std::unique_ptr<aura::Window> window3(CreateTestWindow()); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); // Select window one and start the drag. const int grid_index = 0; const int window_width = Shell::Get()->GetPrimaryRootWindow()->GetBoundsInScreen().width(); - WindowSelectorItem* selector_item = + OverviewItem* selector_item = GetWindowItemForWindow(grid_index, window1.get()); gfx::Rect selector_item_bounds = selector_item->target_bounds(); gfx::Point start_location(selector_item_bounds.CenterPoint()); - window_selector()->InitiateDrag(selector_item, start_location); + overview_session()->InitiateDrag(selector_item, start_location); // Verify that when dragged to the left, the window grid is located where the // right window of split view mode should be. const gfx::Point left(0, 0); - window_selector()->Drag(selector_item, left); + overview_session()->Drag(selector_item, left); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller()->state()); EXPECT_TRUE(split_view_controller()->left_window() == nullptr); @@ -2967,7 +2962,7 @@ // Verify that when dragged to the right, the window grid is located where the // left window of split view mode should be. const gfx::Point right(window_width, 0); - window_selector()->Drag(selector_item, right); + overview_session()->Drag(selector_item, right); EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller()->state()); EXPECT_TRUE(split_view_controller()->right_window() == nullptr); EXPECT_EQ(GetSplitViewLeftWindowBounds(window1.get()), GetGridBounds()); @@ -2975,33 +2970,33 @@ // Verify that when dragged to the center, the window grid is has the // dimensions of the work area. const gfx::Point center(window_width / 2, 0); - window_selector()->Drag(selector_item, center); + overview_session()->Drag(selector_item, center); EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller()->state()); EXPECT_EQ(GetWorkAreaInScreen(window1.get()), GetGridBounds()); // Snap window1 to the left and initialize dragging for window2. - window_selector()->Drag(selector_item, left); - window_selector()->CompleteDrag(selector_item, left); + overview_session()->Drag(selector_item, left); + overview_session()->CompleteDrag(selector_item, left); ASSERT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller()->state()); ASSERT_EQ(window1.get(), split_view_controller()->left_window()); selector_item = GetWindowItemForWindow(grid_index, window2.get()); selector_item_bounds = selector_item->target_bounds(); start_location = selector_item_bounds.CenterPoint(); - window_selector()->InitiateDrag(selector_item, start_location); + overview_session()->InitiateDrag(selector_item, start_location); // Verify that when there is a snapped window, the window grid bounds remain - // constant despite window selector items being dragged left and right. - window_selector()->Drag(selector_item, left); + // constant despite overview items being dragged left and right. + overview_session()->Drag(selector_item, left); EXPECT_EQ(GetSplitViewRightWindowBounds(window1.get()), GetGridBounds()); - window_selector()->Drag(selector_item, right); + overview_session()->Drag(selector_item, right); EXPECT_EQ(GetSplitViewRightWindowBounds(window1.get()), GetGridBounds()); - window_selector()->Drag(selector_item, center); + overview_session()->Drag(selector_item, center); EXPECT_EQ(GetSplitViewRightWindowBounds(window1.get()), GetGridBounds()); } // Tests dragging a unsnappable window. -TEST_F(SplitViewWindowSelectorTest, DraggingUnsnappableAppWithSplitView) { +TEST_F(SplitViewOverviewSessionTest, DraggingUnsnappableAppWithSplitView) { std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow(); // The grid bounds should be the size of the root window minus the shelf. @@ -3013,37 +3008,37 @@ SubtractRects(root_window_bounds, shelf_bounds); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); // Verify that after dragging the unsnappable window to the left and right, // the window grid bounds do not change. - WindowSelectorItem* selector_item = + OverviewItem* selector_item = GetWindowItemForWindow(0, unsnappable_window.get()); - window_selector()->InitiateDrag(selector_item, - selector_item->target_bounds().CenterPoint()); - window_selector()->Drag(selector_item, gfx::Point(0, 0)); + overview_session()->InitiateDrag( + selector_item, selector_item->target_bounds().CenterPoint()); + overview_session()->Drag(selector_item, gfx::Point(0, 0)); EXPECT_EQ(expected_grid_bounds, GetGridBounds()); - window_selector()->Drag(selector_item, - gfx::Point(root_window_bounds.right(), 0)); + overview_session()->Drag(selector_item, + gfx::Point(root_window_bounds.right(), 0)); EXPECT_EQ(expected_grid_bounds, GetGridBounds()); - window_selector()->Drag(selector_item, - gfx::Point(root_window_bounds.right() / 2, 0)); + overview_session()->Drag(selector_item, + gfx::Point(root_window_bounds.right() / 2, 0)); EXPECT_EQ(expected_grid_bounds, GetGridBounds()); } // Tests that if there is only one window in the MRU window list in the overview // mode, snapping the window to one side of the screen will not end the overview // mode even if there is no more window left in the overview window grid. -TEST_F(SplitViewWindowSelectorTest, EmptyWindowsListNotExitOverview) { +TEST_F(SplitViewOverviewSessionTest, EmptyWindowsListNotExitOverview) { const gfx::Rect bounds(400, 400); std::unique_ptr<aura::Window> window1(CreateWindow(bounds)); ToggleOverview(); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); // Drag |window1| selector item to snap to left. const int grid_index = 0; - WindowSelectorItem* selector_item1 = + OverviewItem* selector_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(selector_item1, gfx::Point(0, 0)); @@ -3051,47 +3046,47 @@ EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), true); EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); // Create a new window should exit the overview mode. std::unique_ptr<aura::Window> window2(CreateWindow(bounds)); ::wm::ActivateWindow(window2.get()); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); EXPECT_EQ(split_view_controller()->state(), SplitViewController::BOTH_SNAPPED); // If there are only 2 snapped windows, close one of them should enter // overview mode. window2.reset(); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); // If there are more than 2 windows in overview std::unique_ptr<aura::Window> window3(CreateWindow(bounds)); std::unique_ptr<aura::Window> window4(CreateWindow(bounds)); ::wm::ActivateWindow(window3.get()); ::wm::ActivateWindow(window4.get()); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); EXPECT_EQ(split_view_controller()->state(), SplitViewController::BOTH_SNAPPED); ToggleOverview(); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); window3.reset(); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); window4.reset(); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); // Test that if there is only 1 snapped window, and no window in the overview // grid, ToggleOverview() can't end overview. ToggleOverview(); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); EndSplitView(); EXPECT_FALSE(Shell::Get()->IsSplitViewModeActive()); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); // Test that ToggleOverview() can end overview if we're not in split view // mode. ToggleOverview(); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); // Now enter overview and split view again. Test that exiting tablet mode can // end split view and overview correctly. @@ -3099,21 +3094,21 @@ selector_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(selector_item1, gfx::Point(0, 0)); EXPECT_TRUE(Shell::Get()->IsSplitViewModeActive()); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false); EXPECT_FALSE(Shell::Get()->IsSplitViewModeActive()); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); // Test that closing all windows in overview can end overview if we're not in // split view mode. ToggleOverview(); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); window1.reset(); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); } // Test the overview window drag functionalities when screen rotates. -TEST_F(SplitViewWindowSelectorTest, SplitViewRotationTest) { +TEST_F(SplitViewOverviewSessionTest, SplitViewRotationTest) { using svc = SplitViewController; UpdateDisplay("807x407"); @@ -3137,14 +3132,14 @@ ToggleOverview(); // Test that dragging |window1| to the left of the screen snaps it to left. const int grid_index = 0; - WindowSelectorItem* selector_item1 = + OverviewItem* selector_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(selector_item1, gfx::Point(0, 0)); EXPECT_EQ(split_view_controller()->state(), svc::LEFT_SNAPPED); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); // Test that dragging |window2| to the right of the screen snaps it to right. - WindowSelectorItem* selector_item2 = + OverviewItem* selector_item2 = GetWindowItemForWindow(grid_index, window2.get()); gfx::Rect work_area_rect = GetWorkAreaInScreen(window2.get()); gfx::Point end_location2(work_area_rect.width(), work_area_rect.height()); @@ -3247,7 +3242,7 @@ // Test that when split view mode and overview mode are both active at the same // time, dragging the split view divider resizes the bounds of snapped window // and the bounds of overview window grids at the same time. -TEST_F(SplitViewWindowSelectorTest, SplitViewOverviewBothActiveTest) { +TEST_F(SplitViewOverviewSessionTest, SplitViewOverviewBothActiveTest) { UpdateDisplay("907x407"); const gfx::Rect bounds(400, 400); @@ -3259,7 +3254,7 @@ // Drag |window1| selector item to snap to left. const int grid_index = 0; - WindowSelectorItem* selector_item1 = + OverviewItem* selector_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(selector_item1, gfx::Point(0, 0)); @@ -3298,13 +3293,13 @@ // Verify that selecting an unsnappable window while in split view works as // intended. -TEST_F(SplitViewWindowSelectorTest, SelectUnsnappableWindowInSplitView) { +TEST_F(SplitViewOverviewSessionTest, SelectUnsnappableWindowInSplitView) { // Create one snappable and one unsnappable window. std::unique_ptr<aura::Window> window = CreateTestWindow(); std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow(); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); // Snap the snappable window to enter split view mode. split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT); @@ -3312,7 +3307,7 @@ // Select the unsnappable window. const int grid_index = 0; - WindowSelectorItem* selector_item = + OverviewItem* selector_item = GetWindowItemForWindow(grid_index, unsnappable_window.get()); ui::test::EventGenerator* generator = GetEventGenerator(); generator->set_current_screen_location( @@ -3322,7 +3317,7 @@ // Verify that we are out of split view and overview mode, and that the active // window is the unsnappable window. EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); EXPECT_EQ(unsnappable_window.get(), wm::GetActiveWindow()); std::unique_ptr<aura::Window> window2 = CreateTestWindow(); @@ -3335,13 +3330,13 @@ EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive()); EXPECT_EQ(SplitViewController::BOTH_SNAPPED, split_view_controller()->state()); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); ToggleOverview(); EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive()); EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller()->state()); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); // Now select the unsnappable window. selector_item = GetWindowItemForWindow(grid_index, unsnappable_window.get()); @@ -3352,13 +3347,13 @@ // Split view mode should be ended. And the unsnappable window should be the // active window now. EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); EXPECT_EQ(unsnappable_window.get(), wm::GetActiveWindow()); } // Verify that when in overview mode, the selector items unsnappable indicator // shows up when expected. -TEST_F(SplitViewWindowSelectorTest, OverviewUnsnappableIndicatorVisibility) { +TEST_F(SplitViewOverviewSessionTest, OverviewUnsnappableIndicatorVisibility) { // Create three windows; two normal and one unsnappable, so that when after // snapping |window1| to enter split view we can test the state of each normal // and unsnappable windows. @@ -3367,12 +3362,12 @@ std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow(); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); const int grid_index = 0; - WindowSelectorItem* snappable_selector_item = + OverviewItem* snappable_selector_item = GetWindowItemForWindow(grid_index, window2.get()); - WindowSelectorItem* unsnappable_selector_item = + OverviewItem* unsnappable_selector_item = GetWindowItemForWindow(grid_index, unsnappable_window.get()); // Note: |cannot_snap_label_view_| and its parent will be created on demand. @@ -3402,7 +3397,7 @@ // Test that when splitview mode and overview mode are both active at the same // time, dragging divider behaviors are correct. -TEST_F(SplitViewWindowSelectorTest, DragDividerToExitTest) { +TEST_F(SplitViewOverviewSessionTest, DragDividerToExitTest) { UpdateDisplay("907x407"); const gfx::Rect bounds(400, 400); @@ -3414,12 +3409,12 @@ // Drag |window1| selector item to snap to left. const int grid_index = 0; - WindowSelectorItem* selector_item1 = + OverviewItem* selector_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(selector_item1, gfx::Point(0, 0)); // Test that overview mode and split view mode are both active. EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Drag the divider toward closing the snapped window. gfx::Rect divider_bounds = GetSplitViewDividerBounds(false /* is_dragging */); @@ -3428,15 +3423,15 @@ // Test that split view mode is ended. Overview mode is still active. EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Now drag |window2| selector item to snap to left. - WindowSelectorItem* selector_item2 = + OverviewItem* selector_item2 = GetWindowItemForWindow(grid_index, window2.get()); DragWindowTo(selector_item2, gfx::Point(0, 0)); // Test that overview mode and split view mode are both active. EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Drag the divider toward closing the overview window grid. divider_bounds = GetSplitViewDividerBounds(false /*is_dragging=*/); @@ -3447,38 +3442,38 @@ // Test that split view mode is ended. Overview mode is also ended. |window2| // should be activated. EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(window2.get(), wm::GetActiveWindow()); } -TEST_F(SplitViewWindowSelectorTest, WindowSelectorItemLongPressed) { +TEST_F(SplitViewOverviewSessionTest, OverviewItemLongPressed) { std::unique_ptr<aura::Window> window1 = CreateTestWindow(); std::unique_ptr<aura::Window> window2 = CreateTestWindow(); ToggleOverview(); - ASSERT_TRUE(window_selector_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->IsSelecting()); - WindowSelectorItem* selector_item = GetWindowItemForWindow(0, window1.get()); + OverviewItem* selector_item = GetWindowItemForWindow(0, window1.get()); gfx::Point start_location(selector_item->target_bounds().CenterPoint()); const gfx::Rect original_bounds(selector_item->target_bounds()); - // Verify that when a window selector item receives a resetting gesture, we + // Verify that when a overview item receives a resetting gesture, we // stay in overview mode and the bounds of the item are the same as they were // before the press sequence started. - window_selector()->InitiateDrag(selector_item, start_location); - window_selector()->ResetDraggedWindowGesture(); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + overview_session()->InitiateDrag(selector_item, start_location); + overview_session()->ResetDraggedWindowGesture(); + EXPECT_TRUE(overview_controller()->IsSelecting()); EXPECT_EQ(original_bounds, selector_item->target_bounds()); - // Verify that when a window selector item is tapped, we exit overview mode, + // Verify that when a overview item is tapped, we exit overview mode, // and the current active window is the item. - window_selector()->InitiateDrag(selector_item, start_location); - window_selector()->ActivateDraggedWindow(); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + overview_session()->InitiateDrag(selector_item, start_location); + overview_session()->ActivateDraggedWindow(); + EXPECT_FALSE(overview_controller()->IsSelecting()); EXPECT_EQ(window1.get(), wm::GetActiveWindow()); } -TEST_F(SplitViewWindowSelectorTest, SnappedWindowBoundsTest) { +TEST_F(SplitViewOverviewSessionTest, SnappedWindowBoundsTest) { const gfx::Rect bounds(400, 400); const int kMinimumBoundSize = 100; const gfx::Size size(kMinimumBoundSize, kMinimumBoundSize); @@ -3495,12 +3490,12 @@ // Drag |window1| selector item to snap to left. const int grid_index = 0; - WindowSelectorItem* selector_item1 = + OverviewItem* selector_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(selector_item1, gfx::Point(0, 0)); EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller()->state()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Then drag the divider to left toward closing the snapped window. gfx::Rect divider_bounds = GetSplitViewDividerBounds(false /*is_dragging=*/); @@ -3511,14 +3506,14 @@ // Test that split view mode is ended. Overview mode is still active. EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Test that |window1| has the dimensions of a tablet mode maxed window, so // that when it is placed back on the grid it will not look skinny. EXPECT_LE(window1->bounds().x(), 0); EXPECT_EQ(window1->bounds().width(), screen_width); // Drag |window2| selector item to snap to right. - WindowSelectorItem* selector_item2 = + OverviewItem* selector_item2 = GetWindowItemForWindow(grid_index, window2.get()); const gfx::Rect work_area_rect = GetWorkAreaInScreen(window2.get()); gfx::Point end_location2 = @@ -3526,7 +3521,7 @@ DragWindowTo(selector_item2, end_location2); EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, split_view_controller()->state()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Then drag the divider to right toward closing the snapped window. divider_bounds = GetSplitViewDividerBounds(false /* is_dragging */); @@ -3538,7 +3533,7 @@ // Test that split view mode is ended. Overview mode is still active. EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Test that |window2| has the dimensions of a tablet mode maxed window, so // that when it is placed back on the grid it will not look skinny. EXPECT_GE(window2->bounds().x(), 0); @@ -3548,7 +3543,7 @@ // Verify that if the split view divider is dragged all the way to the edge, the // window being dragged gets returned to the overview list, if overview mode is // still active. -TEST_F(SplitViewWindowSelectorTest, +TEST_F(SplitViewOverviewSessionTest, DividerDraggedToEdgeReturnsWindowToOverviewList) { const gfx::Rect bounds(400, 400); std::unique_ptr<aura::Window> window1(CreateWindow(bounds)); @@ -3559,7 +3554,7 @@ // Drag |window1| selector item to snap to left. There should be two items on // the overview grid afterwards, |window2| and |window3|. const int grid_index = 0; - WindowSelectorItem* selector_item1 = + OverviewItem* selector_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(selector_item1, gfx::Point(0, 0)); EXPECT_EQ(SplitViewController::LEFT_SNAPPED, @@ -3568,7 +3563,7 @@ EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive()); ASSERT_TRUE(split_view_controller()->split_view_divider()); std::vector<aura::Window*> window_list = - window_selector_controller()->GetWindowsListInOverviewGridsForTesting(); + overview_controller()->GetWindowsListInOverviewGridsForTesting(); EXPECT_EQ(2u, window_list.size()); EXPECT_FALSE(base::ContainsValue(window_list, window1.get())); EXPECT_TRUE(wm::IsActiveWindow(window1.get())); @@ -3585,7 +3580,7 @@ EXPECT_TRUE(IsSelecting()); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); window_list = - window_selector_controller()->GetWindowsListInOverviewGridsForTesting(); + overview_controller()->GetWindowsListInOverviewGridsForTesting(); EXPECT_EQ(3u, window_list.size()); EXPECT_TRUE(base::ContainsValue(window_list, window1.get())); EXPECT_FALSE(wm::IsActiveWindow(window1.get())); @@ -3594,7 +3589,7 @@ // Verify that if the split view divider is dragged close to the edge, the grid // bounds will be fixed to a third of the work area width and start sliding off // the screen instead of continuing to shrink. -TEST_F(SplitViewWindowSelectorTest, +TEST_F(SplitViewOverviewSessionTest, OverviewHasMinimumBoundsWhenDividerDragged) { UpdateDisplay("600x400"); @@ -3607,7 +3602,7 @@ // edge of the screen. Shell::Get()->split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); - WindowGrid* grid = window_selector()->grid_list_for_testing()[0].get(); + OverviewGrid* grid = overview_session()->grid_list_for_testing()[0].get(); ASSERT_TRUE(grid); // Drag the divider to the right edge. @@ -3631,7 +3626,7 @@ // edge of the screen. Shell::Get()->split_view_controller()->SnapWindow(window1.get(), SplitViewController::RIGHT); - grid = window_selector()->grid_list_for_testing()[0].get(); + grid = overview_session()->grid_list_for_testing()[0].get(); ASSERT_TRUE(grid); // Drag the divider to the left edge. @@ -3650,7 +3645,7 @@ // Test that when splitview mode is active, minimizing one of the snapped window // will insert the minimized window back to overview mode if overview mode is // active at the moment. -TEST_F(SplitViewWindowSelectorTest, InsertMinimizedWindowBackToOverview) { +TEST_F(SplitViewOverviewSessionTest, InsertMinimizedWindowBackToOverview) { const gfx::Rect bounds(400, 400); std::unique_ptr<aura::Window> window1(CreateWindow(bounds)); std::unique_ptr<aura::Window> window2(CreateWindow(bounds)); @@ -3658,7 +3653,7 @@ ToggleOverview(); const int grid_index = 0; - WindowSelectorItem* selector_item1 = + OverviewItem* selector_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(selector_item1, gfx::Point(0, 0)); EXPECT_EQ(split_view_controller()->state(), @@ -3701,7 +3696,7 @@ // Test that when splitview and overview are both active at the same time, if // overview is ended due to snapping a window in splitview, the tranform of each // window in the overview grid is restored. -TEST_F(SplitViewWindowSelectorTest, SnappedWindowAnimationObserverTest) { +TEST_F(SplitViewOverviewSessionTest, SnappedWindowAnimationObserverTest) { const gfx::Rect bounds(400, 400); std::unique_ptr<aura::Window> window1(CreateWindow(bounds)); std::unique_ptr<aura::Window> window2(CreateWindow(bounds)); @@ -3718,13 +3713,13 @@ EXPECT_FALSE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity()); const int grid_index = 0; - WindowSelectorItem* selector_item1 = + OverviewItem* selector_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(selector_item1, gfx::Point(0, 0)); EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller()->state()); // Drag |window2| to snap to right. - WindowSelectorItem* selector_item2 = + OverviewItem* selector_item2 = GetWindowItemForWindow(grid_index, window2.get()); const gfx::Rect work_area_rect = screen_util::GetDisplayWorkAreaBoundsInScreenForDefaultContainer( @@ -3733,7 +3728,7 @@ DragWindowTo(selector_item2, end_location2); EXPECT_EQ(SplitViewController::BOTH_SNAPPED, split_view_controller()->state()); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity()); @@ -3751,7 +3746,7 @@ ToggleOverview(); EXPECT_EQ(SplitViewController::BOTH_SNAPPED, split_view_controller()->state()); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity()); @@ -3766,7 +3761,7 @@ ::wm::ActivateWindow(window2.get()); EXPECT_EQ(SplitViewController::BOTH_SNAPPED, split_view_controller()->state()); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity()); @@ -3782,7 +3777,7 @@ ::wm::ActivateWindow(window4.get()); EXPECT_EQ(SplitViewController::BOTH_SNAPPED, split_view_controller()->state()); - EXPECT_FALSE(window_selector_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->IsSelecting()); EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity()); @@ -3792,21 +3787,21 @@ // Test that when split view and overview are both active at the same time, // double tapping on the divider can swap the window's position with the // overview window grid's postion. -TEST_F(SplitViewWindowSelectorTest, SwapWindowAndOverviewGrid) { +TEST_F(SplitViewOverviewSessionTest, SwapWindowAndOverviewGrid) { const gfx::Rect bounds(0, 0, 400, 400); std::unique_ptr<aura::Window> window1(CreateWindow(bounds)); std::unique_ptr<aura::Window> window2(CreateWindow(bounds)); ToggleOverview(); const int grid_index = 0; - WindowSelectorItem* selector_item1 = + OverviewItem* selector_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(selector_item1, gfx::Point(0, 0)); EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); EXPECT_EQ(split_view_controller()->default_snap_position(), SplitViewController::LEFT); - EXPECT_TRUE(window_selector_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->IsSelecting()); EXPECT_EQ(GetGridBounds(), split_view_controller()->GetSnappedWindowBoundsInScreen( window1.get(), SplitViewController::RIGHT)); @@ -3823,7 +3818,7 @@ // Verify the behavior when trying to exit overview with one snapped window // is as expected. -TEST_F(SplitViewWindowSelectorTest, ExitOverviewWithOneSnapped) { +TEST_F(SplitViewOverviewSessionTest, ExitOverviewWithOneSnapped) { std::unique_ptr<aura::Window> window(CreateWindow(gfx::Rect(400, 400))); // Tests that we cannot exit overview when there is one snapped window and no @@ -3834,7 +3829,7 @@ ASSERT_TRUE(IsSelecting()); // Tests that we can exit overview if we swipe up from the shelf. - ToggleOverview(WindowSelector::EnterExitOverviewType::kSwipeFromShelf); + ToggleOverview(OverviewSession::EnterExitOverviewType::kSwipeFromShelf); EXPECT_FALSE(IsSelecting()); }
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc index b3202dc..15dc7cb 100644 --- a/ash/wm/overview/overview_utils.cc +++ b/ash/wm/overview/overview_utils.cc
@@ -12,9 +12,9 @@ #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" #include "ash/wm/overview/cleanup_animation_observer.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/overview/scoped_overview_animation_settings.h" #include "ash/wm/overview/start_animation_observer.h" -#include "ash/wm/overview/window_selector_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_utils.h" #include "ash/wm/window_state.h" @@ -142,7 +142,7 @@ auto start_observer = std::make_unique<StartAnimationObserver>(); scoped_overview_animation_settings.AddObserver(start_observer.get()); - Shell::Get()->window_selector_controller()->AddStartAnimationObserver( + Shell::Get()->overview_controller()->AddStartAnimationObserver( std::move(start_observer)); } } @@ -151,8 +151,7 @@ OverviewAnimationType animation_type, bool slide) { // The window selector controller may be nullptr on shutdown. - WindowSelectorController* controller = - Shell::Get()->window_selector_controller(); + OverviewController* controller = Shell::Get()->overview_controller(); if (!controller) { widget->SetOpacity(0.f); return; @@ -291,7 +290,7 @@ } bool IsSlidingOutOverviewFromShelf() { - if (!Shell::Get()->window_selector_controller()->IsSelecting()) + if (!Shell::Get()->overview_controller()->IsSelecting()) return false; HomeLauncherGestureHandler* home_launcher_gesture_handler =
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc index cd61b33..f9d34fbff 100644 --- a/ash/wm/overview/overview_window_drag_controller.cc +++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -8,10 +8,10 @@ #include "ash/screen_util.h" #include "ash/shell.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_item.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/overview/overview_utils.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_item.h" #include "ash/wm/splitview/split_view_constants.h" #include "ash/wm/splitview/split_view_drag_indicators.h" #include "ash/wm/splitview/split_view_utils.h" @@ -47,14 +47,14 @@ } // namespace OverviewWindowDragController::OverviewWindowDragController( - WindowSelector* window_selector) - : window_selector_(window_selector), + OverviewSession* overview_session) + : overview_session_(overview_session), split_view_controller_(Shell::Get()->split_view_controller()) {} OverviewWindowDragController::~OverviewWindowDragController() = default; void OverviewWindowDragController::InitiateDrag( - WindowSelectorItem* item, + OverviewItem* item, const gfx::Point& location_in_screen) { item_ = item; previous_event_location_ = location_in_screen; @@ -79,7 +79,7 @@ if (std::abs(distance.x()) < std::abs(distance.y())) { current_drag_behavior_ = DragBehavior::kDragToClose; original_opacity_ = item_->GetOpacity(); - window_selector_->GetGridWithRootWindow(item_->root_window()) + overview_session_->GetGridWithRootWindow(item_->root_window()) ->StartNudge(item_); did_move_ = true; } else if (ShouldAllowSplitView()) { @@ -95,7 +95,7 @@ float val = std::abs(static_cast<float>(location_in_screen.y()) - initial_event_location_.y()) / kDragToCloseDistanceThresholdDp; - window_selector_->GetGridWithRootWindow(item_->root_window()) + overview_session_->GetGridWithRootWindow(item_->root_window()) ->UpdateNudge(item_, val); val = base::ClampToRange(val, 0.f, 1.f); float opacity = original_opacity_; @@ -103,7 +103,7 @@ opacity = original_opacity_ - val * (original_opacity_ - kItemMinOpacity); item_->SetOpacity(opacity); } else if (current_drag_behavior_ == DragBehavior::kDragToSnap) { - UpdateDragIndicatorsAndWindowGrid(location_in_screen); + UpdateDragIndicatorsAndOverviewGrid(location_in_screen); x_offset = location_in_screen.x() - previous_event_location_.x(); } @@ -135,8 +135,8 @@ // Update window grid bounds and |snap_position_| in case the screen // orientation was changed. if (current_drag_behavior_ == DragBehavior::kDragToSnap) { - UpdateDragIndicatorsAndWindowGrid(location_in_screen); - window_selector_->SetSplitViewDragIndicatorsIndicatorState( + UpdateDragIndicatorsAndOverviewGrid(location_in_screen); + overview_session_->SetSplitViewDragIndicatorsIndicatorState( IndicatorState::kNone, gfx::Point()); } @@ -146,14 +146,14 @@ // If we are in drag to close mode close the window if it has been dragged // enough, otherwise reposition it and set its opacity back to its original // value. - window_selector_->GetGridWithRootWindow(item_->root_window())->EndNudge(); + overview_session_->GetGridWithRootWindow(item_->root_window())->EndNudge(); if (std::abs((location_in_screen - initial_event_location_).y()) > kDragToCloseDistanceThresholdDp) { item_->AnimateAndCloseWindow( (location_in_screen - initial_event_location_).y() < 0); } else { item_->SetOpacity(original_opacity_); - window_selector_->PositionWindows(/*animate=*/true); + overview_session_->PositionWindows(/*animate=*/true); } } else if (current_drag_behavior_ == DragBehavior::kDragToSnap) { // If the window was dragged around but should not be snapped, move it back @@ -161,7 +161,7 @@ if (!ShouldUpdateDragIndicatorsOrSnap(location_in_screen) || snap_position_ == SplitViewController::NONE) { item_->set_should_restack_on_animation_end(true); - window_selector_->PositionWindows(/*animate=*/true); + overview_session_->PositionWindows(/*animate=*/true); } else { SnapWindow(snap_position_); } @@ -180,7 +180,7 @@ did_move_ = true; current_drag_behavior_ = DragBehavior::kDragToSnap; - window_selector_->SetSplitViewDragIndicatorsIndicatorState( + overview_session_->SetSplitViewDragIndicatorsIndicatorState( CanSnapInSplitview(item_->GetWindow()) ? IndicatorState::kDragArea : IndicatorState::kCannotSnap, location_in_screen); @@ -220,23 +220,23 @@ // the selected window, and also exit the overview. SplitViewController::State split_state = split_view_controller_->state(); if (!ShouldAllowSplitView() || split_state == SplitViewController::NO_SNAP) { - window_selector_->SelectWindow(item_); + overview_session_->SelectWindow(item_); } else if (CanSnapInSplitview(item_->GetWindow())) { SnapWindow(split_state == SplitViewController::LEFT_SNAPPED ? SplitViewController::RIGHT : SplitViewController::LEFT); } else { split_view_controller_->EndSplitView(); - window_selector_->SelectWindow(item_); + overview_session_->SelectWindow(item_); split_view_controller_->ShowAppCannotSnapToast(); } current_drag_behavior_ = DragBehavior::kNoDrag; } void OverviewWindowDragController::ResetGesture() { - window_selector_->PositionWindows(/*animate=*/true); + overview_session_->PositionWindows(/*animate=*/true); if (ShouldAllowSplitView()) { - window_selector_->SetSplitViewDragIndicatorsIndicatorState( + overview_session_->SetSplitViewDragIndicatorsIndicatorState( IndicatorState::kNone, gfx::Point()); } // This function gets called after a long press release, which bypasses @@ -245,11 +245,11 @@ current_drag_behavior_ = DragBehavior::kNoDrag; } -void OverviewWindowDragController::ResetWindowSelector() { - window_selector_ = nullptr; +void OverviewWindowDragController::ResetOverviewSession() { + overview_session_ = nullptr; } -void OverviewWindowDragController::UpdateDragIndicatorsAndWindowGrid( +void OverviewWindowDragController::UpdateDragIndicatorsAndOverviewGrid( const gfx::Point& location_in_screen) { DCHECK(ShouldAllowSplitView()); if (!ShouldUpdateDragIndicatorsOrSnap(location_in_screen)) @@ -270,14 +270,14 @@ if (split_view_controller_->state() == SplitViewController::NO_SNAP && snap_position_ != last_snap_position) { // Do not reposition the item that is currently being dragged. - window_selector_->SetBoundsForWindowGridsInScreenIgnoringWindow( + overview_session_->SetBoundsForOverviewGridsInScreenIgnoringWindow( GetGridBounds(snap_position_), item_); } // Show the cannot snap ui on the split view drag indicators if the window // cannot be snapped, otherwise show the drag ui. if (snap_position_ == SplitViewController::NONE) { - window_selector_->SetSplitViewDragIndicatorsIndicatorState( + overview_session_->SetSplitViewDragIndicatorsIndicatorState( CanSnapInSplitview(item_->GetWindow()) ? IndicatorState::kDragArea : IndicatorState::kCannotSnap, gfx::Point()); @@ -286,7 +286,7 @@ // Display the preview area on the split view drag indicators. The split // view drag indicators will calculate the preview area bounds. - window_selector_->SetSplitViewDragIndicatorsIndicatorState( + overview_session_->SetSplitViewDragIndicatorsIndicatorState( snap_position_ == SplitViewController::LEFT ? IndicatorState::kPreviewAreaLeft : IndicatorState::kPreviewAreaRight,
diff --git a/ash/wm/overview/overview_window_drag_controller.h b/ash/wm/overview/overview_window_drag_controller.h index 9b748049..e497c6d 100644 --- a/ash/wm/overview/overview_window_drag_controller.h +++ b/ash/wm/overview/overview_window_drag_controller.h
@@ -14,8 +14,8 @@ namespace ash { -class WindowSelector; -class WindowSelectorItem; +class OverviewItem; +class OverviewSession; // The drag controller for an overview window item in overview mode. It updates // the position of the corresponding window item using transform while dragging. @@ -34,11 +34,10 @@ // requirements. }; - explicit OverviewWindowDragController(WindowSelector* window_selector); + explicit OverviewWindowDragController(OverviewSession* overview_session); ~OverviewWindowDragController(); - void InitiateDrag(WindowSelectorItem* item, - const gfx::Point& location_in_screen); + void InitiateDrag(OverviewItem* item, const gfx::Point& location_in_screen); void Drag(const gfx::Point& location_in_screen); void CompleteDrag(const gfx::Point& location_in_screen); void StartSplitViewDragMode(const gfx::Point& location_in_screen); @@ -48,19 +47,20 @@ void ActivateDraggedWindow(); void ResetGesture(); - // Resets |window_selector_| to nullptr. It's needed since we defer the - // deletion of OverviewWindowDragController in WindowSelector destructor and - // we need to reset |window_selector_| to nullptr to avoid null pointer + // Resets |overview_session_| to nullptr. It's needed since we defer the + // deletion of OverviewWindowDragController in Overview destructor and + // we need to reset |overview_session_| to nullptr to avoid null pointer // dereference. - void ResetWindowSelector(); + void ResetOverviewSession(); - WindowSelectorItem* item() { return item_; } + OverviewItem* item() { return item_; } DragBehavior current_drag_behavior() { return current_drag_behavior_; } private: // Updates visuals for the user while dragging items around. - void UpdateDragIndicatorsAndWindowGrid(const gfx::Point& location_in_screen); + void UpdateDragIndicatorsAndOverviewGrid( + const gfx::Point& location_in_screen); // Dragged items should not attempt to update the indicators or snap if // the drag started in a snap region and has not been dragged pass the @@ -75,12 +75,12 @@ void SnapWindow(SplitViewController::SnapPosition snap_position); - WindowSelector* window_selector_; + OverviewSession* overview_session_; SplitViewController* split_view_controller_; // The drag target window in the overview mode. - WindowSelectorItem* item_ = nullptr; + OverviewItem* item_ = nullptr; DragBehavior current_drag_behavior_ = DragBehavior::kNoDrag;
diff --git a/ash/wm/overview/scoped_hide_overview_windows.cc b/ash/wm/overview/scoped_overview_hide_windows.cc similarity index 75% rename from ash/wm/overview/scoped_hide_overview_windows.cc rename to ash/wm/overview/scoped_overview_hide_windows.cc index cc53bde..ec47bf60 100644 --- a/ash/wm/overview/scoped_hide_overview_windows.cc +++ b/ash/wm/overview/scoped_overview_hide_windows.cc
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/overview/scoped_hide_overview_windows.h" +#include "ash/wm/overview/scoped_overview_hide_windows.h" #include "base/logging.h" #include "ui/aura/window.h" namespace ash { -ScopedHideOverviewWindows::ScopedHideOverviewWindows( +ScopedOverviewHideWindows::ScopedOverviewHideWindows( const std::vector<aura::Window*>& windows) { for (auto* window : windows) { window->AddObserver(this); @@ -18,7 +18,7 @@ } } -ScopedHideOverviewWindows::~ScopedHideOverviewWindows() { +ScopedOverviewHideWindows::~ScopedOverviewHideWindows() { for (auto iter = window_visibility_.begin(); iter != window_visibility_.end(); iter++) { iter->first->RemoveObserver(this); @@ -27,11 +27,11 @@ } } -void ScopedHideOverviewWindows::OnWindowDestroying(aura::Window* window) { +void ScopedOverviewHideWindows::OnWindowDestroying(aura::Window* window) { window_visibility_.erase(window); } -void ScopedHideOverviewWindows::OnWindowVisibilityChanged(aura::Window* window, +void ScopedOverviewHideWindows::OnWindowVisibilityChanged(aura::Window* window, bool visible) { // It's expected that windows hidden in overview should not make them visible // without exiting overview.
diff --git a/ash/wm/overview/scoped_hide_overview_windows.h b/ash/wm/overview/scoped_overview_hide_windows.h similarity index 61% rename from ash/wm/overview/scoped_hide_overview_windows.h rename to ash/wm/overview/scoped_overview_hide_windows.h index 080aed5..3ccf08e 100644 --- a/ash/wm/overview/scoped_hide_overview_windows.h +++ b/ash/wm/overview/scoped_overview_hide_windows.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_WM_OVERVIEW_SCOPED_HIDE_OVERVIEW_WINDOWS_ -#define ASH_WM_OVERVIEW_SCOPED_HIDE_OVERVIEW_WINDOWS_ +#ifndef ASH_WM_OVERVIEW_SCOPED_OVERVIEW_HIDE_WINDOWS_H_ +#define ASH_WM_OVERVIEW_SCOPED_OVERVIEW_HIDE_WINDOWS_H_ #include <map> #include <vector> @@ -18,23 +18,23 @@ namespace ash { -// ScopedHideOverviewWindows hides the list of windows in overview mode, +// ScopedOverviewHideWindows hides the list of windows in overview mode, // remembers their visibility and recovers the visibility after overview mode. -class ASH_EXPORT ScopedHideOverviewWindows : public aura::WindowObserver { +class ASH_EXPORT ScopedOverviewHideWindows : public aura::WindowObserver { public: // |windows| the list of windows to hide in overview mode. - explicit ScopedHideOverviewWindows(const std::vector<aura::Window*>& windows); - ~ScopedHideOverviewWindows() override; + explicit ScopedOverviewHideWindows(const std::vector<aura::Window*>& windows); + ~ScopedOverviewHideWindows() override; - // WindowObserver overrides. + // aura::WindowObserver: void OnWindowDestroying(aura::Window* window) override; void OnWindowVisibilityChanged(aura::Window* window, bool visible) override; private: std::map<aura::Window*, bool> window_visibility_; - DISALLOW_COPY_AND_ASSIGN(ScopedHideOverviewWindows); + DISALLOW_COPY_AND_ASSIGN(ScopedOverviewHideWindows); }; } // namespace ash -#endif // ASH_WM_OVERVIEW_SCOPED_HIDE_OVERVIEW_WINDOWS_ \ No newline at end of file +#endif // ASH_WM_OVERVIEW_SCOPED_OVERVIEW_HIDE_WINDOWS_H_ \ No newline at end of file
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_overview_transform_window.cc similarity index 84% rename from ash/wm/overview/scoped_transform_overview_window.cc rename to ash/wm/overview/scoped_overview_transform_window.cc index 4ed28bb3..74cb64a 100644 --- a/ash/wm/overview/scoped_transform_overview_window.cc +++ b/ash/wm/overview/scoped_overview_transform_window.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/overview/scoped_transform_overview_window.h" +#include "ash/wm/overview/scoped_overview_transform_window.h" #include <algorithm> @@ -11,13 +11,13 @@ #include "ash/shell.h" #include "ash/wm/overview/cleanup_animation_observer.h" #include "ash/wm/overview/overview_constants.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_item.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/overview/overview_utils.h" #include "ash/wm/overview/scoped_overview_animation_settings.h" #include "ash/wm/overview/start_animation_observer.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_item.h" #include "ash/wm/window_preview_view.h" #include "ash/wm/window_state.h" #include "ash/wm/window_transient_descendant_iterator.h" @@ -50,26 +50,26 @@ // Delay closing window to allow it to shrink and fade out. constexpr int kCloseWindowDelayInMilliseconds = 150; -ScopedTransformOverviewWindow::GridWindowFillMode GetWindowDimensionsType( +ScopedOverviewTransformWindow::GridWindowFillMode GetWindowDimensionsType( aura::Window* window) { if (window->bounds().width() > window->bounds().height() * - ScopedTransformOverviewWindow::kExtremeWindowRatioThreshold) { - return ScopedTransformOverviewWindow::GridWindowFillMode::kLetterBoxed; + ScopedOverviewTransformWindow::kExtremeWindowRatioThreshold) { + return ScopedOverviewTransformWindow::GridWindowFillMode::kLetterBoxed; } if (window->bounds().height() > window->bounds().width() * - ScopedTransformOverviewWindow::kExtremeWindowRatioThreshold) { - return ScopedTransformOverviewWindow::GridWindowFillMode::kPillarBoxed; + ScopedOverviewTransformWindow::kExtremeWindowRatioThreshold) { + return ScopedOverviewTransformWindow::GridWindowFillMode::kPillarBoxed; } - return ScopedTransformOverviewWindow::GridWindowFillMode::kNormal; + return ScopedOverviewTransformWindow::GridWindowFillMode::kNormal; } } // namespace -class ScopedTransformOverviewWindow::LayerCachingAndFilteringObserver +class ScopedOverviewTransformWindow::LayerCachingAndFilteringObserver : public ui::LayerObserver { public: LayerCachingAndFilteringObserver(ui::Layer* layer) : layer_(layer) { @@ -99,7 +99,7 @@ // WindowMask is applied to overview windows to give them rounded edges while // they are in overview mode. -class ScopedTransformOverviewWindow::WindowMask : public ui::LayerDelegate, +class ScopedOverviewTransformWindow::WindowMask : public ui::LayerDelegate, public aura::WindowObserver { public: explicit WindowMask(aura::Window* window) @@ -169,8 +169,8 @@ DISALLOW_COPY_AND_ASSIGN(WindowMask); }; -ScopedTransformOverviewWindow::ScopedTransformOverviewWindow( - WindowSelectorItem* selector_item, +ScopedOverviewTransformWindow::ScopedOverviewTransformWindow( + OverviewItem* selector_item, aura::Window* window) : selector_item_(selector_item), window_(window), @@ -183,7 +183,7 @@ null_targeter_ = window_->targeter(); } -ScopedTransformOverviewWindow::~ScopedTransformOverviewWindow() { +ScopedOverviewTransformWindow::~ScopedOverviewTransformWindow() { if (null_targeter_ == window_->targeter()) window_->SetEventTargeter(std::move(original_targeter_)); @@ -191,7 +191,7 @@ } // static -float ScopedTransformOverviewWindow::GetItemScale(const gfx::Size& source, +float ScopedOverviewTransformWindow::GetItemScale(const gfx::Size& source, const gfx::Size& target, int top_view_inset, int title_height) { @@ -200,7 +200,7 @@ } // static -gfx::Transform ScopedTransformOverviewWindow::GetTransformForRect( +gfx::Transform ScopedOverviewTransformWindow::GetTransformForRect( const gfx::Rect& src_rect, const gfx::Rect& dst_rect) { DCHECK(!src_rect.IsEmpty()); @@ -211,7 +211,7 @@ return transform; } -void ScopedTransformOverviewWindow::RestoreWindow(bool reset_transform, +void ScopedOverviewTransformWindow::RestoreWindow(bool reset_transform, bool use_slide_animation) { // Shadow controller may be null on shutdown. if (Shell::Get()->shadow_controller()) @@ -251,7 +251,7 @@ window_->layer()->SetMaskLayer(original_mask_layer_); } -void ScopedTransformOverviewWindow::BeginScopedAnimation( +void ScopedOverviewTransformWindow::BeginScopedAnimation( OverviewAnimationType animation_type, ScopedAnimationSettings* animation_settings) { if (animation_type == OVERVIEW_ANIMATION_NONE) @@ -272,7 +272,7 @@ if (animation_type == OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS_ON_ENTER) { auto start_observer = std::make_unique<StartAnimationObserver>(); settings->AddObserver(start_observer.get()); - Shell::Get()->window_selector_controller()->AddStartAnimationObserver( + Shell::Get()->overview_controller()->AddStartAnimationObserver( std::move(start_observer)); } @@ -285,7 +285,7 @@ } } -bool ScopedTransformOverviewWindow::Contains(const aura::Window* target) const { +bool ScopedOverviewTransformWindow::Contains(const aura::Window* target) const { for (auto* window : wm::GetTransientTreeIterator(window_)) { if (window->Contains(target)) return true; @@ -294,11 +294,11 @@ return mirror && mirror->Contains(target); } -gfx::Rect ScopedTransformOverviewWindow::GetTransformedBounds() const { +gfx::Rect ScopedOverviewTransformWindow::GetTransformedBounds() const { return ::ash::GetTransformedBounds(GetOverviewWindow(), GetTopInset()); } -int ScopedTransformOverviewWindow::GetTopInset() const { +int ScopedOverviewTransformWindow::GetTopInset() const { // Mirror window doesn't have insets. if (minimized_widget_) return 0; @@ -313,16 +313,16 @@ return window_->GetProperty(aura::client::kTopViewInset); } -void ScopedTransformOverviewWindow::OnWindowDestroyed() { +void ScopedOverviewTransformWindow::OnWindowDestroyed() { window_ = nullptr; } -void ScopedTransformOverviewWindow::SetOpacity(float opacity) { +void ScopedOverviewTransformWindow::SetOpacity(float opacity) { for (auto* window : wm::GetTransientTreeIterator(GetOverviewWindow())) window->layer()->SetOpacity(opacity); } -void ScopedTransformOverviewWindow::UpdateMirrorWindowForMinimizedState() { +void ScopedOverviewTransformWindow::UpdateMirrorWindowForMinimizedState() { // TODO(oshima): Disable animation. if (window_->GetProperty(aura::client::kShowStateKey) == ui::SHOW_STATE_MINIMIZED) { @@ -337,7 +337,7 @@ } } -gfx::Rect ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio( +gfx::Rect ScopedOverviewTransformWindow::ShrinkRectToFitPreservingAspectRatio( const gfx::Rect& rect, const gfx::Rect& bounds, int top_view_inset, @@ -357,14 +357,14 @@ bounds.y() + vertical_offset, width, height); switch (type()) { - case ScopedTransformOverviewWindow::GridWindowFillMode::kLetterBoxed: - case ScopedTransformOverviewWindow::GridWindowFillMode::kPillarBoxed: { + case ScopedOverviewTransformWindow::GridWindowFillMode::kLetterBoxed: + case ScopedOverviewTransformWindow::GridWindowFillMode::kPillarBoxed: { // Attempt to scale |rect| to fit |bounds|. Maintain the aspect ratio of // |rect|. Letter boxed windows' width will match |bounds|'s height and // pillar boxed windows' height will match |bounds|'s height. const bool is_pillar = type() == - ScopedTransformOverviewWindow::GridWindowFillMode::kPillarBoxed; + ScopedOverviewTransformWindow::GridWindowFillMode::kPillarBoxed; gfx::Rect src = rect; new_bounds = bounds; src.Inset(0, top_view_inset, 0, 0); @@ -382,10 +382,10 @@ if (top_view_inset > 0) new_bounds.Inset(0, -(scale * top_view_inset), 0, 0); - // Save the original bounds minus the title into |window_selector_bounds_| + // Save the original bounds minus the title into |overview_bounds_| // so a larger backdrop can be drawn behind the window after. - window_selector_bounds_ = bounds; - window_selector_bounds_->Inset(0, title_height, 0, 0); + overview_bounds_ = bounds; + overview_bounds_->Inset(0, title_height, 0, 0); break; } default: @@ -395,19 +395,20 @@ return new_bounds; } -void ScopedTransformOverviewWindow::Close() { +void ScopedOverviewTransformWindow::Close() { if (immediate_close_for_tests) { CloseWidget(); return; } base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, base::Bind(&ScopedTransformOverviewWindow::CloseWidget, - weak_ptr_factory_.GetWeakPtr()), + FROM_HERE, + base::BindOnce(&ScopedOverviewTransformWindow::CloseWidget, + weak_ptr_factory_.GetWeakPtr()), base::TimeDelta::FromMilliseconds(kCloseWindowDelayInMilliseconds)); } -void ScopedTransformOverviewWindow::PrepareForOverview() { +void ScopedOverviewTransformWindow::PrepareForOverview() { Shell::Get()->shadow_controller()->UpdateShadowForWindow(window_); DCHECK(!overview_started_); @@ -429,38 +430,38 @@ } } -void ScopedTransformOverviewWindow::CloseWidget() { +void ScopedOverviewTransformWindow::CloseWidget() { aura::Window* parent_window = ::wm::GetTransientRoot(window_); if (parent_window) wm::CloseWidgetForWindow(parent_window); } // static -void ScopedTransformOverviewWindow::SetImmediateCloseForTests() { +void ScopedOverviewTransformWindow::SetImmediateCloseForTests() { immediate_close_for_tests = true; } -aura::Window* ScopedTransformOverviewWindow::GetOverviewWindow() const { +aura::Window* ScopedOverviewTransformWindow::GetOverviewWindow() const { if (minimized_widget_) return GetOverviewWindowForMinimizedState(); return window_; } -void ScopedTransformOverviewWindow::EnsureVisible() { +void ScopedOverviewTransformWindow::EnsureVisible() { original_opacity_ = 1.f; } aura::Window* -ScopedTransformOverviewWindow::GetOverviewWindowForMinimizedState() const { +ScopedOverviewTransformWindow::GetOverviewWindowForMinimizedState() const { return minimized_widget_ ? minimized_widget_->GetNativeWindow() : nullptr; } -void ScopedTransformOverviewWindow::UpdateWindowDimensionsType() { +void ScopedOverviewTransformWindow::UpdateWindowDimensionsType() { type_ = GetWindowDimensionsType(window_); - window_selector_bounds_.reset(); + overview_bounds_.reset(); } -void ScopedTransformOverviewWindow::UpdateMask(bool show) { +void ScopedOverviewTransformWindow::UpdateMask(bool show) { if (!show) { mask_.reset(); return; @@ -478,11 +479,11 @@ layer->SetMaskLayer(mask_->layer()); } -void ScopedTransformOverviewWindow::CancelAnimationsListener() { +void ScopedOverviewTransformWindow::CancelAnimationsListener() { StopObservingImplicitAnimations(); } -void ScopedTransformOverviewWindow::ResizeMinimizedWidgetIfNeeded() { +void ScopedOverviewTransformWindow::ResizeMinimizedWidgetIfNeeded() { if (!minimized_widget_) return; @@ -500,7 +501,7 @@ } } -void ScopedTransformOverviewWindow::UpdateMinimizedWidget() { +void ScopedOverviewTransformWindow::UpdateMinimizedWidget() { if (!minimized_widget_) return; @@ -510,18 +511,18 @@ minimized_widget_->SetContentsView(preview_view); } -void ScopedTransformOverviewWindow::OnImplicitAnimationsCompleted() { +void ScopedOverviewTransformWindow::OnImplicitAnimationsCompleted() { selector_item_->UpdateMaskAndShadow(/*show=*/true); selector_item_->OnDragAnimationCompleted(); } -gfx::Rect ScopedTransformOverviewWindow::GetMaskBoundsForTesting() const { +gfx::Rect ScopedOverviewTransformWindow::GetMaskBoundsForTesting() const { if (!mask_) return gfx::Rect(); return mask_->layer()->bounds(); } -void ScopedTransformOverviewWindow::CreateMirrorWindowForMinimizedState() { +void ScopedOverviewTransformWindow::CreateMirrorWindowForMinimizedState() { DCHECK(!minimized_widget_.get()); views::Widget::InitParams params; params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
diff --git a/ash/wm/overview/scoped_transform_overview_window.h b/ash/wm/overview/scoped_overview_transform_window.h similarity index 86% rename from ash/wm/overview/scoped_transform_overview_window.h rename to ash/wm/overview/scoped_overview_transform_window.h index f15b28b..5ff2c9f 100644 --- a/ash/wm/overview/scoped_transform_overview_window.h +++ b/ash/wm/overview/scoped_overview_transform_window.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_WM_OVERVIEW_SCOPED_TRANSFORM_OVERVIEW_WINDOW_H_ -#define ASH_WM_OVERVIEW_SCOPED_TRANSFORM_OVERVIEW_WINDOW_H_ +#ifndef ASH_WM_OVERVIEW_SCOPED_OVERVIEW_TRANSFORM_WINDOW_H_ +#define ASH_WM_OVERVIEW_SCOPED_OVERVIEW_TRANSFORM_WINDOW_H_ #include <memory> #include <vector> @@ -21,7 +21,7 @@ namespace aura { class Window; class WindowTargeter; -} +} // namespace aura namespace gfx { class Rect; @@ -38,13 +38,13 @@ namespace ash { class ScopedOverviewAnimationSettings; -class WindowSelectorItem; +class OverviewItem; // Manages a window, and its transient children, in the overview mode. This // class allows transforming the windows with a helper to determine the best // fit in certain bounds. The window's state is restored when this object is // destroyed. -class ASH_EXPORT ScopedTransformOverviewWindow +class ASH_EXPORT ScopedOverviewTransformWindow : public ui::ImplicitAnimationObserver { public: // Overview windows have certain properties if their aspect ratio exceedes a @@ -75,9 +75,9 @@ static gfx::Transform GetTransformForRect(const gfx::Rect& src_rect, const gfx::Rect& dst_rect); - ScopedTransformOverviewWindow(WindowSelectorItem* selector_item, + ScopedOverviewTransformWindow(OverviewItem* selector_item, aura::Window* window); - ~ScopedTransformOverviewWindow() override; + ~ScopedOverviewTransformWindow() override; // Starts an animation sequence which will use animation settings specified by // |animation_type|. The |animation_settings| container is populated with @@ -85,8 +85,8 @@ // animation sequence. // // Example: - // ScopedTransformOverviewWindow overview_window(window); - // ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings; + // ScopedOverviewTransformWindow overview_window(window); + // ScopedOverviewTransformWindow::ScopedAnimationSettings animation_settings; // overview_window.BeginScopedAnimation( // OVERVIEW_ANIMATION_SELECTOR_ITEM_SCROLL_CANCEL, // &animation_settings); @@ -111,10 +111,10 @@ // Restores and animates the managed window to its non overview mode state. // If |reset_transform| equals false, the window's transform will not be reset // to identity transform when exiting the overview mode. See - // WindowSelectorItem::RestoreWindow() for details why we need this. + // OverviewItem::RestoreWindow() for details why we need this. void RestoreWindow(bool reset_transform, bool use_slide_animation); - // Informs the ScopedTransformOverviewWindow that the window being watched was + // Informs the ScopedOverviewTransformWindow that the window being watched was // destroyed. This resets the internal window pointer. void OnWindowDestroyed(); @@ -131,7 +131,7 @@ // aspect ratio). Takes into account a window header that is |top_view_inset| // tall in the original window getting replaced by a window caption that is // |title_height| tall in the transformed window. If |type_| is not normal, - // write |window_selector_bounds_|, which would differ than the return bounds. + // write |overview_bounds_|, which would differ than the return bounds. gfx::Rect ShrinkRectToFitPreservingAspectRatio(const gfx::Rect& rect, const gfx::Rect& bounds, int top_view_inset, @@ -141,9 +141,7 @@ GridWindowFillMode type() const { return type_; } - base::Optional<gfx::Rect> window_selector_bounds() const { - return window_selector_bounds_; - } + base::Optional<gfx::Rect> overview_bounds() const { return overview_bounds_; } // Closes the transient root of the window managed by |this|. void Close(); @@ -159,8 +157,8 @@ // does not exist. aura::Window* GetOverviewWindowForMinimizedState() const; - // Called via WindowSelectorItem from WindowGrid when |window_|'s bounds - // change. Must be called before PositionWindows in WindowGrid. + // Called via OverviewItem from OverviewGrid when |window_|'s bounds + // change. Must be called before PositionWindows in OverviewGrid. void UpdateWindowDimensionsType(); // Updates the mask which gives rounded corners on the windows. Shows the mask @@ -185,10 +183,10 @@ gfx::Rect GetMaskBoundsForTesting() const; private: - friend class WindowSelectorTest; + friend class OverviewSessionTest; class LayerCachingAndFilteringObserver; class WindowMask; - FRIEND_TEST_ALL_PREFIXES(ScopedTransformOverviewWindowTest, + FRIEND_TEST_ALL_PREFIXES(ScopedOverviewTransformWindowTest, WindowBoundsChangeTest); // Closes the window managed by |this|. @@ -200,7 +198,7 @@ static void SetImmediateCloseForTests(); // A weak pointer to the window selector item that owns the transform window. - WindowSelectorItem* selector_item_; + OverviewItem* selector_item_; // A weak pointer to the real window in the overview. aura::Window* window_; @@ -219,7 +217,7 @@ // Empty if window is of type normal. Contains the bounds the window selector // item should be if the window is too wide or too tall. - base::Optional<gfx::Rect> window_selector_bounds_; + base::Optional<gfx::Rect> overview_bounds_; // A widget that holds the content for the minimized window. std::unique_ptr<views::Widget> minimized_widget_; @@ -242,15 +240,15 @@ // prevent events from reaching |window_|. // TODO(sammiequon): Investigate if we can use a custom event targeter on // windows for overview mode and remove the need for the extra widget which - // blocks events in WindowSelectorItem. + // blocks events in OverviewItem. std::unique_ptr<aura::WindowTargeter> original_targeter_; aura::WindowTargeter* null_targeter_ = nullptr; - base::WeakPtrFactory<ScopedTransformOverviewWindow> weak_ptr_factory_; + base::WeakPtrFactory<ScopedOverviewTransformWindow> weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(ScopedTransformOverviewWindow); + DISALLOW_COPY_AND_ASSIGN(ScopedOverviewTransformWindow); }; } // namespace ash -#endif // ASH_WM_OVERVIEW_SCOPED_TRANSFORM_OVERVIEW_WINDOW_H_ +#endif // ASH_WM_OVERVIEW_SCOPED_OVERVIEW_TRANSFORM_WINDOW_H_
diff --git a/ash/wm/overview/scoped_transform_overview_window_unittest.cc b/ash/wm/overview/scoped_overview_transform_window_unittest.cc similarity index 86% rename from ash/wm/overview/scoped_transform_overview_window_unittest.cc rename to ash/wm/overview/scoped_overview_transform_window_unittest.cc index e0f7dec..213d95a 100644 --- a/ash/wm/overview/scoped_transform_overview_window_unittest.cc +++ b/ash/wm/overview/scoped_overview_transform_window_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/overview/scoped_transform_overview_window.h" +#include "ash/wm/overview/scoped_overview_transform_window.h" #include "ash/test/ash_test_base.h" #include "ash/wm/window_state.h" @@ -19,13 +19,13 @@ const gfx::Rect& target, int top_view_inset, int title_height) { - return ScopedTransformOverviewWindow::GetItemScale( + return ScopedOverviewTransformWindow::GetItemScale( source.size(), target.size(), top_view_inset, title_height); } } // namespace -using ScopedTransformOverviewWindowTest = AshTestBase; +using ScopedOverviewTransformWindowTest = AshTestBase; // Tests that transformed Rect scaling preserves its aspect ratio. The window // scale is determined by the target height and so the test is actually testing @@ -33,10 +33,10 @@ // floating point values and then safely converted to integers (using ceiled and // floored values where appropriate), the expectations are forgiving (use // *_NEAR) within a single pixel. -TEST_F(ScopedTransformOverviewWindowTest, TransformedRectMaintainsAspect) { +TEST_F(ScopedOverviewTransformWindowTest, TransformedRectMaintainsAspect) { std::unique_ptr<aura::Window> window = CreateTestWindow(gfx::Rect(10, 10, 100, 100)); - ScopedTransformOverviewWindow transform_window(nullptr, window.get()); + ScopedOverviewTransformWindow transform_window(nullptr, window.get()); gfx::Rect rect(50, 50, 200, 400); gfx::Rect bounds(100, 100, 50, 50); @@ -76,10 +76,10 @@ } // Tests that transformed Rect fits in target bounds and is vertically centered. -TEST_F(ScopedTransformOverviewWindowTest, TransformedRectIsCentered) { +TEST_F(ScopedOverviewTransformWindowTest, TransformedRectIsCentered) { std::unique_ptr<aura::Window> window = CreateTestWindow(gfx::Rect(10, 10, 100, 100)); - ScopedTransformOverviewWindow transform_window(nullptr, window.get()); + ScopedOverviewTransformWindow transform_window(nullptr, window.get()); gfx::Rect rect(50, 50, 200, 400); gfx::Rect bounds(100, 100, 50, 50); gfx::Rect transformed_rect = @@ -96,10 +96,10 @@ // Tests that transformed Rect fits in target bounds and is vertically centered // when inset and header height are specified. -TEST_F(ScopedTransformOverviewWindowTest, TransformedRectIsCenteredWithInset) { +TEST_F(ScopedOverviewTransformWindowTest, TransformedRectIsCenteredWithInset) { std::unique_ptr<aura::Window> window = CreateTestWindow(gfx::Rect(10, 10, 100, 100)); - ScopedTransformOverviewWindow transform_window(nullptr, window.get()); + ScopedOverviewTransformWindow transform_window(nullptr, window.get()); gfx::Rect rect(50, 50, 400, 200); gfx::Rect bounds(100, 100, 50, 50); const int inset = 20; @@ -125,13 +125,13 @@ // Verify that a window which will be displayed like a letter box on the window // grid has the correct bounds. -TEST_F(ScopedTransformOverviewWindowTest, TransformingLetteredRect) { +TEST_F(ScopedOverviewTransformWindowTest, TransformingLetteredRect) { // Create a window whose width is more than twice the height. const gfx::Rect original_bounds(10, 10, 300, 100); const int scale = 3; std::unique_ptr<aura::Window> window = CreateTestWindow(original_bounds); - ScopedTransformOverviewWindow transform_window(nullptr, window.get()); - EXPECT_EQ(ScopedTransformOverviewWindow::GridWindowFillMode::kLetterBoxed, + ScopedOverviewTransformWindow transform_window(nullptr, window.get()); + EXPECT_EQ(ScopedOverviewTransformWindow::GridWindowFillMode::kLetterBoxed, transform_window.type()); // Without any headers, the width should match the target, and the height @@ -159,19 +159,19 @@ // original window selector bounds, minus the header. gfx::Rect selector_bounds = overview_bounds; selector_bounds.Inset(0, overview_header, 0, 0); - ASSERT_TRUE(transform_window.window_selector_bounds().has_value()); - EXPECT_EQ(transform_window.window_selector_bounds().value(), selector_bounds); + ASSERT_TRUE(transform_window.overview_bounds().has_value()); + EXPECT_EQ(transform_window.overview_bounds().value(), selector_bounds); } // Verify that a window which will be displayed like a pillar box on the window // grid has the correct bounds. -TEST_F(ScopedTransformOverviewWindowTest, TransformingPillaredRect) { +TEST_F(ScopedOverviewTransformWindowTest, TransformingPillaredRect) { // Create a window whose height is more than twice the width. const gfx::Rect original_bounds(10, 10, 100, 300); const int scale = 3; std::unique_ptr<aura::Window> window = CreateTestWindow(original_bounds); - ScopedTransformOverviewWindow transform_window(nullptr, window.get()); - EXPECT_EQ(ScopedTransformOverviewWindow::GridWindowFillMode::kPillarBoxed, + ScopedOverviewTransformWindow transform_window(nullptr, window.get()); + EXPECT_EQ(ScopedOverviewTransformWindow::GridWindowFillMode::kPillarBoxed, transform_window.type()); // Without any headers, the height should match the target, and the width @@ -198,12 +198,12 @@ // original window selector bounds, minus the header. gfx::Rect selector_bounds = overview_bounds; selector_bounds.Inset(0, overview_header, 0, 0); - ASSERT_TRUE(transform_window.window_selector_bounds().has_value()); - EXPECT_EQ(transform_window.window_selector_bounds().value(), selector_bounds); + ASSERT_TRUE(transform_window.overview_bounds().has_value()); + EXPECT_EQ(transform_window.overview_bounds().value(), selector_bounds); } // Tests the cases when very wide or tall windows enter overview mode. -TEST_F(ScopedTransformOverviewWindowTest, ExtremeWindowBounds) { +TEST_F(ScopedOverviewTransformWindowTest, ExtremeWindowBounds) { // Add three windows which in overview mode will be considered wide, tall and // normal. Window |wide|, with size (400, 160) will be resized to (200, 160) // when the 400x200 is rotated to 200x400, and should be considered a normal @@ -216,13 +216,13 @@ std::unique_ptr<aura::Window> normal = CreateTestWindow(gfx::Rect(10, 10, 200, 200)); - ScopedTransformOverviewWindow scoped_wide(nullptr, wide.get()); - ScopedTransformOverviewWindow scoped_tall(nullptr, tall.get()); - ScopedTransformOverviewWindow scoped_normal(nullptr, normal.get()); + ScopedOverviewTransformWindow scoped_wide(nullptr, wide.get()); + ScopedOverviewTransformWindow scoped_tall(nullptr, tall.get()); + ScopedOverviewTransformWindow scoped_normal(nullptr, normal.get()); // Verify the window dimension type is as expected after entering overview // mode. - using GridWindowFillMode = ScopedTransformOverviewWindow::GridWindowFillMode; + using GridWindowFillMode = ScopedOverviewTransformWindow::GridWindowFillMode; EXPECT_EQ(GridWindowFillMode::kLetterBoxed, scoped_wide.type()); EXPECT_EQ(GridWindowFillMode::kPillarBoxed, scoped_tall.type()); EXPECT_EQ(GridWindowFillMode::kNormal, scoped_normal.type()); @@ -245,11 +245,11 @@ // Verify that if the window's bounds are changed while it's in overview mode, // the rounded edge mask's bounds are also changed accordingly. -TEST_F(ScopedTransformOverviewWindowTest, WindowBoundsChangeTest) { +TEST_F(ScopedOverviewTransformWindowTest, WindowBoundsChangeTest) { UpdateDisplay("400x400"); const gfx::Rect bounds(10, 10, 200, 200); std::unique_ptr<aura::Window> window = CreateTestWindow(bounds); - ScopedTransformOverviewWindow scoped_window(nullptr, window.get()); + ScopedOverviewTransformWindow scoped_window(nullptr, window.get()); scoped_window.UpdateMask(true); EXPECT_TRUE(scoped_window.mask_);
diff --git a/ash/wm/overview/start_animation_observer.cc b/ash/wm/overview/start_animation_observer.cc index 640a80c5..765f7a3 100644 --- a/ash/wm/overview/start_animation_observer.cc +++ b/ash/wm/overview/start_animation_observer.cc
@@ -15,7 +15,7 @@ owner_->RemoveAndDestroyStartAnimationObserver(this); } -void StartAnimationObserver::SetOwner(WindowSelectorDelegate* owner) { +void StartAnimationObserver::SetOwner(OverviewDelegate* owner) { DCHECK(!owner_); owner_ = owner; }
diff --git a/ash/wm/overview/start_animation_observer.h b/ash/wm/overview/start_animation_observer.h index 98382a6..dc4d03a 100644 --- a/ash/wm/overview/start_animation_observer.h +++ b/ash/wm/overview/start_animation_observer.h
@@ -6,7 +6,7 @@ #define ASH_WM_OVERVIEW_START_ANIMATION_OBSERVER_H_ #include "ash/ash_export.h" -#include "ash/wm/overview/window_selector_delegate.h" +#include "ash/wm/overview/overview_delegate.h" #include "base/macros.h" #include "ui/compositor/layer_animation_observer.h" @@ -24,11 +24,11 @@ void OnImplicitAnimationsCompleted() override; // DelayedAnimationObserver: - void SetOwner(WindowSelectorDelegate* owner) override; + void SetOwner(OverviewDelegate* owner) override; void Shutdown() override; private: - WindowSelectorDelegate* owner_ = nullptr; + OverviewDelegate* owner_ = nullptr; DISALLOW_COPY_AND_ASSIGN(StartAnimationObserver); };
diff --git a/ash/wm/overview/start_animation_observer_unittest.cc b/ash/wm/overview/start_animation_observer_unittest.cc index d6ede9c..b13bd3a 100644 --- a/ash/wm/overview/start_animation_observer_unittest.cc +++ b/ash/wm/overview/start_animation_observer_unittest.cc
@@ -7,7 +7,7 @@ #include <vector> #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_selector_delegate.h" +#include "ash/wm/overview/overview_delegate.h" #include "base/containers/unique_ptr_adapters.h" #include "ui/aura/window.h" #include "ui/compositor/scoped_layer_animation_settings.h" @@ -17,13 +17,13 @@ namespace { -class TestWindowSelectorDelegate : public WindowSelectorDelegate { +class TestOverviewDelegate : public OverviewDelegate { public: - TestWindowSelectorDelegate() = default; + TestOverviewDelegate() = default; - ~TestWindowSelectorDelegate() override = default; + ~TestOverviewDelegate() override = default; - // WindowSelectorDelegate: + // OverviewDelegate: void OnSelectionEnded() override {} void AddDelayedAnimationObserver( std::unique_ptr<DelayedAnimationObserver> animation_observer) override {} @@ -44,7 +44,7 @@ private: std::vector<std::unique_ptr<DelayedAnimationObserver>> observers_; - DISALLOW_COPY_AND_ASSIGN(TestWindowSelectorDelegate); + DISALLOW_COPY_AND_ASSIGN(TestOverviewDelegate); }; } // namespace @@ -53,7 +53,7 @@ // Tests that adding a StartAnimationObserver works as intended. TEST_F(StartAnimationObserverTest, Basic) { - TestWindowSelectorDelegate delegate; + TestOverviewDelegate delegate; std::unique_ptr<aura::Window> window = CreateTestWindow(); {
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc index 778ee0a..f7e8b654 100644 --- a/ash/wm/splitview/split_view_controller.cc +++ b/ash/wm/splitview/split_view_controller.cc
@@ -17,10 +17,10 @@ #include "ash/system/toast/toast_data.h" #include "ash/system/toast/toast_manager.h" #include "ash/wm/mru_window_tracker.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_item.h" #include "ash/wm/overview/overview_utils.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_item.h" #include "ash/wm/splitview/split_view_divider.h" #include "ash/wm/splitview/split_view_utils.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" @@ -123,11 +123,11 @@ return wm::GetWindowState(window)->IsSnapped(); } -// Returns the window selector if overview mode is active, otherwise returns +// Returns the overview session if overview mode is active, otherwise returns // nullptr. -WindowSelector* GetWindowSelector() { - return Shell::Get()->window_selector_controller()->IsSelecting() - ? Shell::Get()->window_selector_controller()->window_selector() +OverviewSession* GetOverviewSession() { + return Shell::Get()->overview_controller()->IsSelecting() + ? Shell::Get()->overview_controller()->overview_session() : nullptr; } @@ -477,7 +477,7 @@ // Track the window that needs to be put back into the overview list if we // remain in overview mode. aura::Window* insert_overview_window = nullptr; - if (Shell::Get()->window_selector_controller()->IsSelecting()) + if (Shell::Get()->overview_controller()->IsSelecting()) insert_overview_window = GetDefaultSnappedWindow(); EndSplitView(); if (active_window) { @@ -631,8 +631,8 @@ // will end the overview start animations which will cause the overview focus // window to be activated. aura::Window* overview_focus_window = - GetWindowSelector() ? GetWindowSelector()->GetOverviewFocusWindow() - : nullptr; + GetOverviewSession() ? GetOverviewSession()->GetOverviewFocusWindow() + : nullptr; DCHECK(IsSplitViewModeActive() || (overview_focus_window && overview_focus_window == gained_active)); @@ -690,13 +690,13 @@ } void SplitViewController::OnOverviewModeEnding( - WindowSelector* window_selector) { + OverviewSession* overview_session) { DCHECK(IsSplitViewModeActive()); // Early exit if overview is ended while swiping up on the shelf to avoid // snapping a window or showing a toast. - if (window_selector->enter_exit_overview_type() == - WindowSelector::EnterExitOverviewType::kSwipeFromShelf) { + if (overview_session->enter_exit_overview_type() == + OverviewSession::EnterExitOverviewType::kSwipeFromShelf) { EndSplitView(); return; } @@ -705,12 +705,12 @@ if (state_ == BOTH_SNAPPED) { // If overview is ended because of the window gets snapped, do not do // exiting overview animation. - window_selector->SetWindowListNotAnimatedWhenExiting(root_window); + overview_session->SetWindowListNotAnimatedWhenExiting(root_window); return; } - WindowGrid* current_grid = - window_selector->GetGridWithRootWindow(root_window); + OverviewGrid* current_grid = + overview_session->GetGridWithRootWindow(root_window); if (!current_grid) return; @@ -719,13 +719,13 @@ // grid and snap it. const auto& windows = current_grid->window_list(); if (windows.size() > 0) { - for (const auto& window_selector_item : windows) { - aura::Window* window = window_selector_item->GetWindow(); + for (const auto& overview_item : windows) { + aura::Window* window = overview_item->GetWindow(); if (CanSnapInSplitview(window) && window != GetDefaultSnappedWindow()) { SnapWindow(window, (default_snap_position_ == LEFT) ? RIGHT : LEFT); // If ending overview causes a window to snap, also do not do exiting // overview animation. - window_selector->SetWindowListNotAnimatedWhenExiting(root_window); + overview_session->SetWindowListNotAnimatedWhenExiting(root_window); return; } } @@ -1326,7 +1326,7 @@ const gfx::Rect snapped_bounds = GetSnappedWindowBoundsInScreen( window, (window == left_window_) ? LEFT : RIGHT); const gfx::Transform starting_transform = - ScopedTransformOverviewWindow::GetTransformForRect(snapped_bounds, + ScopedOverviewTransformWindow::GetTransformForRect(snapped_bounds, item_bounds); SetTransformWithAnimation(window, starting_transform, gfx::Transform()); } @@ -1439,17 +1439,16 @@ void SplitViewController::RemoveWindowFromOverviewIfApplicable( aura::Window* window) { - if (!Shell::Get()->window_selector_controller()->IsSelecting()) + if (!Shell::Get()->overview_controller()->IsSelecting()) return; - WindowSelector* window_selector = GetWindowSelector(); - WindowGrid* current_grid = - window_selector->GetGridWithRootWindow(window->GetRootWindow()); + OverviewSession* overview_session = GetOverviewSession(); + OverviewGrid* current_grid = + overview_session->GetGridWithRootWindow(window->GetRootWindow()); if (!current_grid) return; - WindowSelectorItem* item = - current_grid->GetWindowSelectorItemContaining(window); + OverviewItem* item = current_grid->GetOverviewItemContaining(window); if (!item) return; @@ -1458,7 +1457,7 @@ // repositioned in this case as they have been positioned to the right place // during dragging. item->RestoreWindow(/*reset_transform=*/false); - window_selector->RemoveWindowSelectorItem(item, /*reposition=*/false); + overview_session->RemoveOverviewItem(item, /*reposition=*/false); } void SplitViewController::UpdateSnappingWindowTransformedBounds( @@ -1470,19 +1469,19 @@ } void SplitViewController::InsertWindowToOverview(aura::Window* window) { - if (!window || !GetWindowSelector()) + if (!window || !GetOverviewSession()) return; - GetWindowSelector()->AddItem(window, /*reposition=*/true, /*animate=*/true); + GetOverviewSession()->AddItem(window, /*reposition=*/true, /*animate=*/true); } void SplitViewController::StartOverview() { - if (!Shell::Get()->window_selector_controller()->IsSelecting()) - Shell::Get()->window_selector_controller()->ToggleOverview(); + if (!Shell::Get()->overview_controller()->IsSelecting()) + Shell::Get()->overview_controller()->ToggleOverview(); } void SplitViewController::EndOverview() { - if (Shell::Get()->window_selector_controller()->IsSelecting()) - Shell::Get()->window_selector_controller()->ToggleOverview(); + if (Shell::Get()->overview_controller()->IsSelecting()) + Shell::Get()->overview_controller()->ToggleOverview(); } void SplitViewController::FinishWindowResizing(aura::Window* window) { @@ -1508,7 +1507,7 @@ // If dragged window was in overview before or it has been added to overview // window by dropping on the new selector item, do nothing. - if (GetWindowSelector() && GetWindowSelector()->IsWindowInOverview(window)) + if (GetOverviewSession() && GetOverviewSession()->IsWindowInOverview(window)) return; const bool was_splitview_active = IsSplitViewModeActive(); @@ -1528,20 +1527,20 @@ SetTransformWithAnimation(window, window->layer()->GetTargetTransform(), gfx::Transform()); - WindowSelector* window_selector = GetWindowSelector(); - if (window_selector) { - window_selector->SetWindowListNotAnimatedWhenExiting( + OverviewSession* overview_session = GetOverviewSession(); + if (overview_session) { + overview_session->SetWindowListNotAnimatedWhenExiting( window->GetRootWindow()); // Set the overview exit type to kWindowDragged to avoid update bounds // animation of the windows in overview grid. - window_selector->set_enter_exit_overview_type( - WindowSelector::EnterExitOverviewType::kWindowDragged); + overview_session->set_enter_exit_overview_type( + OverviewSession::EnterExitOverviewType::kWindowDragged); } // Activate the dragged window will end the overview at the same time.The // dragged window will be restored back to its previous state before // dragging. wm::ActivateWindow(window); - DCHECK(!Shell::Get()->window_selector_controller()->IsSelecting()); + DCHECK(!Shell::Get()->overview_controller()->IsSelecting()); // Update the dragged window's bounds. It's possible that the dragged // window's bounds was changed during dragging. Update its bounds after
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h index 47a11d6..58fc638 100644 --- a/ash/wm/splitview/split_view_controller.h +++ b/ash/wm/splitview/split_view_controller.h
@@ -35,7 +35,7 @@ class SplitViewControllerTest; class SplitViewDivider; -class SplitViewWindowSelectorTest; +class SplitViewOverviewSessionTest; // The controller for the split view. It snaps a window to left/right side of // the screen. It also observes the two snapped windows and decides when to exit @@ -168,7 +168,7 @@ // ShellObserver: void OnOverviewModeStarting() override; - void OnOverviewModeEnding(WindowSelector* window_selector) override; + void OnOverviewModeEnding(OverviewSession* overview_session) override; // display::DisplayObserver: void OnDisplayMetricsChanged(const display::Display& display, @@ -196,7 +196,7 @@ private: friend class SplitViewControllerTest; - friend class SplitViewWindowSelectorTest; + friend class SplitViewOverviewSessionTest; class TabDraggedWindowObserver; // Start observing |window|.
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc index 969e4c70..dd662de 100644 --- a/ash/wm/splitview/split_view_controller_unittest.cc +++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -22,9 +22,9 @@ #include "ash/wallpaper/wallpaper_controller.h" #include "ash/wm/drag_window_resizer.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_item.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_item.h" #include "ash/wm/splitview/split_view_divider.h" #include "ash/wm/splitview/split_view_drag_indicators.h" #include "ash/wm/splitview/split_view_utils.h" @@ -72,8 +72,8 @@ // Reset the value to true. overview_animate_when_exiting_ = true; } - void OnOverviewModeEnding(WindowSelector* window_selector) override { - WindowGrid* grid = window_selector->GetGridWithRootWindow(root_window_); + void OnOverviewModeEnding(OverviewSession* overview_session) override { + OverviewGrid* grid = overview_session->GetGridWithRootWindow(root_window_); if (!grid) return; overview_animate_when_exiting_ = grid->should_animate_when_exiting(); @@ -141,7 +141,7 @@ void EndSplitView() { split_view_controller()->EndSplitView(); } void ToggleOverview() { - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); } void LongPressOnOverivewButtonTray() { @@ -154,7 +154,7 @@ std::vector<aura::Window*> GetWindowsInOverviewGrids() { return Shell::Get() - ->window_selector_controller() + ->overview_controller() ->GetWindowsListInOverviewGridsForTesting(); } @@ -298,13 +298,13 @@ SplitViewController::RIGHT); // Window grid is showing no recent items, and has no windows, but it is still // available. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Now close the other snapped window. window2.reset(); EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), false); EXPECT_EQ(split_view_controller()->state(), SplitViewController::NO_SNAP); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // 3 - Then test the scenario with more than two windows. std::unique_ptr<aura::Window> window3(CreateWindow(bounds)); @@ -327,14 +327,14 @@ EXPECT_EQ(split_view_controller()->default_snap_position(), SplitViewController::LEFT); // Now overview window grid can be opened. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Close the other snapped window. window3.reset(); EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), false); EXPECT_EQ(split_view_controller()->state(), SplitViewController::NO_SNAP); // Test the overview winow grid should still open. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); } // Tests that if there are two snapped windows, minimizing one of them will open @@ -376,14 +376,14 @@ EXPECT_EQ(split_view_controller()->default_snap_position(), SplitViewController::RIGHT); // The overview window grid will open. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Now minimize the other snapped window. wm::GetWindowState(window2.get())->OnWMEvent(&minimize_event); EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), false); EXPECT_EQ(split_view_controller()->state(), SplitViewController::NO_SNAP); // The overview window grid is still open. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); } // Tests that if one of the snapped window gets maximized / full-screened, the @@ -438,7 +438,7 @@ // Maximize the snapped window will end the split view mode and overview mode. wm::GetWindowState(window1.get())->OnWMEvent(&maximize_event); EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), false); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), true); @@ -449,7 +449,7 @@ // mode. wm::GetWindowState(window1.get())->OnWMEvent(&fullscreen_event); EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), false); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); } // Tests that if split view mode is active, activate another window will snap @@ -505,7 +505,7 @@ // Tests that if split view mode is active when entering overview, the overview // windows grid should show in the non-default side of the screen, and the // default snapped window should not be shown in the overview window grid. -TEST_F(SplitViewControllerTest, EnterOverviewTest) { +TEST_F(SplitViewControllerTest, EnterOverviewModeTest) { const gfx::Rect bounds(0, 0, 400, 400); std::unique_ptr<aura::Window> window1(CreateWindow(bounds)); std::unique_ptr<aura::Window> window2(CreateWindow(bounds)); @@ -762,7 +762,7 @@ // current active window. LongPressOnOverivewButtonTray(); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(window1.get(), wm::GetActiveWindow()); // Snap |window1| to the right. @@ -776,7 +776,7 @@ // current active window. LongPressOnOverivewButtonTray(); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(window1.get(), wm::GetActiveWindow()); // Snap two windows and activate the left window, |window1|. @@ -862,7 +862,7 @@ // current active window. LongPressOnOverivewButtonTray(); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(right_window.get(), wm::GetActiveWindow()); } @@ -875,7 +875,7 @@ wm::ActivateWindow(window1.get()); ToggleOverview(); - ASSERT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); ASSERT_FALSE(split_view_controller()->IsSplitViewModeActive()); // Nothing happens if there is only one window. @@ -887,7 +887,7 @@ std::unique_ptr<aura::Window> window2(CreateWindow(bounds)); wm::ActivateWindow(window2.get()); ToggleOverview(); - ASSERT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); ASSERT_FALSE(split_view_controller()->IsSplitViewModeActive()); LongPressOnOverivewButtonTray(); @@ -1365,11 +1365,11 @@ ToggleOverview(); EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Now new a window. Test it won't end the overview mode std::unique_ptr<aura::Window> window3(CreateWindow(bounds)); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); } // Tests that when split view ends because of a transition from tablet mode to @@ -1569,16 +1569,16 @@ std::unique_ptr<OverviewStatesObserver> overview_observer = std::make_unique<OverviewStatesObserver>(window1->GetRootWindow()); ToggleOverview(); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); ToggleOverview(); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); // 2) If overview is ended because of activating a window: ToggleOverview(); // It will end overview. wm::ActivateWindow(window1.get()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); // 3) If overview is ended because of snapping a window: @@ -1587,21 +1587,21 @@ // to ShellObserver list after SplitViewController. overview_observer.reset(new OverviewStatesObserver(window1->GetRootWindow())); ToggleOverview(); // Start overview. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Test |overview_animate_when_exiting_| has been properly reset. EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_FALSE(overview_observer->overview_animate_when_exiting()); // 4) If ending overview causes a window to snap: ToggleOverview(); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Test |overview_animate_when_exiting_| has been properly reset. EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); ToggleOverview(); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_FALSE(overview_observer->overview_animate_when_exiting()); } @@ -1641,11 +1641,11 @@ split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); ToggleOverview(); EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); wm::ActivateWindow(window3.get()); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); } // Tests that if a snapped window has a bubble transient child, the bubble's @@ -1886,14 +1886,14 @@ } gfx::Rect GetDropTargetBoundsDuringDrag(aura::Window* window) const { - WindowSelector* window_selector = - Shell::Get()->window_selector_controller()->window_selector(); - DCHECK(window_selector); - WindowGrid* current_grid = - window_selector->GetGridWithRootWindow(window->GetRootWindow()); + OverviewSession* overview_session = + Shell::Get()->overview_controller()->overview_session(); + DCHECK(overview_session); + OverviewGrid* current_grid = + overview_session->GetGridWithRootWindow(window->GetRootWindow()); DCHECK(current_grid); - WindowSelectorItem* selector_item = current_grid->GetDropTarget(); + OverviewItem* selector_item = current_grid->GetDropTarget(); return selector_item->GetTransformedBounds(); } @@ -2020,27 +2020,26 @@ std::unique_ptr<aura::Window> window2( CreateWindowWithType(bounds, AppType::BROWSER)); - Shell::Get()->window_selector_controller()->ToggleOverview(); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - WindowSelector* window_selector = - Shell::Get()->window_selector_controller()->window_selector(); - EXPECT_TRUE(window_selector->IsWindowInOverview(window1.get())); - EXPECT_TRUE(window_selector->IsWindowInOverview(window2.get())); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + OverviewSession* overview_session = + Shell::Get()->overview_controller()->overview_session(); + EXPECT_TRUE(overview_session->IsWindowInOverview(window1.get())); + EXPECT_TRUE(overview_session->IsWindowInOverview(window2.get())); + Shell::Get()->overview_controller()->ToggleOverview(); std::unique_ptr<WindowResizer> resizer = StartDrag(window1.get(), window1.get()); // Since the source window is the dragged window, the overview should have // been opened. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - window_selector = - Shell::Get()->window_selector_controller()->window_selector(); - EXPECT_FALSE(window_selector->IsWindowInOverview(window1.get())); - EXPECT_TRUE(window_selector->IsWindowInOverview(window2.get())); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + overview_session = Shell::Get()->overview_controller()->overview_session(); + EXPECT_FALSE(overview_session->IsWindowInOverview(window1.get())); + EXPECT_TRUE(overview_session->IsWindowInOverview(window2.get())); CompleteDrag(std::move(resizer)); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); } // Test that if a window is in tab-dragging process, the split divider is placed @@ -2091,7 +2090,7 @@ ASSERT_TRUE(resizer.get()); // Overview should have been opened because the dragged window is the source // window. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // 1.a. Drag the window to move a small amount of distance will maximize the // window again. @@ -2104,7 +2103,7 @@ CompleteDrag(std::move(resizer)); EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMaximized()); EXPECT_TRUE(wm::GetWindowState(window2.get())->IsMaximized()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); // 1.b. Drag the window long enough (pass one fourth of the screen vertical // height) to snap the window to splitscreen. @@ -2122,18 +2121,18 @@ EXPECT_EQ(split_view_controller()->left_window(), window1.get()); EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Maximize the snapped window to end split view mode and overview mode. wm::GetWindowState(window1.get())->Maximize(); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); // 2. If the dragged window is not the source window: resizer = StartDrag(window1.get(), window2.get()); ASSERT_TRUE(resizer.get()); // Overview is not opened for this case. - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); // When the drag starts, the source window's bounds are the same with the // work area's bounds. const display::Display display = @@ -2193,7 +2192,7 @@ EXPECT_EQ(split_view_controller()->right_window(), window2.get()); EXPECT_EQ(split_view_controller()->state(), SplitViewController::BOTH_SNAPPED); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_TRUE(window1->GetProperty(kCanAttachToAnotherWindowKey)); EndSplitView(); @@ -2208,7 +2207,7 @@ resizer.reset(); window1.reset(); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_TRUE(wm::GetWindowState(window2.get())->IsMaximized()); // 4. If the dragged window can't be snapped, then the source window should @@ -2222,7 +2221,7 @@ gfx::Size(display_bounds.width() * 0.67f, display_bounds.height())); EXPECT_FALSE(CanSnapInSplitview(window1.get())); resizer = StartDrag(window1.get(), window2.get()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); DragWindowTo(resizer.get(), gfx::Point(0, GetIndicatorsThreshold(window1.get()) + 10)); EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kCannotSnap); @@ -2266,12 +2265,12 @@ EXPECT_EQ(split_view_controller()->state(), SplitViewController::RIGHT_SNAPPED); // In this case overview grid will be opened, containing |window3|. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - WindowSelector* window_selector = - Shell::Get()->window_selector_controller()->window_selector(); - EXPECT_FALSE(window_selector->IsWindowInOverview(window1.get())); - EXPECT_FALSE(window_selector->IsWindowInOverview(window2.get())); - EXPECT_TRUE(window_selector->IsWindowInOverview(window3.get())); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + OverviewSession* overview_session = + Shell::Get()->overview_controller()->overview_session(); + EXPECT_FALSE(overview_session->IsWindowInOverview(window1.get())); + EXPECT_FALSE(overview_session->IsWindowInOverview(window2.get())); + EXPECT_TRUE(overview_session->IsWindowInOverview(window3.get())); // 1.a. If the window is only dragged for a small distance, the window will // be put back to its original position. Overview mode will be ended. @@ -2281,13 +2280,13 @@ SplitViewController::BOTH_SNAPPED); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); EXPECT_EQ(split_view_controller()->right_window(), window2.get()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); // 1.b. If the window is dragged long enough, it can replace the other split // window. resizer = StartDrag(window1.get(), window1.get()); ASSERT_TRUE(resizer.get()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); DragWindowTo(resizer.get(), gfx::Point(600, 300)); // No preview window shows up on overview side of the screen. EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kNone); @@ -2295,12 +2294,11 @@ EXPECT_EQ(split_view_controller()->state(), SplitViewController::RIGHT_SNAPPED); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - window_selector = - Shell::Get()->window_selector_controller()->window_selector(); - EXPECT_FALSE(window_selector->IsWindowInOverview(window1.get())); - EXPECT_TRUE(window_selector->IsWindowInOverview(window2.get())); - EXPECT_TRUE(window_selector->IsWindowInOverview(window3.get())); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + overview_session = Shell::Get()->overview_controller()->overview_session(); + EXPECT_FALSE(overview_session->IsWindowInOverview(window1.get())); + EXPECT_TRUE(overview_session->IsWindowInOverview(window2.get())); + EXPECT_TRUE(overview_session->IsWindowInOverview(window3.get())); // Snap |window2| again to test 1.c. split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT); EXPECT_EQ(split_view_controller()->state(), @@ -2312,14 +2310,14 @@ EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); ASSERT_TRUE(resizer.get()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); resizer->Drag(gfx::Point(100, 100), 0); resizer->CompleteDrag(); resizer.reset(); window1.reset(); EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Recreate |window1| and snap it to test the following senarioes. window1.reset(CreateWindowWithType(bounds, AppType::BROWSER)); @@ -2339,7 +2337,7 @@ SplitViewController::BOTH_SNAPPED); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kNone); EXPECT_EQ(window2->GetBoundsInScreen(), split_view_controller()->GetSnappedWindowBoundsInScreen( @@ -2363,7 +2361,7 @@ SplitViewController::BOTH_SNAPPED); EXPECT_EQ(split_view_controller()->left_window(), window3.get()); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); // 2.b. If the window is dragged long enough, it can replace the other side of // the split window. @@ -2373,7 +2371,7 @@ SplitViewController::BOTH_SNAPPED); EXPECT_EQ(split_view_controller()->left_window(), window3.get()); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); DragWindowTo(resizer.get(), gfx::Point(0, 300)); // No preview window shows up on overview side of the screen. EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kNone); @@ -2382,7 +2380,7 @@ SplitViewController::BOTH_SNAPPED); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); } // Test the functionalities that are related to dragging a snapped window while @@ -2403,7 +2401,7 @@ split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); ToggleOverview(); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); @@ -2414,7 +2412,7 @@ ASSERT_TRUE(resizer.get()); // Overivew mode is still active, but split view mode is ended due to dragging // the only snapped window. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); // 1.a. If the window is only dragged for a small amount of distance @@ -2426,7 +2424,7 @@ EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kDragArea); CompleteDrag(std::move(resizer)); EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMaximized()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); // 1.b. If the window is dragged long enough, it can be snappped again. @@ -2437,7 +2435,7 @@ ToggleOverview(); resizer = StartDrag(window1.get(), window1.get()); ASSERT_TRUE(resizer.get()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); DragWindowTo(resizer.get(), gfx::Point(0, 300)); EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaLeft); @@ -2445,20 +2443,20 @@ EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - WindowSelector* window_selector = - Shell::Get()->window_selector_controller()->window_selector(); - EXPECT_TRUE(window_selector->IsWindowInOverview(window2.get())); - EXPECT_TRUE(window_selector->IsWindowInOverview(window3.get())); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + OverviewSession* overview_session = + Shell::Get()->overview_controller()->overview_session(); + EXPECT_TRUE(overview_session->IsWindowInOverview(window2.get())); + EXPECT_TRUE(overview_session->IsWindowInOverview(window3.get())); // 2. If the dragged window is not the source window: // Prepare the testing senario first. Remove |window2| from overview first // before tab-dragging. - WindowGrid* current_grid = - window_selector->GetGridWithRootWindow(window2->GetRootWindow()); + OverviewGrid* current_grid = + overview_session->GetGridWithRootWindow(window2->GetRootWindow()); ASSERT_TRUE(current_grid); - window_selector->RemoveWindowSelectorItem( - current_grid->GetWindowSelectorItemContaining(window2.get()), + overview_session->RemoveOverviewItem( + current_grid->GetOverviewItemContaining(window2.get()), /*reposition=*/false); resizer = StartDrag(window2.get(), window1.get()); ASSERT_TRUE(resizer.get()); @@ -2485,17 +2483,16 @@ EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - window_selector = - Shell::Get()->window_selector_controller()->window_selector(); - EXPECT_TRUE(window_selector->IsWindowInOverview(window1.get())); - EXPECT_TRUE(window_selector->IsWindowInOverview(window3.get())); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + overview_session = Shell::Get()->overview_controller()->overview_session(); + EXPECT_TRUE(overview_session->IsWindowInOverview(window1.get())); + EXPECT_TRUE(overview_session->IsWindowInOverview(window3.get())); // 2.b. The dragged window can snap to the other side of the splitscreen, // causing overview mode to end. // Remove |window1| from overview first before tab dragging. - window_selector->RemoveWindowSelectorItem( - current_grid->GetWindowSelectorItemContaining(window1.get()), + overview_session->RemoveOverviewItem( + current_grid->GetOverviewItemContaining(window1.get()), /*reposition=*/false); resizer = StartDrag(window1.get(), window2.get()); ASSERT_TRUE(resizer.get()); @@ -2507,7 +2504,7 @@ SplitViewController::BOTH_SNAPPED); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); } // Test that if a window is in tab-dragging process when overview is open, the @@ -2527,47 +2524,46 @@ SplitViewController::RIGHT); EXPECT_EQ(split_view_controller()->state(), SplitViewController::BOTH_SNAPPED); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); // Now drags |window1|. std::unique_ptr<WindowResizer> resizer = StartDrag(window1.get(), window1.get()); // Overview should have been opened. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(split_view_controller()->state(), SplitViewController::RIGHT_SNAPPED); // Test that the new window item widget shows up as the first one of the // windows in the grid. - WindowSelector* window_selector = - Shell::Get()->window_selector_controller()->window_selector(); - WindowGrid* current_grid = - window_selector->GetGridWithRootWindow(window1->GetRootWindow()); + OverviewSession* overview_session = + Shell::Get()->overview_controller()->overview_session(); + OverviewGrid* current_grid = + overview_session->GetGridWithRootWindow(window1->GetRootWindow()); ASSERT_TRUE(current_grid); views::Widget* drop_target_widget = current_grid->drop_target_widget_for_testing(); EXPECT_TRUE(drop_target_widget); - WindowSelectorItem* drop_target = - current_grid->GetWindowSelectorItemContaining( - drop_target_widget->GetNativeWindow()); + OverviewItem* drop_target = current_grid->GetOverviewItemContaining( + drop_target_widget->GetNativeWindow()); ASSERT_TRUE(drop_target); EXPECT_EQ(drop_target, current_grid->window_list().front().get()); const gfx::Rect drop_target_bounds = drop_target->target_bounds(); DragWindowTo(resizer.get(), drop_target_bounds.CenterPoint()); CompleteDrag(std::move(resizer)); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(split_view_controller()->state(), SplitViewController::RIGHT_SNAPPED); // Test that the dragged window has been added to the overview mode, and it is // added at the front of the grid. EXPECT_EQ(current_grid->window_list().size(), 2u); - WindowSelectorItem* first_selector_item = - current_grid->GetWindowSelectorItemContaining(window1.get()); + OverviewItem* first_selector_item = + current_grid->GetOverviewItemContaining(window1.get()); EXPECT_EQ(first_selector_item, current_grid->window_list().front().get()); - EXPECT_TRUE(window_selector->IsWindowInOverview(window1.get())); - EXPECT_TRUE(window_selector->IsWindowInOverview(window3.get())); + EXPECT_TRUE(overview_session->IsWindowInOverview(window1.get())); + EXPECT_TRUE(overview_session->IsWindowInOverview(window3.get())); // Test that the new window item widget has been destroyed. EXPECT_FALSE(current_grid->drop_target_widget_for_testing()); } @@ -2591,14 +2587,14 @@ ASSERT_TRUE(resizer.get()); // Overview should have been opened because the dragged window is the source // window. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // The value should be properly initialized. EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); // Now release the dragged window. There should be no animation when exiting // overview. CompleteDrag(std::move(resizer)); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_FALSE(overview_observer->overview_animate_when_exiting()); // 2) If dragging a snapped window: @@ -2609,7 +2605,7 @@ resizer = StartDrag(window1.get(), window1.get()); ASSERT_TRUE(resizer.get()); // Overview should have been opened behind the dragged window. - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Split view should still be active. EXPECT_EQ(split_view_controller()->state(), SplitViewController::RIGHT_SNAPPED); @@ -2617,7 +2613,7 @@ EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); CompleteDrag(std::move(resizer)); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(split_view_controller()->state(), SplitViewController::BOTH_SNAPPED); EXPECT_FALSE(overview_observer->overview_animate_when_exiting()); @@ -2644,7 +2640,7 @@ std::unique_ptr<WindowResizer> resizer = StartDrag(window.get(), window.get()); ASSERT_TRUE(resizer.get()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Drag the window past the indicators threshold to show the indicators. DragWindowTo(resizer.get(), gfx::Point(200, GetIndicatorsThreshold(window.get()))); @@ -2678,8 +2674,7 @@ std::unique_ptr<aura::Window> window3( CreateWindowWithType(bounds, AppType::BROWSER)); - WindowSelectorController* selector_controller = - Shell::Get()->window_selector_controller(); + OverviewController* selector_controller = Shell::Get()->overview_controller(); EXPECT_FALSE(selector_controller->IsSelecting()); // Start dragging |window1|. @@ -2689,8 +2684,8 @@ EXPECT_TRUE(selector_controller->IsSelecting()); // Test that the drop target shows up as the first item in overview. - WindowGrid* current_grid = - selector_controller->window_selector()->GetGridWithRootWindow( + OverviewGrid* current_grid = + selector_controller->overview_session()->GetGridWithRootWindow( window1->GetRootWindow()); EXPECT_TRUE(current_grid->GetDropTarget()); const gfx::Rect work_area_bounds = @@ -2747,7 +2742,7 @@ EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); - current_grid = selector_controller->window_selector()->GetGridWithRootWindow( + current_grid = selector_controller->overview_session()->GetGridWithRootWindow( window1->GetRootWindow()); // The drop target should be visible. drop_target_widget = current_grid->drop_target_widget_for_testing(); @@ -2782,7 +2777,7 @@ // |window1| should now snap to left. |window2| is put back in overview. EXPECT_EQ(split_view_controller()->left_window(), window1.get()); EXPECT_TRUE(selector_controller->IsSelecting()); - EXPECT_TRUE(selector_controller->window_selector()->IsWindowInOverview( + EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview( window2.get())); // Now drag |window1| again. @@ -2792,7 +2787,7 @@ EXPECT_TRUE(selector_controller->IsSelecting()); // The size of drop target should still not be the same as the dragged // window's size. - current_grid = selector_controller->window_selector()->GetGridWithRootWindow( + current_grid = selector_controller->overview_session()->GetGridWithRootWindow( window1->GetRootWindow()); drop_target_widget = current_grid->drop_target_widget_for_testing(); EXPECT_TRUE(drop_target_widget); @@ -2815,23 +2810,21 @@ // Drag |window1|. Overview should open behind the dragged window. std::unique_ptr<WindowResizer> resizer = StartDrag(window1.get(), window1.get()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); // Change the |window1|'s bounds to simulate what might happen in reality. window1->SetBounds(bounds); EXPECT_EQ(bounds, window1->bounds()); // Drop |window1| to the drop target in overview. - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - WindowSelector* window_selector = - window_selector_controller->window_selector(); - WindowGrid* current_grid = - window_selector->GetGridWithRootWindow(window1->GetRootWindow()); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + OverviewSession* overview_session = overview_controller->overview_session(); + OverviewGrid* current_grid = + overview_session->GetGridWithRootWindow(window1->GetRootWindow()); ASSERT_TRUE(current_grid); EXPECT_EQ(1u, current_grid->window_list().size()); - WindowSelectorItem* selector_item = current_grid->GetDropTarget(); + OverviewItem* selector_item = current_grid->GetDropTarget(); ASSERT_TRUE(selector_item); gfx::Rect drop_target_bounds = selector_item->target_bounds(); DragWindowTo(resizer.get(), drop_target_bounds.CenterPoint()); @@ -2839,7 +2832,7 @@ CompleteDrag(std::move(resizer)); // |window1| should have been merged into overview. EXPECT_EQ(current_grid->window_list().size(), 1u); - EXPECT_TRUE(window_selector->IsWindowInOverview(window1.get())); + EXPECT_TRUE(overview_session->IsWindowInOverview(window1.get())); // |window1|'s bounds should have been updated to its tablet mode bounds. EXPECT_EQ(tablet_mode_bounds, window1->bounds()); selector_item = current_grid->window_list().front().get(); @@ -2847,11 +2840,11 @@ // after drag. EXPECT_EQ(drop_target_bounds, selector_item->target_bounds()); ToggleOverview(); - EXPECT_FALSE(window_selector_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->IsSelecting()); // Drag |window1|. Overview should open behind the dragged window. resizer = StartDrag(window1.get(), window1.get()); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->IsSelecting()); // Change the |window1|'s bounds to simulate what might happen in reality. window1->SetBounds(bounds); @@ -2864,7 +2857,7 @@ drop_target_bounds.bottom_right() + gfx::Vector2d(10, 10)); CompleteDrag(std::move(resizer)); // |window1| should have been merged into overview. - EXPECT_TRUE(window_selector_controller->window_selector()->IsWindowInOverview( + EXPECT_TRUE(overview_controller->overview_session()->IsWindowInOverview( window1.get())); // |window1|'s bounds should have been updated to its tablet mode bounds. EXPECT_EQ(tablet_mode_bounds, window1->bounds()); @@ -2897,7 +2890,7 @@ 10)); CompleteDrag(std::move(resizer)); EXPECT_TRUE(wm::GetWindowState(browser_window1.get())->IsMaximized()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); // Drop window into overview if it has beenn dragged further than the distance // threshold. @@ -2911,9 +2904,9 @@ (drop_target_bounds.y() - work_area_bounds.y()) + 10)); CompleteDrag(std::move(resizer)); - WindowSelector* window_selector = - Shell::Get()->window_selector_controller()->window_selector(); - EXPECT_TRUE(window_selector->IsWindowInOverview(browser_window1.get())); + OverviewSession* overview_session = + Shell::Get()->overview_controller()->overview_session(); + EXPECT_TRUE(overview_session->IsWindowInOverview(browser_window1.get())); ToggleOverview(); // Do not consider the drag position if preview area is shown. Window should @@ -2942,7 +2935,7 @@ CompleteDrag(std::move(resizer)); EXPECT_EQ(SplitViewController::BOTH_SNAPPED, split_view_controller()->state()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EndSplitView(); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); @@ -2963,7 +2956,7 @@ 10)); CompleteDrag(std::move(resizer)); EXPECT_TRUE(wm::GetWindowState(browser_window1.get())->IsMaximized()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); } // Tests that a dragged window should have the active window shadow during @@ -3080,10 +3073,9 @@ gfx::Rect drop_target_bounds = GetDropTargetBoundsDuringDrag(window1.get()); DragWindowTo(resizer.get(), drop_target_bounds.CenterPoint()); CompleteDrag(std::move(resizer)); - WindowSelectorController* selector_controller = - Shell::Get()->window_selector_controller(); + OverviewController* selector_controller = Shell::Get()->overview_controller(); EXPECT_TRUE(selector_controller->IsSelecting()); - EXPECT_TRUE(selector_controller->window_selector()->IsWindowInOverview( + EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview( window2.get())); EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); @@ -3382,12 +3374,12 @@ StartDrag(dragged_window.get(), dragged_window.get()); DragWindowTo(resizer.get(), gfx::Point(300, 300)); EXPECT_TRUE(wm::GetWindowState(dragged_window.get())->is_dragged()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); GetEventGenerator()->PressKey(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_NONE); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_FALSE(Shell::Get() - ->window_selector_controller() - ->window_selector() + ->overview_controller() + ->overview_session() ->IsWindowInOverview(dragged_window.get())); EXPECT_TRUE(wm::GetWindowState(dragged_window.get())->is_dragged()); resizer->CompleteDrag(); @@ -3411,14 +3403,14 @@ EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), true); EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); std::unique_ptr<aura::Window> dragged_window( CreateWindowWithType(bounds, AppType::BROWSER)); EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), true); EXPECT_EQ(split_view_controller()->state(), SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); std::unique_ptr<WindowResizer> resizer = StartDrag(dragged_window.get(), window1.get()); @@ -3434,7 +3426,7 @@ EXPECT_EQ(split_view_controller()->state(), SplitViewController::BOTH_SNAPPED); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_TRUE(split_view_divider()->divider_widget()->IsAlwaysOnTop()); } @@ -3470,7 +3462,7 @@ dragged_window.reset(); EXPECT_EQ(split_view_controller()->state(), SplitViewController::RIGHT_SNAPPED); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_TRUE(split_view_divider()->divider_widget()->IsAlwaysOnTop()); } @@ -3613,16 +3605,14 @@ // dropped into overview. base::TimeTicks timestamp = base::TimeTicks::Now(); SendScrollStartAndUpdate(start, long_scroll_delta, timestamp, window.get()); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); - EXPECT_FALSE( - window_selector_controller->window_selector()->IsWindowInOverview( - window.get())); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->overview_session()->IsWindowInOverview( + window.get())); EndScrollSequence(start, long_scroll_delta, timestamp, window.get()); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->IsSelecting()); EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive()); - EXPECT_TRUE(window_selector_controller->window_selector()->IsWindowInOverview( + EXPECT_TRUE(overview_controller->overview_session()->IsWindowInOverview( window.get())); } @@ -3647,14 +3637,12 @@ const float long_scroll_delta = display_bounds.height() / 4 + 5; base::TimeTicks timestamp = base::TimeTicks::Now(); SendScrollStartAndUpdate(start, long_scroll_delta, timestamp, window.get()); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); - EXPECT_FALSE( - window_selector_controller->window_selector()->IsWindowInOverview( - window.get())); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->overview_session()->IsWindowInOverview( + window.get())); EndScrollSequence(start, long_scroll_delta, timestamp, window.get()); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->IsSelecting()); EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive()); EXPECT_EQ(split_view_controller()->left_window(), window.get()); EXPECT_EQ(split_view_controller()->state(), @@ -3665,25 +3653,25 @@ // kFlingToOverviewThreshold) will not able to drop the window into overview. timestamp = base::TimeTicks::Now(); SendScrollStartAndUpdate(start, 10, timestamp, window.get()); - window_selector_controller = Shell::Get()->window_selector_controller(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + overview_controller = Shell::Get()->overview_controller(); + EXPECT_TRUE(overview_controller->IsSelecting()); EndScrollSequence( start, 10, timestamp, window.get(), /*is_fling=*/true, /*velocity_y=*/ TabletModeWindowDragDelegate::kFlingToOverviewThreshold - 10.f); - EXPECT_FALSE(window_selector_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->IsSelecting()); // FLING the window with large veloicty (larger than // kFlingToOverviewThreshold) will drop the window into overview. timestamp = base::TimeTicks::Now(); SendScrollStartAndUpdate(start, 10, timestamp, window.get()); - window_selector_controller = Shell::Get()->window_selector_controller(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + overview_controller = Shell::Get()->overview_controller(); + EXPECT_TRUE(overview_controller->IsSelecting()); EndScrollSequence( start, 10, timestamp, window.get(), /*is_fling=*/true, /*velocity_y=*/ TabletModeWindowDragDelegate::kFlingToOverviewThreshold + 10.f); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->IsSelecting()); } // Tests the shelf visibility when a fullscreened window is being dragged. @@ -3787,9 +3775,8 @@ // overview. base::TimeTicks timestamp = base::TimeTicks::Now(); SendScrollStartAndUpdate(gfx::Point(0, 0), 10, timestamp, window.get()); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + EXPECT_TRUE(overview_controller->IsSelecting()); EXPECT_TRUE(wm::GetWindowState(window.get())->is_dragged()); // Rotate the screen during drag. @@ -3798,7 +3785,7 @@ EXPECT_EQ(test_api.GetCurrentOrientation(), OrientationLockType::kPortraitPrimary); EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized()); - EXPECT_FALSE(window_selector_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->IsSelecting()); EXPECT_FALSE(wm::GetWindowState(window.get())->is_dragged()); } @@ -3827,12 +3814,10 @@ EndScrollSequence(start, long_scroll_delta, timestamp, window.get(), /*is_fling=*/true, /*velocity_y*/ 0, /*velocity_x=*/large_velocity); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - WindowSelector* window_selector = - window_selector_controller->window_selector(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); - EXPECT_TRUE(window_selector->IsWindowInOverview(window.get())); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + OverviewSession* overview_session = overview_controller->overview_session(); + EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_session->IsWindowInOverview(window.get())); ToggleOverview(); EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized()); @@ -3855,9 +3840,9 @@ EndScrollSequence(start, long_scroll_delta, timestamp, window.get(), /*is_fling=*/true, /*velocity_y*/ 0, /*velocity_x=*/-large_velocity); - window_selector = window_selector_controller->window_selector(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); - EXPECT_TRUE(window_selector->IsWindowInOverview(window.get())); + overview_session = overview_controller->overview_session(); + EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_session->IsWindowInOverview(window.get())); ToggleOverview(); // Fling to the left with small velocity when trying to snap the @@ -3905,9 +3890,8 @@ EndScrollSequence(start, long_scroll_y, timestamp, window1.get(), /*is_fling=*/true, /*velocity_y=*/0, /*velocity_x=*/large_velocity); - WindowSelectorController* selector_controller = - Shell::Get()->window_selector_controller(); - EXPECT_TRUE(selector_controller->window_selector()->IsWindowInOverview( + OverviewController* selector_controller = Shell::Get()->overview_controller(); + EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview( window1.get())); EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, split_view_controller()->state()); @@ -3924,7 +3908,7 @@ EndScrollSequence(end, long_scroll_y, timestamp, window1.get(), /*is_fling=*/true, /*velocity_y=*/0, /*velocity_x=*/-large_velocity); - EXPECT_TRUE(selector_controller->window_selector()->IsWindowInOverview( + EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview( window1.get())); EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, split_view_controller()->state()); @@ -3940,7 +3924,7 @@ /*is_fling=*/true, /*velocity_y=*/0, /*velocity_x=*/large_velocity); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_TRUE(selector_controller->window_selector()->IsWindowInOverview( + EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview( window2.get())); EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, split_view_controller()->state());
diff --git a/ash/wm/splitview/split_view_drag_indicators_unittest.cc b/ash/wm/splitview/split_view_drag_indicators_unittest.cc index ab1e15e..a861d1f3 100644 --- a/ash/wm/splitview/split_view_drag_indicators_unittest.cc +++ b/ash/wm/splitview/split_view_drag_indicators_unittest.cc
@@ -6,10 +6,10 @@ #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_item.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_item.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/splitview/split_view_constants.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" @@ -37,20 +37,18 @@ } void ToggleOverview() { - auto* window_selector_controller = - Shell::Get()->window_selector_controller(); - window_selector_controller->ToggleOverview(); - if (!window_selector_controller->IsSelecting()) { - window_selector_ = nullptr; + auto* overview_controller = Shell::Get()->overview_controller(); + overview_controller->ToggleOverview(); + if (!overview_controller->IsSelecting()) { + overview_session_ = nullptr; split_view_drag_indicators_ = nullptr; return; } - window_selector_ = - Shell::Get()->window_selector_controller()->window_selector(); - ASSERT_TRUE(window_selector_); + overview_session_ = Shell::Get()->overview_controller()->overview_session(); + ASSERT_TRUE(overview_session_); split_view_drag_indicators_ = - window_selector_->split_view_drag_indicators(); + overview_session_->split_view_drag_indicators(); } SplitViewController* split_view_controller() { @@ -67,13 +65,13 @@ indicator_state() == IndicatorState::kPreviewAreaRight; } - WindowSelectorItem* GetOverviewItemForWindow(aura::Window* window, - int grid_index = 0) { + OverviewItem* GetOverviewItemForWindow(aura::Window* window, + int grid_index = 0) { auto& windows = - window_selector_->grid_list_for_testing()[grid_index]->window_list(); + overview_session_->grid_list_for_testing()[grid_index]->window_list(); auto iter = std::find_if(windows.cbegin(), windows.cend(), - [window](const std::unique_ptr<WindowSelectorItem>& item) { + [window](const std::unique_ptr<OverviewItem>& item) { return item->Contains(window); }); if (iter == windows.end()) @@ -96,7 +94,7 @@ protected: SplitViewDragIndicators* split_view_drag_indicators_ = nullptr; - WindowSelector* window_selector_ = nullptr; + OverviewSession* overview_session_ = nullptr; private: DISALLOW_COPY_AND_ASSIGN(SplitViewDragIndicatorsTest); @@ -112,10 +110,8 @@ ui::test::EventGenerator* generator = GetEventGenerator(); ToggleOverview(); - WindowSelectorItem* left_selector_item = - GetOverviewItemForWindow(left_window.get()); - WindowSelectorItem* right_selector_item = - GetOverviewItemForWindow(right_window.get()); + OverviewItem* left_item = GetOverviewItemForWindow(left_window.get()); + OverviewItem* right_item = GetOverviewItemForWindow(right_window.get()); // The inset on each side of the screen which is a snap region. Items dragged // to and released under this region will get snapped. @@ -124,38 +120,36 @@ const int minimum_drag_offset = 96; // The selector item has a margin which does not accept events. Inset any // event aimed at the selector items edge so events will reach it. - const int selector_item_inset = 20; + const int item_inset = 20; // Check the two windows set up have a region which is under no snap region, a // region that is under the left snap region and a region that is under the // right snap region. - ASSERT_GT(left_selector_item->target_bounds().CenterPoint().x(), edge_inset); - ASSERT_LT( - left_selector_item->target_bounds().origin().x() + selector_item_inset, - edge_inset); - ASSERT_GT(right_selector_item->target_bounds().right() - selector_item_inset, + ASSERT_GT(left_item->target_bounds().CenterPoint().x(), edge_inset); + ASSERT_LT(left_item->target_bounds().origin().x() + item_inset, edge_inset); + ASSERT_GT(right_item->target_bounds().right() - item_inset, screen_width - edge_inset); // Verify if the drag is not started in either snap region, the drag still // must move by |drag_offset| before split view acknowledges the drag (ie. // starts moving the selector item). generator->set_current_screen_location( - left_selector_item->target_bounds().CenterPoint()); + left_item->target_bounds().CenterPoint()); generator->PressLeftButton(); - const gfx::Rect left_original_bounds = left_selector_item->target_bounds(); + const gfx::Rect left_original_bounds = left_item->target_bounds(); generator->MoveMouseBy(drag_offset - 1, 0); - EXPECT_EQ(left_original_bounds, left_selector_item->target_bounds()); + EXPECT_EQ(left_original_bounds, left_item->target_bounds()); generator->MoveMouseBy(1, 0); - EXPECT_NE(left_original_bounds, left_selector_item->target_bounds()); + EXPECT_NE(left_original_bounds, left_item->target_bounds()); generator->ReleaseLeftButton(); // Verify if the drag is started in the left snap region, the drag needs to // move by |drag_offset_snap_region| towards the right side of the screen // before split view acknowledges the drag (shows the preview area). - ASSERT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - generator->set_current_screen_location(gfx::Point( - left_selector_item->target_bounds().origin().x() + selector_item_inset, - left_selector_item->target_bounds().CenterPoint().y())); + ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + generator->set_current_screen_location( + gfx::Point(left_item->target_bounds().origin().x() + item_inset, + left_item->target_bounds().CenterPoint().y())); generator->PressLeftButton(); generator->MoveMouseBy(-drag_offset, 0); EXPECT_FALSE(IsPreviewAreaShowing()); @@ -170,10 +164,10 @@ // Verify if the drag is started in the right snap region, the drag needs to // move by |drag_offset_snap_region| towards the left side of the screen // before split view acknowledges the drag. - ASSERT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); - generator->set_current_screen_location(gfx::Point( - right_selector_item->target_bounds().right() - selector_item_inset, - right_selector_item->target_bounds().CenterPoint().y())); + ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + generator->set_current_screen_location( + gfx::Point(right_item->target_bounds().right() - item_inset, + right_item->target_bounds().CenterPoint().y())); generator->PressLeftButton(); generator->MoveMouseBy(drag_offset, 0); EXPECT_FALSE(IsPreviewAreaShowing()); @@ -190,32 +184,30 @@ std::unique_ptr<aura::Window> window(CreateTestWindow()); ToggleOverview(); - // Verify the preview area is visible when |selector_item|'s x is in the + // Verify the preview area is visible when |item|'s x is in the // range [0, edge_inset] or [screen_width - edge_inset - 1, screen_width]. - WindowSelectorItem* selector_item = GetOverviewItemForWindow(window.get()); - ASSERT_TRUE(selector_item); - const gfx::Point start_location(selector_item->target_bounds().CenterPoint()); + OverviewItem* item = GetOverviewItemForWindow(window.get()); + ASSERT_TRUE(item); + const gfx::Point start_location(item->target_bounds().CenterPoint()); // Drag horizontally to avoid activating drag to close. const int y = start_location.y(); - window_selector_->InitiateDrag(selector_item, start_location); + overview_session_->InitiateDrag(item, start_location); EXPECT_FALSE(IsPreviewAreaShowing()); - window_selector_->Drag(selector_item, gfx::Point(edge_inset + 1, y)); + overview_session_->Drag(item, gfx::Point(edge_inset + 1, y)); EXPECT_FALSE(IsPreviewAreaShowing()); - window_selector_->Drag(selector_item, gfx::Point(edge_inset, y)); + overview_session_->Drag(item, gfx::Point(edge_inset, y)); EXPECT_TRUE(IsPreviewAreaShowing()); - window_selector_->Drag(selector_item, - gfx::Point(screen_width - edge_inset - 2, y)); + overview_session_->Drag(item, gfx::Point(screen_width - edge_inset - 2, y)); EXPECT_FALSE(IsPreviewAreaShowing()); - window_selector_->Drag(selector_item, - gfx::Point(screen_width - edge_inset - 1, y)); + overview_session_->Drag(item, gfx::Point(screen_width - edge_inset - 1, y)); EXPECT_TRUE(IsPreviewAreaShowing()); // Drag back to |start_location| before compeleting the drag, otherwise // |selector_time| will snap to the right and the system will enter splitview, // making |window_drag_controller()| nullptr. - window_selector_->Drag(selector_item, start_location); - window_selector_->CompleteDrag(selector_item, start_location); + overview_session_->Drag(item, start_location); + overview_session_->CompleteDrag(item, start_location); EXPECT_FALSE(IsPreviewAreaShowing()); } @@ -227,16 +219,16 @@ std::unique_ptr<aura::Window> window(CreateUnsnappableWindow()); ToggleOverview(); - WindowSelectorItem* selector_item = GetOverviewItemForWindow(window.get()); - const gfx::Point start_location(selector_item->target_bounds().CenterPoint()); - window_selector_->InitiateDrag(selector_item, start_location); + OverviewItem* item = GetOverviewItemForWindow(window.get()); + const gfx::Point start_location(item->target_bounds().CenterPoint()); + overview_session_->InitiateDrag(item, start_location); EXPECT_FALSE(IsPreviewAreaShowing()); - window_selector_->Drag(selector_item, gfx::Point(0, 1)); + overview_session_->Drag(item, gfx::Point(0, 1)); EXPECT_FALSE(IsPreviewAreaShowing()); - window_selector_->Drag(selector_item, gfx::Point(screen_width, 1)); + overview_session_->Drag(item, gfx::Point(screen_width, 1)); EXPECT_FALSE(IsPreviewAreaShowing()); - window_selector_->CompleteDrag(selector_item, start_location); + overview_session_->CompleteDrag(item, start_location); EXPECT_FALSE(IsPreviewAreaShowing()); } @@ -251,44 +243,42 @@ // Verify that when are no snapped windows, the indicator is visible once // there is a long press or after the drag has started. - WindowSelectorItem* selector_item = GetOverviewItemForWindow(window1.get()); - gfx::Point start_location(selector_item->target_bounds().CenterPoint()); - window_selector_->InitiateDrag(selector_item, start_location); + OverviewItem* item = GetOverviewItemForWindow(window1.get()); + gfx::Point start_location(item->target_bounds().CenterPoint()); + overview_session_->InitiateDrag(item, start_location); EXPECT_EQ(IndicatorState::kNone, indicator_state()); - window_selector_->StartSplitViewDragMode(start_location); + overview_session_->StartSplitViewDragMode(start_location); EXPECT_EQ(IndicatorState::kDragArea, indicator_state()); // Reset the gesture so we stay in overview mode. - window_selector_->ResetDraggedWindowGesture(); + overview_session_->ResetDraggedWindowGesture(); // Verify the indicator is visible once the item starts moving, and becomes a // preview area once we reach the left edge of the screen. Drag horizontal to // avoid activating drag to close. const int y_position = start_location.y(); - window_selector_->InitiateDrag(selector_item, start_location); + overview_session_->InitiateDrag(item, start_location); EXPECT_EQ(IndicatorState::kNone, indicator_state()); - window_selector_->Drag(selector_item, gfx::Point(edge_inset + 1, y_position)); + overview_session_->Drag(item, gfx::Point(edge_inset + 1, y_position)); EXPECT_EQ(IndicatorState::kDragArea, indicator_state()); - window_selector_->Drag(selector_item, gfx::Point(edge_inset, y_position)); + overview_session_->Drag(item, gfx::Point(edge_inset, y_position)); EXPECT_EQ(IndicatorState::kPreviewAreaLeft, indicator_state()); // Snap window to the left. - window_selector_->CompleteDrag(selector_item, - gfx::Point(edge_inset, y_position)); + overview_session_->CompleteDrag(item, gfx::Point(edge_inset, y_position)); ASSERT_TRUE(split_view_controller()->IsSplitViewModeActive()); ASSERT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller()->state()); // Verify that when there is a left snapped window, dragging an item to the // right will show the right preview area. - selector_item = GetOverviewItemForWindow(window2.get()); - start_location = selector_item->target_bounds().CenterPoint(); - window_selector_->InitiateDrag(selector_item, start_location); + item = GetOverviewItemForWindow(window2.get()); + start_location = item->target_bounds().CenterPoint(); + overview_session_->InitiateDrag(item, start_location); EXPECT_EQ(IndicatorState::kNone, indicator_state()); - window_selector_->Drag(selector_item, - gfx::Point(screen_width - 1, y_position)); + overview_session_->Drag(item, gfx::Point(screen_width - 1, y_position)); EXPECT_EQ(IndicatorState::kPreviewAreaRight, indicator_state()); - window_selector_->CompleteDrag(selector_item, start_location); + overview_session_->CompleteDrag(item, start_location); } // Verify that the split view drag indicator is shown when expected when @@ -298,16 +288,15 @@ std::unique_ptr<aura::Window> unsnappable_window(CreateUnsnappableWindow()); ToggleOverview(); - WindowSelectorItem* selector_item = - GetOverviewItemForWindow(unsnappable_window.get()); - gfx::Point start_location(selector_item->target_bounds().CenterPoint()); - window_selector_->InitiateDrag(selector_item, start_location); - window_selector_->StartSplitViewDragMode(start_location); + OverviewItem* item = GetOverviewItemForWindow(unsnappable_window.get()); + gfx::Point start_location(item->target_bounds().CenterPoint()); + overview_session_->InitiateDrag(item, start_location); + overview_session_->StartSplitViewDragMode(start_location); EXPECT_EQ(IndicatorState::kCannotSnap, indicator_state()); const gfx::Point end_location1(0, 0); - window_selector_->Drag(selector_item, end_location1); + overview_session_->Drag(item, end_location1); EXPECT_EQ(IndicatorState::kCannotSnap, indicator_state()); - window_selector_->CompleteDrag(selector_item, end_location1); + overview_session_->CompleteDrag(item, end_location1); EXPECT_EQ(IndicatorState::kNone, indicator_state()); } @@ -377,34 +366,32 @@ // Select an item on the primary display and verify the drag indicators // widget's parent is the primary root window. - WindowSelectorItem* selector_item = - GetOverviewItemForWindow(primary_screen_window.get()); - gfx::Point start_location(selector_item->target_bounds().CenterPoint()); - window_selector_->InitiateDrag(selector_item, start_location); - window_selector_->Drag(selector_item, gfx::Point(100, start_location.y())); + OverviewItem* item = GetOverviewItemForWindow(primary_screen_window.get()); + gfx::Point start_location(item->target_bounds().CenterPoint()); + overview_session_->InitiateDrag(item, start_location); + overview_session_->Drag(item, gfx::Point(100, start_location.y())); EXPECT_EQ(IndicatorState::kDragArea, indicator_state()); - EXPECT_EQ(root_windows[0], window_selector_->split_view_drag_indicators() + EXPECT_EQ(root_windows[0], overview_session_->split_view_drag_indicators() ->widget_->GetNativeView() ->GetRootWindow()); // Drag the item in a way that neither opens the window nor activates // splitview mode. - window_selector_->Drag(selector_item, primary_screen_bounds.CenterPoint()); - window_selector_->CompleteDrag(selector_item, - primary_screen_bounds.CenterPoint()); - ASSERT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + overview_session_->Drag(item, primary_screen_bounds.CenterPoint()); + overview_session_->CompleteDrag(item, primary_screen_bounds.CenterPoint()); + ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); ASSERT_FALSE(split_view_controller()->IsSplitViewModeActive()); // Select an item on the secondary display and verify the indicators widget // has reparented to the secondary root window. - selector_item = GetOverviewItemForWindow(secondary_screen_window.get(), 1); - start_location = gfx::Point(selector_item->target_bounds().CenterPoint()); - window_selector_->InitiateDrag(selector_item, start_location); - window_selector_->Drag(selector_item, gfx::Point(800, start_location.y())); + item = GetOverviewItemForWindow(secondary_screen_window.get(), 1); + start_location = gfx::Point(item->target_bounds().CenterPoint()); + overview_session_->InitiateDrag(item, start_location); + overview_session_->Drag(item, gfx::Point(800, start_location.y())); EXPECT_EQ(IndicatorState::kDragArea, indicator_state()); - EXPECT_EQ(root_windows[1], window_selector_->split_view_drag_indicators() + EXPECT_EQ(root_windows[1], overview_session_->split_view_drag_indicators() ->widget_->GetNativeView() ->GetRootWindow()); - window_selector_->CompleteDrag(selector_item, start_location); + overview_session_->CompleteDrag(item, start_location); } } // namespace ash \ No newline at end of file
diff --git a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc index b03700f..1328fa4 100644 --- a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc +++ b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc
@@ -5,7 +5,7 @@ #include "ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h" #include "ash/shell.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_drag_indicators.h" #include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h" #include "ash/wm/window_state.h" @@ -39,8 +39,8 @@ void EndedWindowDrag(const gfx::Point& location_in_screen) override {} void StartFling(const ui::GestureEvent* event) override { if (ShouldFlingIntoOverview(event)) { - DCHECK(Shell::Get()->window_selector_controller()->IsSelecting()); - Shell::Get()->window_selector_controller()->window_selector()->AddItem( + DCHECK(Shell::Get()->overview_controller()->IsSelecting()); + Shell::Get()->overview_controller()->overview_session()->AddItem( dragged_window_, /*reposition=*/true, /*animate=*/false); } }
diff --git a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc index 7d2bd0d..b35513c 100644 --- a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc +++ b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc
@@ -13,9 +13,9 @@ #include "ash/wallpaper/wallpaper_widget_controller.h" #include "ash/wm/mru_window_tracker.h" #include "ash/wm/overview/overview_constants.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_grid.h" #include "ash/wm/overview/overview_utils.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector_controller.h" #include "ash/wm/splitview/split_view_constants.h" #include "ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.h" #include "ash/wm/tablet_mode/tablet_mode_window_state.h" @@ -126,7 +126,7 @@ source_window->SetProperty(kBackdropWindowMode, BackdropWindowMode::kDisabled); - DCHECK(!Shell::Get()->window_selector_controller()->IsSelecting()); + DCHECK(!Shell::Get()->overview_controller()->IsSelecting()); aura::Window* root_window = dragged_window->GetRootWindow(); std::vector<aura::Window*> windows = @@ -165,7 +165,7 @@ widget_window->SetBounds(bounds); views::View* shield_view = new views::View(); shield_view->SetPaintToLayer(ui::LAYER_SOLID_COLOR); - shield_view->layer()->SetColor(WindowGrid::GetShieldColor()); + shield_view->layer()->SetColor(OverviewGrid::GetShieldColor()); shield_view->layer()->SetOpacity(kShieldOpacity); shield_widget_->SetContentsView(shield_view); } @@ -186,7 +186,7 @@ } } - DCHECK(!Shell::Get()->window_selector_controller()->IsSelecting()); + DCHECK(!Shell::Get()->overview_controller()->IsSelecting()); // May reshow the home launcher after dragging. Shell::Get()->app_list_controller()->OnWindowDragEnded(); @@ -278,8 +278,8 @@ void TabletModeBrowserWindowDragDelegate::StartFling( const ui::GestureEvent* event) { if (ShouldFlingIntoOverview(event)) { - DCHECK(Shell::Get()->window_selector_controller()->IsSelecting()); - Shell::Get()->window_selector_controller()->window_selector()->AddItem( + DCHECK(Shell::Get()->overview_controller()->IsSelecting()); + Shell::Get()->overview_controller()->overview_session()->AddItem( dragged_window_, /*reposition=*/true, /*animate=*/false); } else { aura::Window* source_window =
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc index 1f31a73..9fd176e 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -112,6 +112,13 @@ return TabletModeController::UiMode::kNone; } +// Returns true if the device has an active internal display. +bool HasActiveInternalDisplay() { + return display::Display::HasInternalDisplay() && + Shell::Get()->display_manager()->IsActiveDisplayId( + display::Display::InternalDisplayId()); +} + } // namespace constexpr char TabletModeController::kLidAngleHistogramName[]; @@ -264,9 +271,7 @@ } void TabletModeController::OnDisplayConfigurationChanged() { - if (!display::Display::HasInternalDisplay() || - !Shell::Get()->display_manager()->IsActiveDisplayId( - display::Display::InternalDisplayId())) { + if (!HasActiveInternalDisplay()) { AttemptLeaveTabletMode(); } else if (tablet_mode_switch_is_on_ && !IsTabletModeWindowManagerEnabled()) { // The internal display has returned, as we are exiting docked mode. @@ -314,14 +319,9 @@ return; } - if (!display::Display::HasInternalDisplay()) + if (!HasActiveInternalDisplay()) return; - if (!Shell::Get()->display_manager()->IsActiveDisplayId( - display::Display::InternalDisplayId())) { - return; - } - // Whether or not we enter tablet mode affects whether we handle screen // rotation, so determine whether to enter tablet mode first. if (update->IsReadingStable(ACCELEROMETER_SOURCE_SCREEN) && @@ -358,12 +358,11 @@ VLOG(1) << "Tablet mode event received: " << static_cast<int>(mode); const bool on = mode == chromeos::PowerManagerClient::TabletMode::ON; tablet_mode_switch_is_on_ = on; + // Do not change if docked. - if (!display::Display::HasInternalDisplay() || - !Shell::Get()->display_manager()->IsActiveDisplayId( - display::Display::InternalDisplayId())) { + if (!HasActiveInternalDisplay()) return; - } + // The tablet mode switch activates at 300 degrees, so it is always reliable // when |on|. However we wish to exit tablet mode at a smaller angle, so // when |on| is false we ignore if it is possible to calculate the lid angle. @@ -640,10 +639,14 @@ // If we are currently in tablet mode, the internal input events should // always be blocked. should_block_internal_events = true; - } else if (LidAngleIsInTabletModeRange() || tablet_mode_switch_is_on_) { + } else if (HasActiveInternalDisplay() && + (LidAngleIsInTabletModeRange() || tablet_mode_switch_is_on_)) { // If we are currently in clamshell mode, the intenral input events should // only be blocked if the current lid angle belongs to tablet mode angle // or |tablet_mode_switch_is_on_| is true. + // Note if we don't have an active internal display, the device is currently + // in docked mode, and the user may still want to use the internal keyboard + // and mouse in docked mode, we don't block internal events in this case. should_block_internal_events = true; }
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc index f26af8f..64bac6a5 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -15,7 +15,7 @@ #include "ash/public/cpp/tablet_mode.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" #include "base/command_line.h" #include "base/run_loop.h" @@ -500,7 +500,7 @@ // Test if this case does not crash. See http://crbug.com/462806 TEST_F(TabletModeControllerTest, DisplayDisconnectionDuringOverview) { // Do not animate wallpaper on entering overview. - WindowSelectorController::SetDoNotChangeWallpaperBlurForTests(); + OverviewController::SetDoNotChangeWallpaperBlurForTests(); UpdateDisplay("800x600,800x600"); std::unique_ptr<aura::Window> w1( @@ -511,11 +511,11 @@ ASSERT_FALSE(IsTabletModeStarted()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->ToggleOverview()); + EXPECT_TRUE(Shell::Get()->overview_controller()->ToggleOverview()); UpdateDisplay("800x600"); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); EXPECT_EQ(w1->GetRootWindow(), w2->GetRootWindow()); } @@ -930,6 +930,48 @@ EXPECT_TRUE(AreEventsBlocked()); } +// Test that internal keyboard and mouse are not disabled in docked mode. +TEST_F(TabletModeControllerTest, InternalKeyboardMouseInDockedModeTest) { + UpdateDisplay("800x600, 800x600"); + const int64_t internal_display_id = + display::test::DisplayManagerTestApi(display_manager()) + .SetFirstDisplayAsInternalDisplay(); + EXPECT_FALSE(IsTabletModeStarted()); + // Input devices events are unblocked. + EXPECT_FALSE(AreEventsBlocked()); + EXPECT_TRUE(display::Display::HasInternalDisplay()); + EXPECT_TRUE( + Shell::Get()->display_manager()->IsActiveDisplayId(internal_display_id)); + + // Enter tablet mode first. + SetTabletMode(true); + EXPECT_TRUE(IsTabletModeStarted()); + EXPECT_TRUE(AreEventsBlocked()); + + // Deactivate internal display to simulate Docked Mode. + std::vector<display::ManagedDisplayInfo> all_displays; + all_displays.push_back(display_manager()->GetDisplayInfo( + display_manager()->GetDisplayAt(0).id())); + std::vector<display::ManagedDisplayInfo> secondary_only; + display::ManagedDisplayInfo secondary_display = + display_manager()->GetDisplayInfo( + display_manager()->GetDisplayAt(1).id()); + all_displays.push_back(secondary_display); + secondary_only.push_back(secondary_display); + display_manager()->OnNativeDisplaysChanged(secondary_only); + ASSERT_FALSE(display_manager()->IsActiveDisplayId(internal_display_id)); + // We should now enter in clamshell mode when the device is docked. + EXPECT_FALSE(IsTabletModeStarted()); + EXPECT_FALSE(AreEventsBlocked()); + + // Exiting docked state should enter tablet mode again. + display_manager()->OnNativeDisplaysChanged(all_displays); + display::test::DisplayManagerTestApi(display_manager()) + .SetFirstDisplayAsInternalDisplay(); + EXPECT_TRUE(IsTabletModeStarted()); + EXPECT_TRUE(AreEventsBlocked()); +} + class TabletModeControllerForceTabletModeTest : public TabletModeControllerTest { public:
diff --git a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc index 7b8c909..725799a 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
@@ -7,11 +7,11 @@ #include "ash/root_window_controller.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shell.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_item.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/overview/overview_utils.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_item.h" #include "ash/wm/root_window_finder.h" #include "ash/wm/splitview/split_view_constants.h" #include "ash/wm/splitview/split_view_controller.h" @@ -31,36 +31,36 @@ // tablet mode. constexpr float kIndicatorsThresholdRatio = 0.1; -// Returns the window selector if overview mode is active, otherwise returns +// Returns the overview session if overview mode is active, otherwise returns // nullptr. -WindowSelector* GetWindowSelector() { - return Shell::Get()->window_selector_controller()->IsSelecting() - ? Shell::Get()->window_selector_controller()->window_selector() +OverviewSession* GetOverviewSession() { + return Shell::Get()->overview_controller()->IsSelecting() + ? Shell::Get()->overview_controller()->overview_session() : nullptr; } -WindowGrid* GetWindowGrid(aura::Window* dragged_window) { - if (!GetWindowSelector()) +OverviewGrid* GetOverviewGrid(aura::Window* dragged_window) { + if (!GetOverviewSession()) return nullptr; - return GetWindowSelector()->GetGridWithRootWindow( + return GetOverviewSession()->GetGridWithRootWindow( dragged_window->GetRootWindow()); } // Returns the drop target in overview during drag. -WindowSelectorItem* GetDropTarget(aura::Window* dragged_window) { - WindowGrid* window_grid = GetWindowGrid(dragged_window); - if (!window_grid || window_grid->empty()) +OverviewItem* GetDropTarget(aura::Window* dragged_window) { + OverviewGrid* overview_grid = GetOverviewGrid(dragged_window); + if (!overview_grid || overview_grid->empty()) return nullptr; - return window_grid->GetDropTarget(); + return overview_grid->GetDropTarget(); } // Gets the bounds of selected drop target in overview grid that is displaying // in the same root window as |dragged_window|. Note that the returned bounds is // scaled-up. gfx::Rect GetBoundsOfSelectedDropTarget(aura::Window* dragged_window) { - WindowSelectorItem* drop_target = GetDropTarget(dragged_window); + OverviewItem* drop_target = GetDropTarget(dragged_window); if (!drop_target) return gfx::Rect(); @@ -101,8 +101,7 @@ dragged_window_->SetProperty(kBackdropWindowMode, BackdropWindowMode::kDisabled); - WindowSelectorController* controller = - Shell::Get()->window_selector_controller(); + OverviewController* controller = Shell::Get()->overview_controller(); bool was_overview_open = controller->IsSelecting(); // If the dragged window is one of the snapped windows, SplitViewController @@ -111,14 +110,14 @@ if (ShouldOpenOverviewWhenDragStarts() && !controller->IsSelecting()) { controller->ToggleOverview( - WindowSelector::EnterExitOverviewType::kWindowDragged); + OverviewSession::EnterExitOverviewType::kWindowDragged); } if (controller->IsSelecting()) { // Only do animation if overview was open before the drag started. If the // overview is opened because of the window drag, do not do animation. - GetWindowSelector()->OnWindowDragStarted(dragged_window_, - /*animate=*/was_overview_open); + GetOverviewSession()->OnWindowDragStarted(dragged_window_, + /*animate=*/was_overview_open); } bounds_of_selected_drop_target_ = @@ -171,8 +170,8 @@ split_view_drag_indicators_->SetIndicatorState(indicator_state, location_in_screen); - if (GetWindowSelector()) { - GetWindowSelector()->OnWindowDragContinued( + if (GetOverviewSession()) { + GetOverviewSession()->OnWindowDragContinued( dragged_window_, location_in_screen, indicator_state); } } @@ -191,8 +190,8 @@ // The window might merge into an overview window or become a new window item // in overview mode. - if (GetWindowSelector()) { - GetWindowSelector()->OnWindowDragEnded( + if (GetOverviewSession()) { + GetOverviewSession()->OnWindowDragEnded( dragged_window_, location_in_screen, ShouldDropWindowIntoOverview(snap_position, location_in_screen)); } @@ -336,7 +335,7 @@ void TabletModeWindowDragDelegate::UpdateDraggedWindowTransform( const gfx::Point& location_in_screen) { - DCHECK(Shell::Get()->window_selector_controller()->IsSelecting()); + DCHECK(Shell::Get()->overview_controller()->IsSelecting()); // Calculate the desired scale along the y-axis. The scale of the window // during drag is based on the distance from |y_location_in_screen| to the y @@ -369,15 +368,15 @@ if (snap_position != SplitViewController::NONE && !is_split_view_active) return false; - WindowSelectorItem* drop_target = GetDropTarget(dragged_window_); + OverviewItem* drop_target = GetDropTarget(dragged_window_); if (!drop_target) return false; - WindowGrid* window_grid = GetWindowGrid(dragged_window_); + OverviewGrid* overview_grid = GetOverviewGrid(dragged_window_); aura::Window* target_window = - window_grid->GetTargetWindowOnLocation(location_in_screen); + overview_grid->GetTargetWindowOnLocation(location_in_screen); const bool is_drop_target_selected = - target_window && window_grid->IsDropTargetWindow(target_window); + target_window && overview_grid->IsDropTargetWindow(target_window); // TODO(crbug.com/878294): Should also consider drag distance when splitview // is active. @@ -404,7 +403,7 @@ // overview is not opened when drag starts (if it's tab-dragging and the // dragged window is not the same with the source window), we should not fling // the dragged window into overview in this case. - if (!Shell::Get()->window_selector_controller()->IsSelecting()) + if (!Shell::Get()->overview_controller()->IsSelecting()) return false; const gfx::Point location_in_screen = GetEventLocationInScreen(event);
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc index 1169941..b3d84a2 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -11,7 +11,7 @@ #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/tablet_mode/scoped_skip_user_session_blocked_check.h" #include "ash/wm/tablet_mode/tablet_mode_backdrop_delegate_impl.h" #include "ash/wm/tablet_mode/tablet_mode_event_handler.h" @@ -30,8 +30,7 @@ // Exits overview mode if it is currently active. void CancelOverview() { - WindowSelectorController* controller = - Shell::Get()->window_selector_controller(); + OverviewController* controller = Shell::Get()->overview_controller(); if (controller->IsSelecting()) controller->OnSelectionEnded(); } @@ -89,10 +88,10 @@ } void TabletModeWindowManager::OnOverviewModeEnding( - WindowSelector* window_selector) { + OverviewSession* overview_session) { exit_overview_by_window_drag_ = - window_selector->enter_exit_overview_type() == - WindowSelector::EnterExitOverviewType::kWindowDragged; + overview_session->enter_exit_overview_type() == + OverviewSession::EnterExitOverviewType::kWindowDragged; } void TabletModeWindowManager::OnOverviewModeEnded() { @@ -259,7 +258,7 @@ } else { // If split view mode is ended when overview mode is still active, defer // all bounds change until overview mode is ended. - if (Shell::Get()->window_selector_controller()->IsSelecting()) { + if (Shell::Get()->overview_controller()->IsSelecting()) { for (auto& pair : window_state_map_) SetDeferBoundsUpdates(pair.first, true); } @@ -347,7 +346,7 @@ Shell::Get()->split_view_controller(); split_view_controller->SnapWindow(windows[0], curr_win_snap_pos); if (prev_win_snap_pos == SplitViewController::NONE) - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); else split_view_controller->SnapWindow(windows[1], prev_win_snap_pos);
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.h b/ash/wm/tablet_mode/tablet_mode_window_manager.h index aa3617c..98227bd 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_manager.h +++ b/ash/wm/tablet_mode/tablet_mode_window_manager.h
@@ -59,7 +59,7 @@ // ShellObserver: void OnOverviewModeStarting() override; - void OnOverviewModeEnding(WindowSelector* window_selector) override; + void OnOverviewModeEnding(OverviewSession* overview_session) override; void OnOverviewModeEnded() override; void OnSplitViewModeEnded() override;
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc index b74495a..c602c1d 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
@@ -19,7 +19,7 @@ #include "ash/shell_test_api.h" #include "ash/test/ash_test_base.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/switchable_windows.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" @@ -1330,20 +1330,19 @@ std::unique_ptr<aura::Window> w2( CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect2)); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - ASSERT_TRUE(window_selector_controller->ToggleOverview()); - ASSERT_TRUE(window_selector_controller->IsSelecting()); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + ASSERT_TRUE(overview_controller->ToggleOverview()); + ASSERT_TRUE(overview_controller->IsSelecting()); TabletModeWindowManager* manager = CreateTabletModeWindowManager(); ASSERT_TRUE(manager); - EXPECT_FALSE(window_selector_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->IsSelecting()); - ASSERT_TRUE(window_selector_controller->ToggleOverview()); - ASSERT_TRUE(window_selector_controller->IsSelecting()); + ASSERT_TRUE(overview_controller->ToggleOverview()); + ASSERT_TRUE(overview_controller->IsSelecting()); // Destroy the manager again and check that the windows return to their // previous state. DestroyTabletModeWindowManager(); - EXPECT_FALSE(window_selector_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->IsSelecting()); } // Test that an edge swipe from the top will end full screen mode. @@ -1789,14 +1788,13 @@ EXPECT_TRUE(window_state->IsMinimized()); EXPECT_EQ(window->bounds(), rect); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - window_selector_controller->ToggleOverview(); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + overview_controller->ToggleOverview(); EXPECT_EQ(window->bounds(), rect); // Exit overview mode will update all windows' bounds. However, if the window // is minimized, the bounds will not be updated. - window_selector_controller->ToggleOverview(); + overview_controller->ToggleOverview(); EXPECT_EQ(window->bounds(), rect); } @@ -1841,7 +1839,7 @@ ::wm::ActivateWindow(window.get()); ASSERT_TRUE(CreateTabletModeWindowManager()); EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller->state()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); } // Test that if the active window is snapped on the left before tablet mode, @@ -1854,7 +1852,7 @@ ASSERT_TRUE(CreateTabletModeWindowManager()); EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state()); EXPECT_EQ(window.get(), split_view_controller->left_window()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); } // Test that if the active window is snapped on the right before tablet mode, @@ -1867,7 +1865,7 @@ ASSERT_TRUE(CreateTabletModeWindowManager()); EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, split_view_controller->state()); EXPECT_EQ(window.get(), split_view_controller->right_window()); - EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); } // Test that if before tablet mode, the active window is snapped on the left and @@ -1884,7 +1882,7 @@ EXPECT_EQ(SplitViewController::BOTH_SNAPPED, split_view_controller->state()); EXPECT_EQ(left_window.get(), split_view_controller->left_window()); EXPECT_EQ(right_window.get(), split_view_controller->right_window()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); } // Test that if before tablet mode, the active window is snapped on the right @@ -1901,7 +1899,7 @@ EXPECT_EQ(SplitViewController::BOTH_SNAPPED, split_view_controller->state()); EXPECT_EQ(left_window.get(), split_view_controller->left_window()); EXPECT_EQ(right_window.get(), split_view_controller->right_window()); - EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); } } // namespace ash
diff --git a/ash/wm/window_finder.cc b/ash/wm/window_finder.cc index 45d7f2071..dff3aa7 100644 --- a/ash/wm/window_finder.cc +++ b/ash/wm/window_finder.cc
@@ -6,9 +6,9 @@ #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/root_window_finder.h" #include "services/ws/window_service.h" #include "ui/aura/client/screen_position_client.h" @@ -94,13 +94,13 @@ aura::Window* GetToplevelWindowInOverviewAtPoint( const gfx::Point& screen_point, const std::set<aura::Window*>& ignore) { - ash::WindowSelectorController* window_selector_controller = - ash::Shell::Get()->window_selector_controller(); - if (!window_selector_controller->IsSelecting()) + ash::OverviewController* overview_controller = + ash::Shell::Get()->overview_controller(); + if (!overview_controller->IsSelecting()) return nullptr; - ash::WindowGrid* grid = - window_selector_controller->window_selector()->GetGridWithRootWindow( + ash::OverviewGrid* grid = + overview_controller->overview_session()->GetGridWithRootWindow( ash::wm::GetRootWindowAt(screen_point)); if (!grid) return nullptr;
diff --git a/ash/wm/window_finder_unittest.cc b/ash/wm/window_finder_unittest.cc index 4c63753d0..c031b42b 100644 --- a/ash/wm/window_finder_unittest.cc +++ b/ash/wm/window_finder_unittest.cc
@@ -7,10 +7,10 @@ #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_item.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_grid.h" +#include "ash/wm/overview/overview_item.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/window_state.h" #include "ui/aura/window_targeter.h" #include "ui/compositor/layer_type.h" @@ -133,19 +133,18 @@ std::unique_ptr<aura::Window> window2 = CreateTestWindow(gfx::Rect(0, 0, 100, 100)); - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - window_selector_controller->ToggleOverview(); - EXPECT_TRUE(window_selector_controller->IsSelecting()); + OverviewController* overview_controller = Shell::Get()->overview_controller(); + overview_controller->ToggleOverview(); + EXPECT_TRUE(overview_controller->IsSelecting()); // Get |window1| and |window2|'s transformed bounds in overview. - WindowGrid* grid = - window_selector_controller->window_selector()->GetGridWithRootWindow( + OverviewGrid* grid = + overview_controller->overview_session()->GetGridWithRootWindow( window1->GetRootWindow()); gfx::Rect bounds1 = - grid->GetWindowSelectorItemContaining(window1.get())->target_bounds(); + grid->GetOverviewItemContaining(window1.get())->target_bounds(); gfx::Rect bounds2 = - grid->GetWindowSelectorItemContaining(window2.get())->target_bounds(); + grid->GetOverviewItemContaining(window2.get())->target_bounds(); std::set<aura::Window*> ignore; aura::Window* real_topmost = nullptr;
diff --git a/ash/wm/window_properties.cc b/ash/wm/window_properties.cc index b0ac78f..19993c8f 100644 --- a/ash/wm/window_properties.cc +++ b/ash/wm/window_properties.cc
@@ -7,7 +7,7 @@ #include "ash/wm/window_state.h" #include "ui/gfx/geometry/rect.h" -DEFINE_UI_CLASS_PROPERTY_TYPE(ash::wm::WindowState*); +DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(ASH_EXPORT, ash::wm::WindowState*); DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(ASH_EXPORT, ash::WidgetCreationType); namespace ash {
diff --git a/ash/wm/window_properties.h b/ash/wm/window_properties.h index d1b1a36c..c243e56 100644 --- a/ash/wm/window_properties.h +++ b/ash/wm/window_properties.h
@@ -56,7 +56,8 @@ // A property key to store WindowState in the window. The window state // is owned by the window. -extern const aura::WindowProperty<wm::WindowState*>* const kWindowStateKey; +ASH_EXPORT extern const aura::WindowProperty<wm::WindowState*>* const + kWindowStateKey; // Alphabetical sort.
diff --git a/ash/wm/wm_shadow_controller_delegate.cc b/ash/wm/wm_shadow_controller_delegate.cc index 32fc9f0..08ba76e 100644 --- a/ash/wm/wm_shadow_controller_delegate.cc +++ b/ash/wm/wm_shadow_controller_delegate.cc
@@ -5,8 +5,8 @@ #include "ash/wm/wm_shadow_controller_delegate.h" #include "ash/shell.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" +#include "ash/wm/overview/overview_session.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/window_state.h" #include "ui/aura/client/aura_constants.h" @@ -31,14 +31,12 @@ } // Hide the shadow while we are in overview mode. - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - if (window_selector_controller && window_selector_controller->IsSelecting()) { - WindowSelector* window_selector = - window_selector_controller->window_selector(); - // IsSelecting() being true implies |window_selector| exists. - DCHECK(window_selector); - if (window_selector->IsWindowInOverview(window)) + OverviewController* overview_controller = Shell::Get()->overview_controller(); + if (overview_controller && overview_controller->IsSelecting()) { + OverviewSession* overview_session = overview_controller->overview_session(); + // IsSelecting() being true implies |overview_session| exists. + DCHECK(overview_session); + if (overview_session->IsWindowInOverview(window)) return false; }
diff --git a/ash/wm/workspace/backdrop_controller.cc b/ash/wm/workspace/backdrop_controller.cc index 851a4b1..a7135085 100644 --- a/ash/wm/workspace/backdrop_controller.cc +++ b/ash/wm/workspace/backdrop_controller.cc
@@ -18,7 +18,7 @@ #include "ash/screen_util.h" #include "ash/shell.h" #include "ash/wallpaper/wallpaper_controller.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace/backdrop_delegate.h" @@ -121,10 +121,9 @@ void BackdropController::UpdateBackdrop() { // No need to continue update for recursive calls or in overview mode. - WindowSelectorController* window_selector_controller = - Shell::Get()->window_selector_controller(); - if (pause_update_ || (window_selector_controller && - window_selector_controller->IsSelecting())) { + OverviewController* overview_controller = Shell::Get()->overview_controller(); + if (pause_update_ || + (overview_controller && overview_controller->IsSelecting())) { return; } @@ -161,7 +160,8 @@ Hide(); } -void BackdropController::OnOverviewModeEnding(WindowSelector* window_selector) { +void BackdropController::OnOverviewModeEnding( + OverviewSession* overview_session) { pause_update_ = true; }
diff --git a/ash/wm/workspace/backdrop_controller.h b/ash/wm/workspace/backdrop_controller.h index 3c0d893..33a35c4a 100644 --- a/ash/wm/workspace/backdrop_controller.h +++ b/ash/wm/workspace/backdrop_controller.h
@@ -69,7 +69,7 @@ // ShellObserver: void OnOverviewModeStarting() override; - void OnOverviewModeEnding(WindowSelector* window_selector) override; + void OnOverviewModeEnding(OverviewSession* overview_session) override; void OnOverviewModeEndingAnimationComplete(bool canceled) override; void OnAppListVisibilityChanged(bool shown, aura::Window* root_window) override;
diff --git a/ash/wm/workspace/multi_window_resize_controller.cc b/ash/wm/workspace/multi_window_resize_controller.cc index 9212e6e..291c0002 100644 --- a/ash/wm/workspace/multi_window_resize_controller.cc +++ b/ash/wm/workspace/multi_window_resize_controller.cc
@@ -9,6 +9,8 @@ #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace/workspace_window_resizer.h" +#include "services/ws/public/mojom/window_tree_constants.mojom.h" +#include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" #include "ui/base/cursor/cursor.h" @@ -76,6 +78,25 @@ return ContainsY(window, window_loc.y()); } +// Returns true if |p| is on the edge |edge_want| of |window|. +bool PointOnWindowEdge(aura::Window* window, + int edge_want, + const gfx::Point& p) { + switch (edge_want) { + case HTLEFT: + return ContainsY(window, p.y()) && p.x() == 0; + case HTRIGHT: + return ContainsY(window, p.y()) && p.x() == window->bounds().width(); + case HTTOP: + return ContainsX(window, p.x()) && p.y() == 0; + case HTBOTTOM: + return ContainsX(window, p.x()) && p.y() == window->bounds().height(); + default: + NOTREACHED(); + return false; + } +} + bool Intersects(int x1, int max_1, int x2, int max_2) { return x2 <= max_1 && max_2 > x1; } @@ -238,6 +259,15 @@ Hide(); } +void MultiWindowResizeController::OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) { + // If the window is now non-resizeable, make sure the resizer is not showing. + if ((window->GetProperty(aura::client::kResizeBehaviorKey) & + ws::mojom::kResizeBehaviorCanResize) == 0) + ResetResizer(); +} + void MultiWindowResizeController::OnWindowVisibilityChanged( aura::Window* window, bool visible) { @@ -282,6 +312,12 @@ int window_component, const gfx::Point& point) const { ResizeWindows result; + + // Check if the window is non-resizeable. + if ((window->GetProperty(aura::client::kResizeBehaviorKey) & + ws::mojom::kResizeBehaviorCanResize) == 0) + return result; + gfx::Point point_in_parent = ConvertPointToTarget(window, window->parent(), point); switch (window_component) { @@ -331,30 +367,19 @@ if (!window->delegate()) continue; - gfx::Point p = ConvertPointToTarget(parent, window, - gfx::Point(x_in_parent, y_in_parent)); - switch (edge_want) { - case HTLEFT: - if (ContainsY(window, p.y()) && p.x() == 0) - return window; - break; - case HTRIGHT: - if (ContainsY(window, p.y()) && p.x() == window->bounds().width()) - return window; - break; - case HTTOP: - if (ContainsX(window, p.x()) && p.y() == 0) - return window; - break; - case HTBOTTOM: - if (ContainsX(window, p.x()) && p.y() == window->bounds().height()) - return window; - break; - default: - NOTREACHED(); + // Return the window if it is resizeable and the wanted edge has the point. + if ((window->GetProperty(aura::client::kResizeBehaviorKey) & + ws::mojom::kResizeBehaviorCanResize) != 0 && + PointOnWindowEdge( + window, edge_want, + ConvertPointToTarget(parent, window, + gfx::Point(x_in_parent, y_in_parent)))) { + return window; } - // Window doesn't contain the edge, but if window contains |point| - // it's obscuring any other window that could be at the location. + + // Having determined that the window is not a suitable return value, if it + // contains the point, then it is obscuring that point on any remaining + // window that also contains the point. if (window->bounds().Contains(x_in_parent, y_in_parent)) return NULL; }
diff --git a/ash/wm/workspace/multi_window_resize_controller.h b/ash/wm/workspace/multi_window_resize_controller.h index 5f46ddf..0d561429 100644 --- a/ash/wm/workspace/multi_window_resize_controller.h +++ b/ash/wm/workspace/multi_window_resize_controller.h
@@ -49,6 +49,9 @@ void MouseMovedOutOfHost() override; // WindowObserver: + void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) override; void OnWindowVisibilityChanged(aura::Window* window, bool visible) override; void OnWindowDestroying(aura::Window* window) override;
diff --git a/ash/wm/workspace/multi_window_resize_controller_unittest.cc b/ash/wm/workspace/multi_window_resize_controller_unittest.cc index 5d14ea5..03fd167 100644 --- a/ash/wm/workspace/multi_window_resize_controller_unittest.cc +++ b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
@@ -429,6 +429,94 @@ EXPECT_FALSE(IsShowing()); } +// Tests that the resizer does not appear while the mouse resides in a +// non-resizeable window. +TEST_F(MultiWindowResizeControllerTest, NonResizeableWindowTestA) { + aura::test::TestWindowDelegate delegate1; + std::unique_ptr<aura::Window> w1(CreateTestWindowInShellWithDelegate( + &delegate1, -1, gfx::Rect(0, 0, 100, 100))); + delegate1.set_window_component(HTRIGHT); + aura::test::TestWindowDelegate delegate2; + std::unique_ptr<aura::Window> w2(CreateTestWindowInShellWithDelegate( + &delegate2, -2, gfx::Rect(0, 0, 100, 100))); + w2->SetProperty(aura::client::kResizeBehaviorKey, 0); + delegate2.set_window_component(HTRIGHT); + aura::test::TestWindowDelegate delegate3; + std::unique_ptr<aura::Window> w3(CreateTestWindowInShellWithDelegate( + &delegate3, -3, gfx::Rect(100, 0, 100, 100))); + delegate3.set_window_component(HTRIGHT); + ui::test::EventGenerator* generator = GetEventGenerator(); + generator->MoveMouseTo(w1->bounds().CenterPoint()); + EXPECT_FALSE(HasPendingShow()); +} + +// Tests that the resizer does not appear while the mouse resides in a window +// bordering two other windows, one of which is non-resizeable and obscures the +// other. +TEST_F(MultiWindowResizeControllerTest, NonResizeableWindowTestB) { + aura::test::TestWindowDelegate delegate1; + std::unique_ptr<aura::Window> w1(CreateTestWindowInShellWithDelegate( + &delegate1, -1, gfx::Rect(0, 0, 100, 100))); + delegate1.set_window_component(HTRIGHT); + aura::test::TestWindowDelegate delegate2; + std::unique_ptr<aura::Window> w2(CreateTestWindowInShellWithDelegate( + &delegate2, -2, gfx::Rect(100, 0, 100, 100))); + delegate2.set_window_component(HTRIGHT); + aura::test::TestWindowDelegate delegate3; + std::unique_ptr<aura::Window> w3(CreateTestWindowInShellWithDelegate( + &delegate3, -3, gfx::Rect(100, 0, 100, 100))); + w3->SetProperty(aura::client::kResizeBehaviorKey, 0); + delegate3.set_window_component(HTRIGHT); + ui::test::EventGenerator* generator = GetEventGenerator(); + generator->MoveMouseTo(w1->bounds().CenterPoint()); + EXPECT_FALSE(HasPendingShow()); +} + +// Tests that the resizer appears while the mouse resides in a window bordering +// two other windows, one of which is non-resizeable but obscured by the other. +TEST_F(MultiWindowResizeControllerTest, NonResizeableWindowTestC) { + aura::test::TestWindowDelegate delegate1; + std::unique_ptr<aura::Window> w1(CreateTestWindowInShellWithDelegate( + &delegate1, -1, gfx::Rect(0, 0, 100, 100))); + delegate1.set_window_component(HTRIGHT); + aura::test::TestWindowDelegate delegate2; + std::unique_ptr<aura::Window> w2(CreateTestWindowInShellWithDelegate( + &delegate2, -2, gfx::Rect(100, 0, 100, 100))); + w2->SetProperty(aura::client::kResizeBehaviorKey, 0); + delegate2.set_window_component(HTRIGHT); + aura::test::TestWindowDelegate delegate3; + std::unique_ptr<aura::Window> w3(CreateTestWindowInShellWithDelegate( + &delegate3, -3, gfx::Rect(100, 0, 100, 100))); + delegate3.set_window_component(HTRIGHT); + ui::test::EventGenerator* generator = GetEventGenerator(); + generator->MoveMouseTo(w1->bounds().CenterPoint()); + EXPECT_TRUE(HasPendingShow()); + EXPECT_FALSE(HasTarget(w2.get())); +} + +// Tests that the resizer is dismissed when one of the resized windows becomes +// non-resizeable. +TEST_F(MultiWindowResizeControllerTest, MakeWindowNonResizeable) { + aura::test::TestWindowDelegate delegate1; + std::unique_ptr<aura::Window> w1(CreateTestWindowInShellWithDelegate( + &delegate1, -1, gfx::Rect(0, 0, 100, 100))); + delegate1.set_window_component(HTRIGHT); + aura::test::TestWindowDelegate delegate2; + std::unique_ptr<aura::Window> w2(CreateTestWindowInShellWithDelegate( + &delegate2, -2, gfx::Rect(100, 0, 100, 100))); + delegate2.set_window_component(HTLEFT); + + ui::test::EventGenerator* generator = GetEventGenerator(); + gfx::Point w1_center_in_screen = w1->GetBoundsInScreen().CenterPoint(); + generator->MoveMouseTo(w1_center_in_screen); + ShowNow(); + EXPECT_TRUE(IsShowing()); + + // Making one window non-resizeable should dismiss the resizer. + w1->SetProperty(aura::client::kResizeBehaviorKey, 0); + EXPECT_FALSE(IsShowing()); +} + namespace { class TestWindowStateDelegate : public wm::WindowStateDelegate {
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc index 5ec0ea2..3b6aef2 100644 --- a/ash/wm/workspace/workspace_layout_manager.cc +++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -259,6 +259,13 @@ const HierarchyChangeParams& params) { if (params.new_parent && params.new_parent == settings_bubble_container_) settings_bubble_window_observer_.ObserveWindow(params.target); + // The window should have a parent (unless it's being removed), so we can + // create WindowState, which requires its parent. (crbug.com/924305) + // TODO(oshima): Change this to |EnsureWindowState|, then change + // GetWindowState so that it simply returns the WindowState associated with + // the window, or nullptr. + if (params.new_parent) + wm::GetWindowState(params.target); if (!wm::IsActiveWindow(params.target)) return;
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc index 5740cccf..50dcfb54 100644 --- a/ash/wm/workspace/workspace_layout_manager_unittest.cc +++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -30,10 +30,11 @@ #include "ash/wallpaper/wallpaper_controller_test_api.h" #include "ash/window_factory.h" #include "ash/wm/fullscreen_window_finder.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_backdrop_delegate_impl.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" +#include "ash/wm/window_properties.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "ash/wm/wm_event.h" @@ -682,6 +683,17 @@ EXPECT_EQ(expected_bounds.ToString(), window2->bounds().ToString()); } +TEST_F(WorkspaceLayoutManagerTest, EnsureWindowStateInOverlay) { + std::unique_ptr<aura::Window> window = + window_factory::NewWindow(nullptr, aura::client::WINDOW_TYPE_NORMAL); + window->Init(ui::LAYER_TEXTURED); + auto* overlay_container = + Shell::GetPrimaryRootWindowController()->GetContainer( + kShellWindowId_OverlayContainer); + overlay_container->AddChild(window.get()); + EXPECT_TRUE(window->GetProperty(kWindowStateKey)); +} + // Following "Solo" tests were originally written for BaseLayoutManager. using WorkspaceLayoutManagerSoloTest = AshTestBase; @@ -1302,11 +1314,11 @@ } // Toggle overview. - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(test_helper.GetBackdropWindow()); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); base::RunLoop().RunUntilIdle(); backdrop = test_helper.GetBackdropWindow(); EXPECT_TRUE(backdrop); @@ -1332,10 +1344,10 @@ } // Toggle overview with the delegate. - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(test_helper.GetBackdropWindow()); - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); base::RunLoop().RunUntilIdle(); backdrop = test_helper.GetBackdropWindow(); { @@ -1495,7 +1507,7 @@ EXPECT_TRUE(test_helper.GetBackdropWindow()); // Toggle overview button to enter overview mode. - Shell::Get()->window_selector_controller()->ToggleOverview(); + Shell::Get()->overview_controller()->ToggleOverview(); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(test_helper.GetBackdropWindow());
diff --git a/ash/wm/workspace_controller.cc b/ash/wm/workspace_controller.cc index b5bed153..df3e76e 100644 --- a/ash/wm/workspace_controller.cc +++ b/ash/wm/workspace_controller.cc
@@ -12,7 +12,7 @@ #include "ash/shell.h" #include "ash/wm/fullscreen_window_finder.h" #include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/window_state.h" #include "ash/wm/wm_window_animations.h" #include "ash/wm/workspace/backdrop_controller.h" @@ -59,9 +59,9 @@ // Always use DEFAULT state in overview mode so that work area stays // the same regardles of the window we have. - // The |window_selector_controller| can be null during shutdown. - if (Shell::Get()->window_selector_controller() && - Shell::Get()->window_selector_controller()->IsSelecting()) { + // The |overview_controller| can be null during shutdown. + if (Shell::Get()->overview_controller() && + Shell::Get()->overview_controller()->IsSelecting()) { return wm::WORKSPACE_WINDOW_STATE_DEFAULT; }
diff --git a/base/README.md b/base/README.md index 6a1ede35..da452ce 100644 --- a/base/README.md +++ b/base/README.md
@@ -32,6 +32,16 @@ Owners are added when a contributor has shown the above qualifications and when they express interest. There isn't an upper bound on the number of OWNERS. +## Design and naming + * Be sure to use the base namespace. + * STL-like constructs should adhere as closely to STL as possible. Functions + and behaviors not present in STL should only be added when they are related + to the specific data structure implemented by the container. + * For STL-like constructs our policy is that they should use STL-like naming + even when it may conflict with the style guide. So functions and class names + should be lower case with underscores. Non-STL-like classes and functions + should use Google naming. + ## Performance testing Since the primitives provided by //base are used very widely, it is important to
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc index 15c8c3d4..2d402355 100644 --- a/base/allocator/partition_allocator/partition_alloc_unittest.cc +++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -22,9 +22,7 @@ #if defined(OS_POSIX) #include <sys/mman.h> -#if !defined(OS_FUCHSIA) #include <sys/resource.h> -#endif #include <sys/time.h> #endif // defined(OS_POSIX) @@ -74,7 +72,7 @@ } bool ClearAddressSpaceLimit() { -#if !defined(ARCH_CPU_64_BITS) || !defined(OS_POSIX) || defined(OS_FUCHSIA) +#if !defined(ARCH_CPU_64_BITS) || !defined(OS_POSIX) return true; #elif defined(OS_POSIX) struct rlimit limit; @@ -1352,8 +1350,7 @@ // cause flake. #if !defined(OS_WIN) && \ (!defined(ARCH_CPU_64_BITS) || \ - (defined(OS_POSIX) && \ - !(defined(OS_FUCHSIA) || defined(OS_MACOSX) || defined(OS_ANDROID)))) + (defined(OS_POSIX) && !(defined(OS_MACOSX) || defined(OS_ANDROID)))) // The following four tests wrap a called function in an expect death statement // to perform their test, because they are non-hermetic. Specifically they are @@ -1401,7 +1398,7 @@ } #endif // !defined(ARCH_CPU_64_BITS) || (defined(OS_POSIX) && - // !(defined(OS_FUCHSIA) || defined(OS_MACOSX) || defined(OS_ANDROID))) + // !(defined(OS_MACOSX) || defined(OS_ANDROID))) // Make sure that malloc(-1) dies. // In the past, we had an integer overflow that would alias malloc(-1) to
diff --git a/base/android/jni_generator/AndroidManifest.xml b/base/android/jni_generator/AndroidManifest.xml index ec28ff5..59a72d6 100644 --- a/base/android/jni_generator/AndroidManifest.xml +++ b/base/android/jni_generator/AndroidManifest.xml
@@ -7,7 +7,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.jni.generator"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="24" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24" /> <application></application> </manifest>
diff --git a/base/android/orderfile/BUILD.gn b/base/android/orderfile/BUILD.gn index ff0bfff..41a372f 100644 --- a/base/android/orderfile/BUILD.gn +++ b/base/android/orderfile/BUILD.gn
@@ -4,7 +4,7 @@ import("//build/config/android/config.gni") -if (use_order_profiling && target_cpu == "arm") { +if (use_order_profiling && (target_cpu == "arm" || target_cpu == "arm64")) { static_library("orderfile_instrumentation") { sources = [ "orderfile_instrumentation.cc",
diff --git a/base/android/orderfile/orderfile_instrumentation.cc b/base/android/orderfile/orderfile_instrumentation.cc index f06cc20..f6de6cef 100644 --- a/base/android/orderfile/orderfile_instrumentation.cc +++ b/base/android/orderfile/orderfile_instrumentation.cc
@@ -32,9 +32,9 @@ #include "base/trace_event/memory_dump_provider.h" #endif // BUILDFLAG(DEVTOOLS_INSTRUMENTATION_DUMPING) -#if !defined(ARCH_CPU_ARMEL) -#error Only supported on ARM. -#endif // !defined(ARCH_CPU_ARMEL) +#if !BUILDFLAG(SUPPORTS_CODE_ORDERING) +#error Only supported on architectures supporting code ordering (arm/arm64). +#endif // !BUILDFLAG(SUPPORTS_CODE_ORDERING) // Must be applied to all functions within this file. #define NO_INSTRUMENT_FUNCTION __attribute__((no_instrument_function))
diff --git a/base/containers/README.md b/base/containers/README.md index e788262b..4adc38d36 100644 --- a/base/containers/README.md +++ b/base/containers/README.md
@@ -14,6 +14,8 @@ ### Design and naming +Fundamental [//base principles](../README.md#design-and-naming) apply, i.e.: + Containers should adhere as closely to STL as possible. Functions and behaviors not present in STL should only be added when they are related to the specific data structure implemented by the container.
diff --git a/base/cpu.cc b/base/cpu.cc index 3a0f6fa0..66caa09 100644 --- a/base/cpu.cc +++ b/base/cpu.cc
@@ -79,18 +79,22 @@ } #endif +#endif // !defined(COMPILER_MSVC) -// _xgetbv returns the value of an Intel Extended Control Register (XCR). +// xgetbv returns the value of an Intel Extended Control Register (XCR). // Currently only XCR0 is defined by Intel so |xcr| should always be zero. -uint64_t _xgetbv(uint32_t xcr) { +uint64_t xgetbv(uint32_t xcr) { +#if defined(COMPILER_MSVC) + return _xgetbv(xcr); +#else uint32_t eax, edx; __asm__ volatile ( "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr)); return (static_cast<uint64_t>(edx) << 32) | eax; +#endif // defined(COMPILER_MSVC) } -#endif // !defined(COMPILER_MSVC) #endif // ARCH_CPU_X86_FAMILY #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) @@ -198,7 +202,7 @@ (cpu_info[2] & 0x10000000) != 0 && (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ && (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ && - (_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */; + (xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */; has_aesni_ = (cpu_info[2] & 0x02000000) != 0; has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 0; }
diff --git a/base/debug/task_annotator.cc b/base/debug/task_annotator.cc index 382bb39..88b0837 100644 --- a/base/debug/task_annotator.cc +++ b/base/debug/task_annotator.cc
@@ -80,8 +80,14 @@ // Store a marker to locate |task_backtrace| content easily on a memory // dump. - task_backtrace.front() = reinterpret_cast<void*>(0xefefefefefefefef); - task_backtrace.back() = reinterpret_cast<void*>(0xfefefefefefefefe); + // + // Markers glossary (compliments of wez): + // cool code,do it dude! + // 0x c001 c0de d0 17 d00d + // o dude,i did it biig + // 0x 0 d00d 1 d1d 17 8119 + task_backtrace.front() = reinterpret_cast<void*>(0xc001c0ded017d00d); + task_backtrace.back() = reinterpret_cast<void*>(0x0d00d1d1d178119); task_backtrace[1] = pending_task->posted_from.program_counter(); std::copy(pending_task->task_backtrace.begin(),
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h index 26a2f18b..433642f5 100644 --- a/base/mac/foundation_util.h +++ b/base/mac/foundation_util.h
@@ -53,9 +53,11 @@ #endif #if defined(OS_IOS) +typedef struct CF_BRIDGED_TYPE(id) __SecCertificate* SecCertificateRef; typedef struct CF_BRIDGED_TYPE(id) __SecKey* SecKeyRef; typedef struct CF_BRIDGED_TYPE(id) __SecPolicy* SecPolicyRef; #else +typedef struct OpaqueSecCertificateRef* SecCertificateRef; typedef struct OpaqueSecKeyRef* SecKeyRef; typedef struct OpaqueSecPolicyRef* SecPolicyRef; #endif @@ -146,6 +148,7 @@ TYPE_NAME_FOR_CF_TYPE_DECL(CTFont); TYPE_NAME_FOR_CF_TYPE_DECL(CTRun); +TYPE_NAME_FOR_CF_TYPE_DECL(SecCertificate); TYPE_NAME_FOR_CF_TYPE_DECL(SecKey); TYPE_NAME_FOR_CF_TYPE_DECL(SecPolicy); @@ -308,6 +311,7 @@ CF_CAST_DECL(CTFontDescriptor); CF_CAST_DECL(CTRun); +CF_CAST_DECL(SecCertificate); CF_CAST_DECL(SecKey); CF_CAST_DECL(SecPolicy);
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm index 38954c895..5046eed 100644 --- a/base/mac/foundation_util.mm +++ b/base/mac/foundation_util.mm
@@ -215,6 +215,7 @@ TYPE_NAME_FOR_CF_TYPE_DEFN(CTRun); #if !defined(OS_IOS) +TYPE_NAME_FOR_CF_TYPE_DEFN(SecCertificate); TYPE_NAME_FOR_CF_TYPE_DEFN(SecKey); TYPE_NAME_FOR_CF_TYPE_DEFN(SecPolicy); #endif @@ -414,6 +415,7 @@ #if !defined(OS_IOS) CF_CAST_DEFN(SecACL); +CF_CAST_DEFN(SecCertificate); CF_CAST_DEFN(SecKey); CF_CAST_DEFN(SecPolicy); CF_CAST_DEFN(SecTrustedApplication);
diff --git a/base/mac/launchd.cc b/base/mac/launchd.cc index 0337d2e6..ded1306829 100644 --- a/base/mac/launchd.cc +++ b/base/mac/launchd.cc
@@ -7,6 +7,11 @@ #include "base/logging.h" #include "base/mac/scoped_launch_data.h" +// This file is written in terms of launch_data_t, which is deprecated but has +// no replacement. Ignore the deprecation warnings for now. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + namespace base { namespace mac { @@ -73,3 +78,5 @@ } // namespace mac } // namespace base + +#pragma clang diagnostic pop
diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm index 4c6a0d1..e4177d3 100644 --- a/base/mac/mac_util.mm +++ b/base/mac/mac_util.mm
@@ -98,13 +98,16 @@ for(NSUInteger i = 0; i < [login_items_array count]; ++i) { LSSharedFileListItemRef item = reinterpret_cast<LSSharedFileListItemRef>(login_items_array[i]); - CFURLRef item_url_ref = NULL; + base::ScopedCFTypeRef<CFErrorRef> error; + CFURLRef item_url_ref = + LSSharedFileListItemCopyResolvedURL(item, 0, error.InitializeInto()); - // It seems that LSSharedFileListItemResolve() can return NULL in - // item_url_ref even if the function itself returns noErr. See - // https://crbug.com/760989 - if (LSSharedFileListItemResolve(item, 0, &item_url_ref, NULL) == noErr && - item_url_ref) { + // This function previously used LSSharedFileListItemResolve(), which could + // return a NULL URL even when returning no error. This caused + // <https://crbug.com/760989>. It's not clear one way or the other whether + // LSSharedFileListItemCopyResolvedURL() shares this behavior, so this check + // remains in place. + if (!error && item_url_ref) { ScopedCFTypeRef<CFURLRef> item_url(item_url_ref); if (CFEqual(item_url, url)) { CFRetain(item);
diff --git a/base/mac/scoped_launch_data.h b/base/mac/scoped_launch_data.h index f4db3306..e7ef0a8 100644 --- a/base/mac/scoped_launch_data.h +++ b/base/mac/scoped_launch_data.h
@@ -9,6 +9,11 @@ #include "base/scoped_generic.h" +// This file uses launch_data_t and related APIs, which are deprecated with no +// replacement. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + namespace base { namespace mac { @@ -28,4 +33,6 @@ } // namespace mac } // namespace base +#pragma clang diagnostic pop // -Wdeprecated-declarations + #endif // BASE_MAC_SCOPED_LAUNCH_DATA_H_
diff --git a/base/optional.h b/base/optional.h index f6b1547..84b302e 100644 --- a/base/optional.h +++ b/base/optional.h
@@ -15,20 +15,12 @@ namespace base { // Specification: -// http://en.cppreference.com/w/cpp/utility/optional/in_place_t -struct in_place_t {}; - -// Specification: // http://en.cppreference.com/w/cpp/utility/optional/nullopt_t struct nullopt_t { constexpr explicit nullopt_t(int) {} }; // Specification: -// http://en.cppreference.com/w/cpp/utility/optional/in_place -constexpr in_place_t in_place = {}; - -// Specification: // http://en.cppreference.com/w/cpp/utility/optional/nullopt constexpr nullopt_t nullopt(0);
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h index a8afb18..3bba9aa 100644 --- a/base/process/process_metrics.h +++ b/base/process/process_metrics.h
@@ -189,7 +189,7 @@ // process since process start. uint64_t GetCumulativeDiskUsageInBytes(); -#if defined(OS_LINUX) || defined(OS_AIX) || defined(OS_ANDROID) +#if defined(OS_POSIX) // Returns the number of file descriptors currently open by the process, or // -1 on error. int GetOpenFdCount() const; @@ -197,7 +197,7 @@ // Returns the soft limit of file descriptors that can be opened by the // process, or -1 on error. int GetOpenFdSoftLimit() const; -#endif // defined(OS_LINUX) || defined(OS_AIX) || defined(OS_ANDROID) +#endif // defined(OS_POSIX) #if defined(OS_LINUX) || defined(OS_ANDROID) // Bytes of swap as reported by /proc/[pid]/status.
diff --git a/base/process/process_metrics_mac.cc b/base/process/process_metrics_mac.cc index ef7f8ae..cbb5e93 100644 --- a/base/process/process_metrics_mac.cc +++ b/base/process/process_metrics_mac.cc
@@ -4,6 +4,7 @@ #include "base/process/process_metrics.h" +#include <libproc.h> #include <mach/mach.h> #include <mach/mach_vm.h> #include <mach/shared_region.h> @@ -193,6 +194,34 @@ return CalculateIdleWakeupsPerSecond(power_info_data.task_interrupt_wakeups); } +int ProcessMetrics::GetOpenFdCount() const { + // In order to get a true count of the open number of FDs, PROC_PIDLISTFDS + // is used. This is done twice: first to get the appropriate size of a + // buffer, and then secondly to fill the buffer with the actual FD info. + // + // The buffer size returned in the first call is an estimate, based on the + // number of allocated fileproc structures in the kernel. This number can be + // greater than the actual number of open files, since the structures are + // allocated in slabs. The value returned in proc_bsdinfo::pbi_nfiles is + // also the number of allocated fileprocs, not the number in use. + // + // However, the buffer size returned in the second call is an accurate count + // of the open number of descriptors. The contents of the buffer are unused. + int rv = proc_pidinfo(process_, PROC_PIDLISTFDS, 0, nullptr, 0); + if (rv < 0) + return -1; + + std::unique_ptr<char[]> buffer(new char[rv]); + rv = proc_pidinfo(process_, PROC_PIDLISTFDS, 0, buffer.get(), rv); + if (rv < 0) + return -1; + return rv / PROC_PIDLISTFD_SIZE; +} + +int ProcessMetrics::GetOpenFdSoftLimit() const { + return GetMaxFds(); +} + bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { return false; }
diff --git a/base/process/process_metrics_unittest.cc b/base/process/process_metrics_unittest.cc index eec66b887..791fa23 100644 --- a/base/process/process_metrics_unittest.cc +++ b/base/process/process_metrics_unittest.cc
@@ -19,6 +19,7 @@ #include "base/macros.h" #include "base/memory/shared_memory.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "base/system/sys_info.h" #include "base/test/multiprocess_test.h" #include "base/threading/thread.h" @@ -519,7 +520,7 @@ } #endif // defined(OS_LINUX) -#if defined(OS_LINUX) +#if defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS)) namespace { // Keep these in sync so the GetChildOpenFdCount test can refer to correct test @@ -529,8 +530,15 @@ // Command line flag name and file name used for synchronization. const char kTempDirFlag[] = "temp-dir"; + +const char kSignalReady[] = "ready"; +const char kSignalReadyAck[] = "ready-ack"; +const char kSignalOpened[] = "opened"; +const char kSignalOpenedAck[] = "opened-ack"; const char kSignalClosed[] = "closed"; +const int kChildNumFilesToOpen = 100; + bool SignalEvent(const FilePath& signal_dir, const char* signal_file) { File file(signal_dir.AppendASCII(signal_file), File::FLAG_CREATE | File::FLAG_WRITE); @@ -556,9 +564,20 @@ const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag); CHECK(DirectoryExists(temp_path)); - // Try to close all the file descriptors, so the open count goes to 0. - for (size_t i = 0; i < 1000; ++i) - close(i); + CHECK(SignalEvent(temp_path, kSignalReady)); + WaitForEvent(temp_path, kSignalReadyAck); + + std::vector<File> files; + for (int i = 0; i < kChildNumFilesToOpen; ++i) { + files.emplace_back(temp_path.AppendASCII(StringPrintf("file.%d", i)), + File::FLAG_CREATE | File::FLAG_WRITE); + } + + CHECK(SignalEvent(temp_path, kSignalOpened)); + WaitForEvent(temp_path, kSignalOpenedAck); + + files.clear(); + CHECK(SignalEvent(temp_path, kSignalClosed)); // Wait to be terminated. @@ -578,30 +597,56 @@ Process child = SpawnMultiProcessTestChild( ChildMainString, child_command_line, LaunchOptions()); ASSERT_TRUE(child.IsValid()); + + WaitForEvent(temp_path, kSignalReady); + + std::unique_ptr<ProcessMetrics> metrics = +#if defined(OS_MACOSX) + ProcessMetrics::CreateProcessMetrics(child.Handle(), nullptr); +#else + ProcessMetrics::CreateProcessMetrics(child.Handle()); +#endif // defined(OS_MACOSX) + + const int fd_count = metrics->GetOpenFdCount(); + EXPECT_GE(fd_count, 0); + + ASSERT_TRUE(SignalEvent(temp_path, kSignalReadyAck)); + WaitForEvent(temp_path, kSignalOpened); + + EXPECT_EQ(fd_count + kChildNumFilesToOpen, metrics->GetOpenFdCount()); + ASSERT_TRUE(SignalEvent(temp_path, kSignalOpenedAck)); + WaitForEvent(temp_path, kSignalClosed); - std::unique_ptr<ProcessMetrics> metrics( - ProcessMetrics::CreateProcessMetrics(child.Handle())); - EXPECT_EQ(0, metrics->GetOpenFdCount()); + EXPECT_EQ(fd_count, metrics->GetOpenFdCount()); + ASSERT_TRUE(child.Terminate(0, true)); } -#endif // defined(OS_LINUX) - -#if defined(OS_ANDROID) || defined(OS_LINUX) TEST(ProcessMetricsTest, GetOpenFdCount) { - std::unique_ptr<base::ProcessMetrics> metrics( - base::ProcessMetrics::CreateProcessMetrics( - base::GetCurrentProcessHandle())); + base::ProcessHandle process = base::GetCurrentProcessHandle(); + std::unique_ptr<base::ProcessMetrics> metrics = +#if defined(OS_MACOSX) + ProcessMetrics::CreateProcessMetrics(process, nullptr); +#else + ProcessMetrics::CreateProcessMetrics(process); +#endif // defined(OS_MACOSX) + + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + int fd_count = metrics->GetOpenFdCount(); EXPECT_GT(fd_count, 0); - ScopedFILE file(fopen("/proc/self/statm", "r")); - EXPECT_TRUE(file); + File file(temp_dir.GetPath().AppendASCII("file"), + File::FLAG_CREATE | File::FLAG_WRITE); int new_fd_count = metrics->GetOpenFdCount(); EXPECT_GT(new_fd_count, 0); EXPECT_EQ(new_fd_count, fd_count + 1); } +#endif // defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS)) + +#if defined(OS_ANDROID) || defined(OS_LINUX) TEST(ProcessMetricsTestLinux, GetPageFaultCounts) { std::unique_ptr<base::ProcessMetrics> process_metrics( base::ProcessMetrics::CreateProcessMetrics(
diff --git a/base/template_util.h b/base/template_util.h index 8544aa2..6eff136 100644 --- a/base/template_util.h +++ b/base/template_util.h
@@ -145,6 +145,35 @@ using is_trivially_copy_constructible = std::is_trivially_copy_constructible<T>; #endif +// base::in_place_t is an implementation of std::in_place_t from +// C++17. A tag type used to request in-place construction in template vararg +// constructors. + +// Specification: +// https://en.cppreference.com/w/cpp/utility/in_place +struct in_place_t {}; +constexpr in_place_t in_place = {}; + +// base::in_place_type_t is an implementation of std::in_place_type_t from +// C++17. A tag type used for in-place construction when the type to construct +// needs to be specified, such as with base::unique_any, designed to be a +// drop-in replacement. + +// Specification: +// http://en.cppreference.com/w/cpp/utility/in_place +template <typename T> +struct in_place_type_t {}; + +template <typename T> +struct is_in_place_type_t { + static constexpr bool value = false; +}; + +template <typename... Ts> +struct is_in_place_type_t<in_place_type_t<Ts...>> { + static constexpr bool value = true; +}; + } // namespace base #undef CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h index 3e4c4e8..339e81f 100644 --- a/base/threading/platform_thread.h +++ b/base/threading/platform_thread.h
@@ -145,7 +145,10 @@ // Yield the current thread so another thread can be scheduled. static void YieldCurrentThread(); - // Sleeps for the specified duration. + // Sleeps for the specified duration. Note: The sleep duration may be in + // base::Time or base::TimeTicks, depending on platform. If you're looking to + // use this in unit tests testing delayed tasks, this will be unreliable - + // instead, use base::test::ScopedTaskEnvironment with MOCK_TIME mode. static void Sleep(base::TimeDelta duration); // Sets the thread name visible to debuggers/tools. This will try to
diff --git a/base/threading/thread_restrictions.cc b/base/threading/thread_restrictions.cc index 57d84f3..4541b22 100644 --- a/base/threading/thread_restrictions.cc +++ b/base/threading/thread_restrictions.cc
@@ -188,13 +188,6 @@ return !previous_disallowed; } -ThreadRestrictions::ScopedAllowWait::ScopedAllowWait() - : was_allowed_(SetWaitAllowed(true)) {} - -ThreadRestrictions::ScopedAllowWait::~ScopedAllowWait() { - SetWaitAllowed(was_allowed_); -} - } // namespace base #endif // DCHECK_IS_ON()
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h index 5ede3b9e1..10b2456 100644 --- a/base/threading/thread_restrictions.h +++ b/base/threading/thread_restrictions.h
@@ -260,7 +260,6 @@ class SimpleThread; class StackSamplingProfiler; class Thread; -class ThreadTestHelper; #if DCHECK_IS_ON() #define INLINE_IF_DCHECK_IS_OFF BASE_EXPORT @@ -456,8 +455,8 @@ MultiThreadedProxyResolverScopedAllowJoinOnIO; // http://crbug.com/69710 friend class net::NetworkChangeNotifierMac; // http://crbug.com/125097 friend class net:: - ScopedAllowThreadJoinForProxyResolverV8Tracing; // http://crbug.com/69710 - friend class printing::PrinterQuery; // http://crbug.com/66082 + ScopedAllowThreadJoinForProxyResolverV8Tracing; // http://crbug.com/69710 + friend class printing::PrinterQuery; // http://crbug.com/66082 // Not used in production yet, https://crbug.com/844078. friend class service_manager::ServiceProcessLauncher; friend class ui::WindowResizeHelperMac; // http://crbug.com/902829 @@ -557,52 +556,24 @@ #endif private: - // TODO(etiennep): Remove friendship for ScopedAllowWait. // DO NOT ADD ANY OTHER FRIEND STATEMENTS. // BEGIN ALLOWED USAGE. - friend class android_webview::AwFormDatabaseService; - friend class android_webview::CookieManager; - friend class base::StackSamplingProfiler; friend class content::BrowserMainLoop; friend class content::BrowserShutdownProfileDumper; friend class content::BrowserTestBase; - friend class content::NestedMessagePumpAndroid; friend class content::ScopedAllowWaitForDebugURL; friend class ::HistogramSynchronizer; friend class internal::TaskTracker; - friend class cc::CompletionEvent; - friend class cc::SingleThreadTaskGraphRunner; - friend class content::CategorizedWorkerPool; - friend class remoting::AutoThread; - friend class ui::WindowResizeHelperMac; friend class web::WebMainLoop; friend class MessagePumpDefault; - friend class SimpleThread; - friend class Thread; - friend class ThreadTestHelper; friend class PlatformThread; - friend class android::JavaHandlerThread; - friend class mojo::SyncCallRestrictions; friend class ui::CommandBufferClientImpl; friend class ui::CommandBufferLocal; friend class ui::GpuState; // END ALLOWED USAGE. // BEGIN USAGE THAT NEEDS TO BE FIXED. - friend class ::chromeos::BlockingMethodCaller; // http://crbug.com/125360 - friend class ::chromeos::system::StatisticsProviderImpl; // http://crbug.com/125385 friend class chrome_browser_net::Predictor; // http://crbug.com/78451 - friend class - content::BrowserGpuChannelHostFactory; // http://crbug.com/125248 - friend class content::TextInputClientMac; // http://crbug.com/121917 - friend class dbus::Bus; // http://crbug.com/125222 - friend class disk_cache::BackendImpl; // http://crbug.com/74623 - friend class disk_cache::InFlightIO; // http://crbug.com/74623 - friend class gpu::GpuChannelHost; // http://crbug.com/125264 - friend class net::internal::AddressTrackerLinux; // http://crbug.com/125097 - friend class net::NetworkChangeNotifierMac; // http://crbug.com/125097 - friend class ::BrowserProcessImpl; // http://crbug.com/125207 - friend class ::NativeBackendKWallet; // http://crbug.com/125331 #if !defined(OFFICIAL_BUILD) friend class content::SoftwareOutputDeviceMus; // Interim non-production code #endif @@ -615,24 +586,6 @@ static bool SetWaitAllowed(bool allowed) { return true; } #endif - // Constructing a ScopedAllowWait temporarily allows waiting on the current - // thread. Doing this is almost always incorrect, which is why we limit who - // can use this through friend. - // - // DEPRECATED. Use ScopedAllowBaseSyncPrimitives. - class BASE_EXPORT ScopedAllowWait { - public: - ScopedAllowWait() EMPTY_BODY_IF_DCHECK_IS_OFF; - ~ScopedAllowWait() EMPTY_BODY_IF_DCHECK_IS_OFF; - - private: -#if DCHECK_IS_ON() - const bool was_allowed_; -#endif - - DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait); - }; - DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions); };
diff --git a/build/android/AndroidManifest.xml b/build/android/AndroidManifest.xml index 5439a5a..fe21b80b 100644 --- a/build/android/AndroidManifest.xml +++ b/build/android/AndroidManifest.xml
@@ -15,6 +15,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.dummy"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="24" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24" /> </manifest>
diff --git a/build/android/gradle/android.jinja b/build/android/gradle/android.jinja index e0e3c11..4a7da29 100644 --- a/build/android/gradle/android.jinja +++ b/build/android/gradle/android.jinja
@@ -51,7 +51,7 @@ defaultConfig { vectorDrawables.useSupportLibrary = true - minSdkVersion 16 + minSdkVersion 19 targetSdkVersion {{ target_sdk_version }} }
diff --git a/build/android/gyp/merge_manifest.py b/build/android/gyp/merge_manifest.py index f07ce7a..23432aa7 100755 --- a/build/android/gyp/merge_manifest.py +++ b/build/android/gyp/merge_manifest.py
@@ -14,6 +14,7 @@ import xml.dom.minidom as minidom from util import build_utils +from util import diff_utils # Tools library directory - relative to Android SDK root SDK_TOOLS_LIB_DIR = os.path.join('tools', 'lib') @@ -72,6 +73,12 @@ parser.add_argument('--root-manifest', help='Root manifest which to merge into', required=True) + parser.add_argument( + '--expected-manifest', help='Expected contents for the merged manifest.') + parser.add_argument( + '--verify-expected-manifest', + action='store_true', + help='Fail if expected contents do not match merged manifest contents.') parser.add_argument('--output', help='Output manifest path', required=True) parser.add_argument('--extras', help='GN list of additional manifest to merge') @@ -101,6 +108,24 @@ # The merger doesn't set a nonzero exit code for failures. fail_func=lambda returncode, stderr: returncode != 0 or build_utils.IsTimeStale(f.name, [root_manifest] + extras)) + + if args.expected_manifest: + diff = diff_utils.DiffFileContents(args.expected_manifest, args.output) + if diff: + print """ +{} + +Detected AndroidManifest change. Please update by running: + +cp {} {} + +See https://chromium.googlesource.com/chromium/src/+/HEAD/chrome/android/java/README.md +for more info. +""".format(diff, os.path.abspath(args.output), + os.path.abspath(args.expected_manifest)) + if args.verify_expected_manifest: + sys.exit(1) + if args.depfile: inputs = extras + classpath.split(':') build_utils.WriteDepfile(args.depfile, args.output, inputs=inputs,
diff --git a/build/android/gyp/merge_manifest.pydeps b/build/android/gyp/merge_manifest.pydeps index 37901962c..797cd5fb 100644 --- a/build/android/gyp/merge_manifest.pydeps +++ b/build/android/gyp/merge_manifest.pydeps
@@ -4,4 +4,5 @@ merge_manifest.py util/__init__.py util/build_utils.py +util/diff_utils.py util/md5_check.py
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py index dbfcbcb..a42dadee 100755 --- a/build/android/gyp/proguard.py +++ b/build/android/gyp/proguard.py
@@ -112,7 +112,7 @@ cp {} {} -See https://chromium.googlesource.com/chromium/src/+/HEAD/chrome/android/java/README.md#fixing-build-failures +See https://chromium.googlesource.com/chromium/src/+/HEAD/chrome/android/java/README.md for more info. """.format(diff, os.path.abspath(actual_path), os.path.abspath(expected_path)) if fail_on_exit:
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml index 569c92b..d7004a1d 100644 --- a/build/android/lint/suppressions.xml +++ b/build/android/lint/suppressions.xml
@@ -349,6 +349,9 @@ <ignore regexp="The resource `R.string.search_widget_title.*` appears to be unused"/> <!-- 1 resource used by android tv to generate resources.zip file --> <ignore regexp="chromecast/internal/shell/browser/android/java/res/drawable-hdpi/ic_settings_cast.png"/> + <!-- TODO(crbug.com/909915): Remove this after full Lite mode launch. --> + <!-- 12 resources used by Data Saver during rebranding to Lite mode --> + <ignore regexp="The resource `R.string..*lite_mode` appears to be unused"/> <!-- Endnote: Please specify number of suppressions when adding more --> </issue> <issue id="UseCompoundDrawables">
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index b81e0e8..ee4498a 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -1103,7 +1103,7 @@ _proguard_enabled = defined(invoker.proguard_enabled) && invoker.proguard_enabled _proguarding_with_r8 = - _proguard_enabled && !defined(invoker.proguard_jar_path) + _proguard_enabled && (!defined(invoker.proguard_jar_path) || use_r8) _enable_multidex = defined(invoker.enable_multidex) && invoker.enable_multidex @@ -1179,19 +1179,25 @@ } if (_enable_multidex && _proguarding_with_r8) { - if (defined(invoker.extra_main_dex_proguard_config)) { + if (!defined(invoker.min_sdk_version) || + invoker.min_sdk_version < 21) { + if (defined(invoker.extra_main_dex_proguard_config)) { + args += [ + "--main-dex-rules-path", + rebase_path(invoker.extra_main_dex_proguard_config, + root_build_dir), + ] + inputs += [ invoker.extra_main_dex_proguard_config ] + } args += [ "--main-dex-rules-path", - rebase_path(invoker.extra_main_dex_proguard_config, - root_build_dir), + rebase_path(_main_dex_rules, root_build_dir), ] - inputs += [ invoker.extra_main_dex_proguard_config ] + inputs += [ _main_dex_rules ] + } else { + not_needed(invoker, [ "extra_main_dex_proguard_config" ]) + not_needed([ "_main_dex_rules" ]) } - args += [ - "--main-dex-rules-path", - rebase_path(_main_dex_rules, root_build_dir), - ] - inputs += [ _main_dex_rules ] } output_path = _proguard_output_path @@ -1742,6 +1748,17 @@ "--extras", "@FileArg($_rebased_build_config:extra_android_manifests)", ] + + if (defined(invoker.expected_manifest)) { + inputs += [ invoker.expected_manifest ] + args += [ + "--expected-manifest", + rebase_path(invoker.expected_manifest, root_build_dir), + ] + if (check_android_configuration) { + args += [ "--verify-expected-manifest" ] + } + } } }
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index caf33d39..0f2324a 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -1951,8 +1951,8 @@ # resources.arsc file in the apk or module. # resources_config_path: Path to the aapt2 optimize config file that tags # resources with acceptable/non-acceptable optimizations. - # proguard_expectations_file: Path to generated file containing the merged - # proguard flags from all input config files. + # verify_android_configuration: Enables verification of expected merged + # manifest and proguard flags based on a golden file. template("android_apk_or_module") { forward_variables_from(invoker, [ "testonly" ]) @@ -2165,6 +2165,13 @@ _incremental_install_json_path = "$root_out_dir/gen.runtime/$_target_dir_name/$target_name.incremental.json" } + _verify_android_configuration = + defined(invoker.verify_android_configuration) && + invoker.verify_android_configuration && !is_java_debug + if (_verify_android_configuration) { + _target_src_dir = get_label_info(":$target_name", "dir") + } + _android_manifest = "$target_gen_dir/${_template_name}_manifest/AndroidManifest.xml" _merge_manifest_target = "${_template_name}__merge_manifests" @@ -2172,6 +2179,10 @@ input_manifest = _android_root_manifest output_manifest = _android_manifest build_config = _build_config + if (_verify_android_configuration) { + expected_manifest = + "$_target_src_dir/java/$_template_name.AndroidManifest.expected" + } deps = _android_root_manifest_deps + [ ":$_build_config_target" ] } @@ -2568,7 +2579,6 @@ [ "min_sdk_version", "dexlayout_profile", - "proguard_expectations_file", ]) proguard_enabled = _proguard_enabled build_config = _build_config @@ -2581,6 +2591,11 @@ deps += _deps + [ ":$_compile_resources_target" ] proguard_configs = [ _jar_path ] proguard_mapping_path = _proguard_mapping_path + if (!defined(invoker.proguard_jar_path) && + _verify_android_configuration) { + proguard_expectations_file = + "$_target_src_dir/java/$_template_name.proguard_flags.expected" + } } else { input_jars = [ _lib_dex_path ] input_dex_classpath = @@ -2967,7 +2982,7 @@ "product_version_resources_dep", "proguard_configs", "proguard_enabled", - "proguard_expectations_file", + "verify_android_configuration", "proguard_jar_path", "resource_blacklist_regex", "resource_blacklist_exceptions",
diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni index 544c524..1a6d170a 100644 --- a/build/config/mac/mac_sdk.gni +++ b/build/config/mac/mac_sdk.gni
@@ -14,7 +14,7 @@ # additional code changes are required to be compliant with the availability # rules. # Must be of the form x.x.x for Info.plist files. - mac_deployment_target = "10.9.0" + mac_deployment_target = "10.10.0" # The value of the LSMinimmumSystemVersion in Info.plist files. This partially # controls the minimum supported version of macOS for Chromium by
diff --git a/build_overrides/angle.gni b/build_overrides/angle.gni new file mode 100644 index 0000000..56b6c8e --- /dev/null +++ b/build_overrides/angle.gni
@@ -0,0 +1,10 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Overrides for ANGLE's dependencies +angle_glslang_dir = "//third_party/glslang/src" +angle_googletest_dir = "//third_party/googletest/src" +angle_jsoncpp_dir = "//third_party/jsoncpp" +angle_libpng_dir = "//third_party/libpng" +angle_spirv_tools_dir = "//third_party/SPIRV-Tools/src"
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index d46a406..7d07aa39 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc
@@ -605,6 +605,15 @@ NoteLayerPropertyChanged(); } +bool LayerImpl::ShouldHitTest() const { + bool should_hit_test = draws_content_; + if (GetEffectTree().Node(effect_tree_index())) + should_hit_test &= + !GetEffectTree().Node(effect_tree_index())->subtree_hidden; + should_hit_test |= hit_testable_without_draws_content_; + return should_hit_test; +} + void LayerImpl::SetBackgroundColor(SkColor background_color) { if (background_color_ == background_color) return;
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index f4b63cce..837b7e0 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h
@@ -167,9 +167,7 @@ // True if either the layer draws content or has been marked as hit testable // without draws_content. - bool should_hit_test() const { - return draws_content_ || hit_testable_without_draws_content_; - } + bool ShouldHitTest() const; LayerImplTestProperties* test_properties() { if (!test_properties_)
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc index aff30af..044c5b7 100644 --- a/cc/layers/layer_unittest.cc +++ b/cc/layers/layer_unittest.cc
@@ -1346,7 +1346,7 @@ root_layer->PushPropertiesTo(impl_layer.get()); EXPECT_TRUE(impl_layer->DrawsContent()); EXPECT_FALSE(impl_layer->hit_testable_without_draws_content()); - EXPECT_TRUE(impl_layer->should_hit_test()); + EXPECT_TRUE(impl_layer->ShouldHitTest()); // A layer that does not draw content and does not hit test without drawing // content should not be hit testable. @@ -1354,7 +1354,7 @@ root_layer->PushPropertiesTo(impl_layer.get()); EXPECT_FALSE(impl_layer->DrawsContent()); EXPECT_FALSE(impl_layer->hit_testable_without_draws_content()); - EXPECT_FALSE(impl_layer->should_hit_test()); + EXPECT_FALSE(impl_layer->ShouldHitTest()); // |SetHitTestableWithoutDrawsContent| should cause a layer to become hit // testable even though it does not draw content. @@ -1362,7 +1362,7 @@ root_layer->PushPropertiesTo(impl_layer.get()); EXPECT_FALSE(impl_layer->DrawsContent()); EXPECT_TRUE(impl_layer->hit_testable_without_draws_content()); - EXPECT_TRUE(impl_layer->should_hit_test()); + EXPECT_TRUE(impl_layer->ShouldHitTest()); } void ReceiveCopyOutputResult(int* result_count,
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h index 354734cc..7855f97 100644 --- a/cc/test/fake_layer_tree_host_impl_client.h +++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -43,6 +43,8 @@ uint32_t frame_token, std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback) override {} + void DidGenerateLocalSurfaceIdAllocationOnImplThread( + const viz::LocalSurfaceIdAllocation& allocation) override {} void reset_did_request_impl_side_invalidation() { did_request_impl_side_invalidation_ = false;
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index 76ea211..10539e20 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc
@@ -494,6 +494,8 @@ void DidPresentCompositorFrame( uint32_t frame_token, const gfx::PresentationFeedback& feedback) override {} + void DidGenerateLocalSurfaceIdAllocation( + const viz::LocalSurfaceIdAllocation& allocation) override {} private: explicit LayerTreeHostClientForTesting(TestHooks* test_hooks)
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc index 3450fe8..154d15c 100644 --- a/cc/test/pixel_test.cc +++ b/cc/test/pixel_test.cc
@@ -271,7 +271,8 @@ ->GetFormat(), gpu_service_->gpu_feature_info(), gpu_service_->gpu_channel_manager()->gpu_preferences(), - gpu_service_->shared_image_manager()); + gpu_service_->shared_image_manager(), + gpu_service_->gpu_channel_manager()->program_cache()); event->Signal(); }
diff --git a/cc/test/stub_layer_tree_host_client.h b/cc/test/stub_layer_tree_host_client.h index e150e251..021d747a 100644 --- a/cc/test/stub_layer_tree_host_client.h +++ b/cc/test/stub_layer_tree_host_client.h
@@ -41,6 +41,8 @@ void DidPresentCompositorFrame( uint32_t frame_token, const gfx::PresentationFeedback& feedback) override {} + void DidGenerateLocalSurfaceIdAllocation( + const viz::LocalSurfaceIdAllocation& allocation) override {} }; } // namespace cc
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc index 2fb5a10..5cb51724f 100644 --- a/cc/tiles/gpu_image_decode_cache_unittest.cc +++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -2548,12 +2548,6 @@ } TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { -#if defined(OS_WIN) - // TODO(ericrk): Mips are temporarily disabled to investigate a memory - // regression on Windows. https://crbug.com/867468 - return; -#endif // defined(OS_WIN) - auto cache = CreateCache(); bool is_decomposable = true; auto filter_quality = kMedium_SkFilterQuality;
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index fd01da6..7980e4b 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -688,6 +688,11 @@ client_->DidPresentCompositorFrame(frame_token, feedback); } +void LayerTreeHost::DidGenerateLocalSurfaceIdAllocation( + const viz::LocalSurfaceIdAllocation& allocation) { + client_->DidGenerateLocalSurfaceIdAllocation(allocation); +} + void LayerTreeHost::DidCompletePageScaleAnimation() { did_complete_scale_animation_ = true; }
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h index fc28203b..3dad3b5 100644 --- a/cc/trees/layer_tree_host.h +++ b/cc/trees/layer_tree_host.h
@@ -88,6 +88,12 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { public: struct CC_EXPORT InitParams { + InitParams(); + ~InitParams(); + + InitParams(InitParams&&); + InitParams& operator=(InitParams&&); + LayerTreeHostClient* client = nullptr; TaskGraphRunner* task_graph_runner = nullptr; LayerTreeSettings const* settings = nullptr; @@ -100,12 +106,6 @@ scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner; std::unique_ptr<UkmRecorderFactory> ukm_recorder_factory; - - InitParams(); - ~InitParams(); - - InitParams(InitParams&&); - InitParams& operator=(InitParams&&); }; // Constructs a LayerTreeHost with a compositor thread where scrolling and @@ -589,6 +589,8 @@ uint32_t frame_token, std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback); + void DidGenerateLocalSurfaceIdAllocation( + const viz::LocalSurfaceIdAllocation& allocation); // Called when the compositor completed page scale animation. void DidCompletePageScaleAnimation(); void ApplyScrollAndScale(ScrollAndScaleSet* info);
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h index 03b5ade5..a282dae8 100644 --- a/cc/trees/layer_tree_host_client.h +++ b/cc/trees/layer_tree_host_client.h
@@ -18,6 +18,7 @@ } namespace viz { +class LocalSurfaceIdAllocation; struct BeginFrameArgs; } @@ -131,6 +132,8 @@ // Record UMA and UKM metrics that require the time from the start of // BeginMainFrame to the Commit, or early out. virtual void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) = 0; + virtual void DidGenerateLocalSurfaceIdAllocation( + const viz::LocalSurfaceIdAllocation& allocation) = 0; protected: virtual ~LayerTreeHostClient() {}
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index bc110bf..6a44080 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -2021,7 +2021,7 @@ if (child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() .IsValid()) { if (allocate_new_local_surface_id) - child_local_surface_id_allocator_.GenerateId(); + AllocateLocalSurfaceId(); metadata.local_surface_id_allocation = child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation(); } @@ -2615,7 +2615,7 @@ Region overlapping_region; for (const auto* layer : base::Reversed(*active_tree())) { - if (!layer->should_hit_test()) + if (!layer->ShouldHitTest()) continue; if (layer->is_surface_layer()) { @@ -2896,7 +2896,7 @@ child_local_surface_id_allocator_.UpdateFromParent( active_tree()->local_surface_id_allocation_from_parent()); if (active_tree()->TakeNewLocalSurfaceIdRequest()) - child_local_surface_id_allocator_.GenerateId(); + AllocateLocalSurfaceId(); } // Dump property trees and layers if run with: @@ -3360,7 +3360,7 @@ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation = child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation(); if (local_surface_id_allocation.IsValid()) - child_local_surface_id_allocator_.GenerateId(); + AllocateLocalSurfaceId(); } else { layer_tree_frame_sink_->ForceAllocateNewId(); } @@ -5688,4 +5688,10 @@ ukm_manager_->SetSourceURL(url); } +void LayerTreeHostImpl::AllocateLocalSurfaceId() { + child_local_surface_id_allocator_.GenerateId(); + client_->DidGenerateLocalSurfaceIdAllocationOnImplThread( + child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()); +} + } // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 9297f60..04b750687 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -154,6 +154,9 @@ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback) = 0; + virtual void DidGenerateLocalSurfaceIdAllocationOnImplThread( + const viz::LocalSurfaceIdAllocation& allocation) = 0; + protected: virtual ~LayerTreeHostImplClient() {} }; @@ -877,6 +880,8 @@ void OnMemoryPressure( base::MemoryPressureListener::MemoryPressureLevel level); + void AllocateLocalSurfaceId(); + const LayerTreeSettings settings_; const bool is_synchronous_single_threaded_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 26b7843..29e27769 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -224,6 +224,8 @@ uint32_t frame_token, std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback) override {} + void DidGenerateLocalSurfaceIdAllocationOnImplThread( + const viz::LocalSurfaceIdAllocation& allocation) override {} void set_reduce_memory_result(bool reduce_memory_result) { reduce_memory_result_ = reduce_memory_result;
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 1a5d3a8..034dc7e295 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -2154,7 +2154,7 @@ struct HitTestVisibleScrollableOrTouchableFunctor { bool operator()(LayerImpl* layer) const { - return layer->scrollable() || layer->should_hit_test() || + return layer->scrollable() || layer->ShouldHitTest() || !layer->touch_action_region().region().IsEmpty(); } };
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc index 2b78d1a2..15c783c 100644 --- a/cc/trees/property_tree.cc +++ b/cc/trees/property_tree.cc
@@ -776,6 +776,12 @@ node->screen_space_opacity *= parent_node->screen_space_opacity; } +void EffectTree::UpdateSubtreeHidden(EffectNode* node, + EffectNode* parent_node) { + if (parent_node) + node->subtree_hidden |= parent_node->subtree_hidden; +} + void EffectTree::UpdateIsDrawn(EffectNode* node, EffectNode* parent_node) { // Nodes that have screen space opacity 0 are hidden. So they are not drawn. // Exceptions: @@ -900,6 +906,7 @@ EffectNode* parent_node = parent(node); UpdateOpacities(node, parent_node); + UpdateSubtreeHidden(node, parent_node); UpdateIsDrawn(node, parent_node); UpdateEffectChanged(node, parent_node); UpdateBackfaceVisibility(node, parent_node);
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h index 27281e0..6b9ef88f 100644 --- a/cc/trees/property_tree.h +++ b/cc/trees/property_tree.h
@@ -374,6 +374,7 @@ private: void UpdateOpacities(EffectNode* node, EffectNode* parent_node); + void UpdateSubtreeHidden(EffectNode* node, EffectNode* parent_node); void UpdateIsDrawn(EffectNode* node, EffectNode* parent_node); void UpdateBackfaceVisibility(EffectNode* node, EffectNode* parent_node); void UpdateHasMaskingChild(EffectNode* node, EffectNode* parent_node);
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc index 6d5481c5..8e3a509 100644 --- a/cc/trees/proxy_impl.cc +++ b/cc/trees/proxy_impl.cc
@@ -507,6 +507,13 @@ std::move(callbacks), feedback)); } +void ProxyImpl::DidGenerateLocalSurfaceIdAllocationOnImplThread( + const viz::LocalSurfaceIdAllocation& allocation) { + MainThreadTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(&ProxyMain::DidGenerateLocalSurfaceIdAllocation, + proxy_main_weak_ptr_, allocation)); +} + bool ProxyImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) { DCHECK(IsImplThread()); return host_impl_->WillBeginImplFrame(args);
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h index 72d2afb8..5f1ff43 100644 --- a/cc/trees/proxy_impl.h +++ b/cc/trees/proxy_impl.h
@@ -108,6 +108,8 @@ uint32_t frame_token, std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback) override; + void DidGenerateLocalSurfaceIdAllocationOnImplThread( + const viz::LocalSurfaceIdAllocation& allocation) override; // SchedulerClient implementation bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override;
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc index ec2907a..85bf14a0 100644 --- a/cc/trees/proxy_main.cc +++ b/cc/trees/proxy_main.cc
@@ -348,6 +348,11 @@ feedback); } +void ProxyMain::DidGenerateLocalSurfaceIdAllocation( + const viz::LocalSurfaceIdAllocation& allocation) { + layer_tree_host_->DidGenerateLocalSurfaceIdAllocation(allocation); +} + bool ProxyMain::IsStarted() const { DCHECK(IsMainThread()); return started_;
diff --git a/cc/trees/proxy_main.h b/cc/trees/proxy_main.h index 6a701d90..7fbff9ef 100644 --- a/cc/trees/proxy_main.h +++ b/cc/trees/proxy_main.h
@@ -11,6 +11,10 @@ #include "cc/trees/proxy.h" #include "cc/trees/proxy_common.h" +namespace viz { +class LocalSurfaceIdAllocation; +} + namespace cc { class MutatorEvents; @@ -57,6 +61,8 @@ uint32_t frame_token, std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback); + void DidGenerateLocalSurfaceIdAllocation( + const viz::LocalSurfaceIdAllocation& allocation); CommitPipelineStage max_requested_pipeline_stage() const { return max_requested_pipeline_stage_;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 92e1d84..b15148d 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc
@@ -499,6 +499,11 @@ feedback); } +void SingleThreadProxy::DidGenerateLocalSurfaceIdAllocationOnImplThread( + const viz::LocalSurfaceIdAllocation& allocation) { + layer_tree_host_->DidGenerateLocalSurfaceIdAllocation(allocation); +} + void SingleThreadProxy::RequestBeginMainFrameNotExpected(bool new_state) { if (scheduler_on_impl_thread_) { scheduler_on_impl_thread_->SetMainThreadWantsBeginMainFrameNotExpected(
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h index 7247fce1..565af3d 100644 --- a/cc/trees/single_thread_proxy.h +++ b/cc/trees/single_thread_proxy.h
@@ -128,6 +128,8 @@ uint32_t frame_token, std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback) override; + void DidGenerateLocalSurfaceIdAllocationOnImplThread( + const viz::LocalSurfaceIdAllocation& allocation) override; void RequestNewLayerTreeFrameSink();
diff --git a/chrome/VERSION b/chrome/VERSION index b76484a..5753a6a 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=73 MINOR=0 -BUILD=3682 +BUILD=3683 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index e182549..38a1736 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -67,7 +67,7 @@ output = chrome_public_android_manifest variables = chrome_public_jinja_variables variables += [ - "min_sdk_version=16", + "min_sdk_version=19", "target_sdk_version=$android_sdk_version", ] @@ -1448,7 +1448,7 @@ android_manifest = chrome_modern_public_android_manifest android_manifest_dep = ":chrome_modern_public_android_manifest" } else { - min_sdk_version = 16 + min_sdk_version = 19 android_manifest = chrome_public_android_manifest android_manifest_dep = ":chrome_public_android_manifest" } @@ -1545,7 +1545,7 @@ "apk_name", "is_base_module", "module_name", - "proguard_expectations_file", + "verify_android_configuration", "proguard_jar_path", "target_type", "use_trichrome_library", @@ -1587,11 +1587,10 @@ apk_name = "MonochromePublic" target_type = "android_apk" - # Having //clank present causes different flags because of how play services - # is wired up. - if (!is_java_debug && !enable_chrome_android_internal) { - proguard_expectations_file = - "//chrome/android/java/monochrome_public_apk.proguard_flags.expected" + # Having //clank present causes different flags because of how play + # services is wired up. + if (!enable_chrome_android_internal) { + verify_android_configuration = true } } @@ -1633,7 +1632,7 @@ variables = default_chrome_public_jinja_variables variables += [ "manifest_package=$test_manifest_package", - "min_sdk_version=16", + "min_sdk_version=19", "target_sdk_version=$android_sdk_version", ] } @@ -1644,7 +1643,7 @@ output = chrome_public_test_vr_apk_manifest variables = chrome_public_jinja_variables variables += [ - "min_sdk_version=16", + "min_sdk_version=19", "target_sdk_version=$android_sdk_version", ] }
diff --git a/chrome/android/OWNERS b/chrome/android/OWNERS index 044f3ad..a66cf43 100644 --- a/chrome/android/OWNERS +++ b/chrome/android/OWNERS
@@ -12,6 +12,7 @@ per-file BUILD.gn=bsheedy@chromium.org per-file *.proguard_flags.expected=* +per-file *.AndroidManifest.expected=* # Translation artifacts: per-file *.xtb=file://tools/translation/TRANSLATION_OWNERS
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedAppLifecycle.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedAppLifecycle.java index 075847c..e6d5be9c 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedAppLifecycle.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedAppLifecycle.java
@@ -175,12 +175,15 @@ private void onClearAll(boolean suppressRefreshes) { reportEvent(AppLifecycleEvent.CLEAR_ALL); - // It is important that #onClearAll() is called before notifying the scheduler, otherwise - // the clear all could wipe out the new results. These are both async operations that are - // kicked off here, but the Feed is responsible for tracking them and making sure they're - // correctly respected. - mAppLifecycleListener.onClearAll(); - mFeedScheduler.onArticlesCleared(suppressRefreshes); + // Clearing and triggering refreshes are both asynchronous operations. The Feed is able to + // better coordinate them if {@link AppLifecycleListener#onClearAllWithRefresh} is called. + // If the scheduler returns true from {@link FeedScheduler#onArticlesCleared}, this means + // that it did not trigger the refresh, but is allowing us to do so. + if (mFeedScheduler.onArticlesCleared(suppressRefreshes)) { + mAppLifecycleListener.onClearAllWithRefresh(); + } else { + mAppLifecycleListener.onClearAll(); + } } private void initialize() {
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java index 91d1bee..6c96bbd 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java
@@ -30,6 +30,7 @@ * To be called when articles are cleared. * @param suppressRefreshes whether the scheduler should temporarily avoid kicking off * refreshes. This is used, for example, when history data is deleted. + * @return If a refresh should be made by the caller. */ - void onArticlesCleared(boolean suppressRefreshes); + boolean onArticlesCleared(boolean suppressRefreshes); }
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java index e44840e5..783303a 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java
@@ -123,9 +123,9 @@ } @Override - public void onArticlesCleared(boolean suppressRefreshes) { + public boolean onArticlesCleared(boolean suppressRefreshes) { assert mNativeBridge != 0; - nativeOnArticlesCleared(mNativeBridge, suppressRefreshes); + return nativeOnArticlesCleared(mNativeBridge, suppressRefreshes); } @CalledByNative @@ -159,6 +159,6 @@ private native void nativeOnForegrounded(long nativeFeedSchedulerBridge); private native void nativeOnFixedTimer(long nativeFeedSchedulerBridge, Runnable onCompletion); private native void nativeOnSuggestionConsumed(long nativeFeedSchedulerBridge); - private native void nativeOnArticlesCleared( + private native boolean nativeOnArticlesCleared( long nativeFeedSchedulerBridge, boolean suppressRefreshes); }
diff --git a/chrome/android/java/README.md b/chrome/android/java/README.md index 4af18a2..51d6ca0 100644 --- a/chrome/android/java/README.md +++ b/chrome/android/java/README.md
@@ -1,6 +1,6 @@ -## //chrome/android/java/*proguard_flags.expected files +# //chrome/android/java/*.expected files -### Proguard flags +## Proguard flags [Proguard](https://www.guardsquare.com/en/products/proguard) is used in the build to obfuscate and minify Java code. @@ -23,7 +23,7 @@ contains all proguard configs used when building MonochromePublic.apk, and is generated by the `proguard()` build step. -### Why do we care about proguard flag discrepancies? +### Why do we care about Proguard flag discrepancies? Some configs are explicitly added ([ex](proguard.flags)) while others are pulled in implicitly by GN deps (ex. `aar_prebuilt()` deps). In the later case, these @@ -36,10 +36,30 @@ Having checked-in versions of the Proguard configs used allows us to identify and address these issues earlier. +## AndroidManifest.xml + +Each Android application has a manifest that contains information about the app +(ex. permissions required, services exposed, etc). + +### What are `*.AndroidManifest.expected` files? + +[monochrome_public_apk.AndroidManifest.expected](monochrome_public_apk.AndroidManifest.expected) +contains the contents of the final merged manifest used when building +MonochromePublic.apk. + +### Why do we care about AndroidManifest discrepancies? + +While most manifest changes are reviewed when the manifest template file +changes, manifest entries that are pulled in via. deps (through manifest +merging) can cause real bugs (permissions issues, security vulnerabilities). + +## Build failures caused by `*.expected` files + ### What is the build error telling me? -The build error is indicating that your CL has caused proguard rules to be -added/removed/changed and that the expected file needs to be updated. +The build error is indicating that your CL has caused a mismatch between the +expected file and the generated file and that either the issue requires +attention or the expected file needs updating. ### Fixing build failures @@ -56,7 +76,7 @@ ``` 3. Run the command suggested in the error message to copy the contents of the - generated proguard config file to the expected config file. + generated file to the expected file path 4. Add the updated `.expected` file to your CL @@ -67,7 +87,7 @@ On the [android-binary-size](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/android-binary-size) trybot we set `check_android_configuration=true` which causes any differences -between the expected and generated Proguard configs to fail the build. +between the expected and generated files to fail the build. Without this argument the error message is shown but doesn't fail the build.
diff --git a/chrome/android/java/monochrome_public_apk.AndroidManifest.expected b/chrome/android/java/monochrome_public_apk.AndroidManifest.expected new file mode 100644 index 0000000..c39719b --- /dev/null +++ b/chrome/android/java/monochrome_public_apk.AndroidManifest.expected
@@ -0,0 +1,2367 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2015 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. +--> +<!-- +Note: This is a jinja2 template, processed at build time into the final manifest. + +Blocks denoted with { % block some_name % }foo{ % endblock % } can be overridden +by a child template that "extends" this file. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="org.chromium.chrome" + tools:ignore="MissingVersion" > <!-- android:versionCode and android:versionName is set through gyp. See build/common.gypi --> + <uses-sdk + android:minSdkVersion="24" + android:targetSdkVersion="28" /> + + <uses-feature android:glEsVersion="0x00020000" /> + + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> + + <uses-permission-sdk-23 android:name="android.permission.ACCESS_WIFI_STATE" /> + + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + + <!-- + Enable runtime permissions as uses-permission in tip of tree builds + only for ease of development on Android L and earlier. For consumer + channels use "runtime permission" uses-permission-sdk-23 which provides + permission on Android M and later without a prompt. + --> + <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> + + <uses-permission-sdk-23 android:name="android.permission.BLUETOOTH" /> + <uses-permission-sdk-23 android:name="android.permission.BLUETOOTH_ADMIN" /> + <uses-permission-sdk-23 android:name="android.permission.READ_CONTACTS" /> + <uses-permission-sdk-23 android:name="android.permission.REORDER_TASKS" /> + <uses-permission-sdk-23 android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> + + <uses-permission android:name="android.permission.CAMERA" /> + <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" /> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> + <uses-permission android:name="android.permission.GET_ACCOUNTS" /> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> + <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> + <uses-permission android:name="android.permission.NFC" /> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> + <uses-permission android:name="android.permission.READ_SYNC_STATS" /> + <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> + <uses-permission android:name="android.permission.RECORD_AUDIO" /> + <uses-permission android:name="android.permission.USE_CREDENTIALS" /> + <uses-permission android:name="android.permission.VIBRATE" /> + <uses-permission android:name="android.permission.WAKE_LOCK" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" /> + <!-- Indicates use of Android's VR-mode, available only on Android N+. --> + <uses-feature + android:name="android.software.vr.mode" + android:required="false" /> + <!-- Indicates use of VR features that are available only on Daydream-ready devices. --> + <uses-feature + android:name="android.hardware.vr.high_performance" + android:required="false" /> + <!-- + Indicates that we don't need Chrome to be available on devices that only support landscape + orientation. This is needed because we have VR specific activities that declare the + android:orientation attribute. + --> + <uses-feature + android:name="android.hardware.screen.landscape" + android:required="false" /> + <!-- Indicates that head tracking should be done in 6DoF, if available --> + <uses-feature + android:name="android.hardware.vr.headtracking" + android:required="false" + android:version="1" /> + + <permission + android:name="org.chromium.chrome.permission.CHILD_SERVICE" + android:protectionLevel="signature" /> + <permission + android:name="org.chromium.chrome.permission.READ_WRITE_BOOKMARK_FOLDERS" + android:protectionLevel="signatureOrSystem" /> + <permission + android:name="org.chromium.chrome.TOS_ACKED" + android:protectionLevel="signatureOrSystem" /> + <!-- Only chrome can receive the messages and registration result --> + <permission + android:name="org.chromium.chrome.permission.C2D_MESSAGE" + android:protectionLevel="signature" /> + <permission + android:name="org.chromium.chrome.permission.DEBUG" + android:label="Debug web pages" + android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS" + android:protectionLevel="signature" /> + + <uses-permission android:name="org.chromium.chrome.permission.C2D_MESSAGE" /> + <uses-permission android:name="org.chromium.chrome.permission.READ_WRITE_BOOKMARK_FOLDERS" /> + <uses-permission android:name="org.chromium.chrome.TOS_ACKED" /> + <uses-permission android:name="com.chrome.permission.DEVICE_EXTRAS" /> + <uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" /> + <uses-permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS" /> + <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> + <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> + <uses-permission android:name="com.google.android.apps.now.CURRENT_ACCOUNT_ACCESS" /> + + <!-- We may use GPS but it's not required --> + <uses-feature + android:name="android.hardware.location.gps" + android:required="false" /> + <uses-feature + android:name="android.hardware.camera" + android:required="false" /> + + <!-- + android.permission.RECORD_AUDIO makes this implied, however we don't + require a microphone. + --> + <uses-feature + android:name="android.hardware.microphone" + android:required="false" /> + <!-- + The app is usable with keyboard/mouse. This feature is implicitly true for + all applications and needs to be disabled manually. + --> + <uses-feature + android:name="android.hardware.touchscreen" + android:required="false" /> + <!-- No keyset definitions should exist for any monochrome apks --> + <!-- + Set android:largeHeap to "true" to allow more than the default + Java heap limit (32Mb on Nexus S, 48Mb on Xoom). + --> + <application + android:name="org.chromium.chrome.browser.MonochromeApplication" + android:allowBackup="false" + android:extractNativeLibs="false" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:largeHeap="false" + android:manageSpaceActivity="@string/manage_space_activity" + android:multiArch="true" + android:networkSecurityConfig="@xml/network_security_config" + android:roundIcon="@drawable/ic_launcher_round" + android:supportsRtl="true" + android:use32bitAbi="true" > + + <!-- Samsung MultiWindow Support --> + <meta-data + android:name="com.samsung.android.sdk.multiwindow.enable" + android:value="true" /> + <meta-data + android:name="com.samsung.android.sdk.multiwindow.penwindow.enable" + android:value="true" /> + <meta-data + android:name="com.sec.android.support.multiwindow" + android:value="true" /> + <meta-data + android:name="android.content.APP_RESTRICTIONS" + android:resource="@xml/app_restrictions" /> + + <!-- ARCore APK integration --> + <!-- This tag indicates that this application optionally uses ARCore. --> + <meta-data + android:name="com.google.ar.core" + android:value="optional" /> + <!-- This value must match value present in ARCore SDK's .aar --> + <!-- + TODO(https://crbug.com/917406): modify build scripts to + automatically pull this value in - the problem exists because in + bundle mode, the ARCore SDK is packaged into AR module and + the module installation will not automatically bring in DFM's + manifest entries. + --> + <meta-data + android:name="com.google.ar.core.min_apk_version" + android:value="181012000" /> + + <!-- Cast support --> + <meta-data + android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME" + android:value="org.chromium.chrome.browser.media.router.caf.CastOptionsProvider" /> + + <!-- + Note: All activities directly or indirectly derived from ChromeActivity + must specify android:hardwareAccelerated="false". + + Since this activity (shown in the launcher) and the application + (shown in Android's Settings/Apps list) share the same label, we + do not specify one here to allow it to inherit from the app. + --> + <activity + android:name="org.chromium.chrome.browser.document.ChromeLauncherActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:excludeFromRecents="true" + android:relinquishTaskIdentity="true" + android:taskAffinity="" + android:theme="@style/LauncherTheme" > + + <!-- + TODO(mthiesse, b/72214458): This is a duplication of the icon metadata below. + Daydream will actually ignore the metadata here, and use the metadata on the + activity-alias. However, play store apk validation fails to find the icons on the + alias, so we need to include them here to pass validation. + --> + <meta-data + android:name="com.google.android.vr.icon" + android:resource="@drawable/daydream_icon_foreground" /> + <meta-data + android:name="com.google.android.vr.icon_background" + android:resource="@drawable/daydream_icon_background" /> + + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.IntentDispatcher" + android:exported="true" + android:targetActivity="org.chromium.chrome.browser.document.ChromeLauncherActivity" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.NOTIFICATION_PREFERENCES" /> + <category android:name="com.google.intent.category.DAYDREAM" /> + </intent-filter> + <!-- + Matches the common case of intents with no MIME type. + Make sure to keep in sync with the next filter. + --> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <category android:name="com.google.intent.category.DAYDREAM" /> + + <data android:scheme="googlechrome" /> + <data android:scheme="http" /> + <data android:scheme="https" /> + <data android:scheme="about" /> + <data android:scheme="javascript" /> + </intent-filter> + <!-- + Same filter as above but with MIME types. Intents that + do not specify a MIME type won't match. + --> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <category android:name="com.google.intent.category.DAYDREAM" /> + + <data android:scheme="googlechrome" /> + <data android:scheme="http" /> + <data android:scheme="https" /> + <data android:scheme="about" /> + <data android:scheme="javascript" /> + <data android:scheme="content" /> + <data android:mimeType="text/html" /> + <data android:mimeType="text/plain" /> + <data android:mimeType="application/xhtml+xml" /> + </intent-filter> + <!-- MHTML support, used for snapshots --> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + + <category android:name="android.intent.category.DEFAULT" /> + + <data android:scheme="file" /> + <data android:scheme="content" /> + <data android:mimeType="multipart/related" /> + </intent-filter> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + + <category android:name="android.intent.category.DEFAULT" /> + + <data android:scheme="file" /> + <data android:scheme="content" /> + <data android:mimeType="message/rfc822" /> + </intent-filter> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <category android:name="com.google.intent.category.DAYDREAM" /> + + <data android:scheme="file" /> + <data android:scheme="content" /> + <data android:host="*" /> + <data android:pathPattern="/.*\\.mhtml" /> + <data android:pathPattern="/.*\\.mht" /> + </intent-filter> + <!-- + Same filter as above but with mimeType="*/*". Used for + handling intent send by ShareIt. + --> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <category android:name="com.google.intent.category.DAYDREAM" /> + + <data android:scheme="file" /> + <data android:scheme="content" /> + <data android:host="*" /> + <data android:pathPattern="/.*\\.mhtml" /> + <data android:pathPattern="/.*\\.mht" /> + <data android:mimeType="*/*" /> + </intent-filter> + <intent-filter> + <action android:name="android.intent.action.MEDIA_SEARCH" /> + + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <intent-filter> + <action android:name="android.speech.action.VOICE_SEARCH_RESULTS" /> + + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <intent-filter> + <action android:name="android.nfc.action.NDEF_DISCOVERED" /> + + <category android:name="android.intent.category.DEFAULT" /> + + <data android:scheme="http" /> + <data android:scheme="https" /> + </intent-filter> + <intent-filter> + <action android:name="android.intent.action.SEARCH" /> + </intent-filter> + <intent-filter> + <action android:name="com.sec.android.airview.HOVER" /> + </intent-filter> + + <meta-data + android:name="android.app.searchable" + android:resource="@xml/searchable" /> + <meta-data + android:name="com.google.android.vr.icon" + android:resource="@drawable/daydream_icon_foreground" /> + <meta-data + android:name="com.google.android.vr.icon_background" + android:resource="@drawable/daydream_icon_background" /> + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.media.MediaLauncherActivity" + android:enabled="false" + android:excludeFromRecents="true" + android:exported="true" + android:theme="@android:style/Theme.NoDisplay" > <!-- This will be selectively enabled at runtime. --> + <intent-filter tools:ignore="AppLinkUrlError" > + <action android:name="android.intent.action.VIEW" /> + + <category android:name="android.intent.category.DEFAULT" /> + <!-- TODO(https://crbug.com/800875): Limit these to supported MIME types. --> + <data android:mimeType="audio/*" /> + <data android:mimeType="image/*" /> + <data android:mimeType="video/*" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.LauncherShortcutActivity" + android:excludeFromRecents="true" + android:exported="false" + android:taskAffinity="" + android:theme="@android:style/Theme.NoDisplay" /> + + <!-- Upgrade related --> + <activity + android:name="org.chromium.chrome.browser.upgrade.UpgradeActivity" + android:autoRemoveFromRecents="false" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:excludeFromRecents="true" + android:hardwareAccelerated="false" + android:launchMode="singleInstance" + android:persistableMode="persistNever" + android:taskAffinity="" + android:theme="@style/MainTheme" + android:windowSoftInputMode="adjustResize" > + </activity> + + <service + android:name="org.chromium.chrome.browser.upgrade.UpgradeIntentService" + android:exported="false" /> + + <receiver + android:name="org.chromium.chrome.browser.upgrade.PackageReplacedBroadcastReceiver" + android:exported="false" > + <intent-filter> + <action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> + </intent-filter> + </receiver> + + <!-- Locale related --> + <receiver + android:name="org.chromium.chrome.browser.locale.LocaleChangedBroadcastReceiver" + android:exported="false" > + <intent-filter> + <action android:name="android.intent.action.LOCALE_CHANGED" /> + </intent-filter> + </receiver> + + <!-- Document mode Activities. --> + <activity + android:name="org.chromium.chrome.browser.document.DocumentActivity" + android:autoRemoveFromRecents="false" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:persistableMode="persistAcrossReboots" + android:taskAffinity="" + android:theme="@style/MainTheme" + android:windowSoftInputMode="adjustResize" > + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.document.DocumentActivity" + android:exported="false" + android:targetActivity="org.chromium.chrome.browser.document.DocumentActivity" /> + + <activity + android:name="org.chromium.chrome.browser.document.IncognitoDocumentActivity" + android:autoRemoveFromRecents="false" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/incognito_app_icon" + android:persistableMode="persistNever" + android:taskAffinity="" + android:theme="@style/IncognitoTheme" + android:windowSoftInputMode="adjustResize" > + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.document.IncognitoDocumentActivity" + android:exported="false" + android:targetActivity="org.chromium.chrome.browser.document.IncognitoDocumentActivity" /> + + <!-- Custom Tabs --> + <activity + android:name="org.chromium.chrome.browser.customtabs.CustomTabActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:theme="@style/MainTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.customtabs.PaymentHandlerActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:theme="@style/TranslucentMainTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <!-- + SeparateTaskCustomTabActivity is a wrapper of CustomTabActivity. It provides the + general feeling of supporting multi tasks, even for versions that did not fully support + it. + TODO(arthursonzogni, tedchoc): Enabled this only on Android < 21 after M74. + --> + <activity + android:name="org.chromium.chrome.browser.customtabs.SeparateTaskCustomTabActivity" + android:autoRemoveFromRecents="false" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="" + android:theme="@style/MainTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.incognito.IncognitoDisclosureActivity" + android:exported="false" + android:theme="@style/FullscreenTransparentActivityTheme" > + </activity> + + <!-- ChromeTabbedActivity related --> + <activity + android:name="org.chromium.chrome.browser.ChromeTabbedActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="true" + android:hardwareAccelerated="false" + android:launchMode="singleTask" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:theme="@style/TabbedModeTheme" + android:windowSoftInputMode="adjustResize" > + + <!-- + Daydream api categorizes an activity to three categories: Cardboard only, hybrid + or Daydream. It does so by testing if intents can be resolved by the activity + that requests it. + --> + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> <!-- TODO(crbug.com/780674): retarget .Main back to CTA for non-modern APK --> + <activity-alias + android:name="com.google.android.apps.chrome.Main" + android:exported="true" + android:targetActivity="org.chromium.chrome.browser.ChromeTabbedActivity" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.LAUNCHER" /> + <category android:name="android.intent.category.BROWSABLE" /> + <category android:name="android.intent.category.APP_BROWSER" /> + <category android:name="android.intent.category.MULTIWINDOW_LAUNCHER" /> + </intent-filter> + + <meta-data + android:name="android.app.shortcuts" + android:resource="@xml/launchershortcuts" /> + + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.ChromeTabbedActivity2" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:launchMode="singleTask" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.ChromeTabbedActivity2" + android:theme="@style/TabbedModeTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.multiwindow.MultiInstanceChromeTabbedActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:theme="@style/TabbedModeTheme" + android:windowSoftInputMode="adjustResize" > + </activity> + <activity + android:name="org.chromium.chrome.browser.NoTouchActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:launchMode="singleTask" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:theme="@style/MainTheme" + android:windowSoftInputMode="adjustResize" > + </activity> + <activity + android:name="org.chromium.chrome.browser.sync.ui.PassphraseActivity" + android:autoRemoveFromRecents="true" + android:theme="@style/MainTheme" > + </activity> + <activity + android:name="org.chromium.chrome.browser.firstrun.LightweightFirstRunActivity" + android:autoRemoveFromRecents="true" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:excludeFromRecents="true" + android:label="@string/fre_activity_label" + android:launchMode="singleInstance" + android:theme="@style/SimpleDialog" + android:windowSoftInputMode="stateHidden|adjustPan" > + </activity> + <activity + android:name="org.chromium.chrome.browser.firstrun.FirstRunActivity" + android:autoRemoveFromRecents="true" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:excludeFromRecents="true" + android:label="@string/fre_activity_label" + android:launchMode="singleInstance" + android:theme="@style/FirstRunTheme" + android:windowSoftInputMode="stateHidden|adjustPan" > + </activity> + <activity + android:name="org.chromium.chrome.browser.firstrun.TabbedModeFirstRunActivity" + android:autoRemoveFromRecents="true" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:excludeFromRecents="true" + android:label="@string/fre_activity_label" + android:launchMode="singleInstance" + android:theme="@style/TabbedModeFirstRunTheme" + android:windowSoftInputMode="stateHidden|adjustPan" > + </activity> + <activity + android:name="org.chromium.chrome.browser.vr.VrFirstRunActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode" + android:enableVrMode="@string/gvr_vr_mode_component" + android:excludeFromRecents="true" + android:exported="false" + android:launchMode="singleInstance" + android:theme="@style/VrActivityTheme" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.signin.AccountSigninActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:theme="@style/DialogWhenLarge" > + </activity> + <activity + android:name="org.chromium.chrome.browser.signin.SigninActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:exported="false" + android:theme="@style/DialogWhenLarge" > + </activity> + <activity + android:name="org.chromium.chrome.browser.preferences.Preferences" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:exported="false" + android:label="@string/preferences" + android:theme="@style/PreferencesTheme" > + </activity> + <activity + android:name="org.chromium.chrome.browser.preferences.website.ManageSpaceActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:exported="false" + android:label="@string/storage_management_activity_label" + android:theme="@style/ManageSpaceTheme" > + </activity> + <activity + android:name="org.chromium.chrome.browser.bookmarks.BookmarkActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:exported="false" + android:theme="@style/FullscreenWhiteActivityTheme" + android:windowSoftInputMode="stateAlwaysHidden|adjustResize" > + </activity> + <activity + android:name="org.chromium.chrome.browser.bookmarks.BookmarkAddActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:theme="@style/DialogWhenLarge" + android:windowSoftInputMode="stateHidden" > + <intent-filter> + <action android:name="org.chromium.chrome.ADDBOOKMARK" /> + + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.bookmarks.BookmarkEditActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:exported="false" + android:label="@string/edit_bookmark" + android:theme="@style/DialogWhenLarge" + android:windowSoftInputMode="stateHidden" > + </activity> + <activity + android:name="org.chromium.chrome.browser.bookmarks.BookmarkAddEditFolderActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:exported="false" + android:theme="@style/DialogWhenLarge" > + </activity> + <activity + android:name="org.chromium.chrome.browser.bookmarks.BookmarkFolderSelectActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:exported="false" + android:label="@string/bookmark_choose_folder" + android:theme="@style/DialogWhenLarge" + android:windowSoftInputMode="stateAlwaysHidden" > + </activity> + + <!-- Activities for downloads. --> + <activity + android:name="org.chromium.chrome.browser.download.DownloadActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:exported="false" + android:theme="@style/FullscreenWhiteActivityTheme" + android:windowSoftInputMode="stateAlwaysHidden|adjustResize" > + </activity> + + <!-- Activities for history. --> + <activity + android:name="org.chromium.chrome.browser.history.HistoryActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:exported="false" + android:theme="@style/FullscreenWhiteActivityTheme" + android:windowSoftInputMode="stateAlwaysHidden|adjustResize" > + </activity> + + <!-- + Activities for webapps. + TODO(dfalcantara): Remove the aliases for the WebappActivities once we're pretty sure + that users don't have any instances of the original Activity still + running. + --> + <activity + android:name="org.chromium.chrome.browser.webapps.WebappLauncherActivity" + android:excludeFromRecents="true" + android:taskAffinity="" + android:theme="@android:style/Theme.NoDisplay" > + <intent-filter> + <action android:name="com.google.android.apps.chrome.webapps.WebappManager.ACTION_START_WEBAPP" /> + + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <intent-filter> + <action android:name="org.webapk.ACTION_START_WEBAPK" /> + + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappManager" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappLauncherActivity" > + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.webapps.WebappActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:documentLaunchMode="intoExisting" + android:exported="false" + android:hardwareAccelerated="false" + android:label="@string/webapp_activity_title" + android:launchMode="singleTop" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappActivity" + android:label="@string/webapp_activity_title" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity" > + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.webapps.WebappActivity0" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebappActivity0" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappActivity0" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity0" > + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.webapps.WebappActivity1" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebappActivity1" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappActivity1" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity1" > + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.webapps.WebappActivity2" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebappActivity2" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappActivity2" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity2" > + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.webapps.WebappActivity3" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebappActivity3" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappActivity3" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity3" > + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.webapps.WebappActivity4" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebappActivity4" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappActivity4" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity4" > + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.webapps.WebappActivity5" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebappActivity5" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappActivity5" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity5" > + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.webapps.WebappActivity6" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebappActivity6" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappActivity6" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity6" > + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.webapps.WebappActivity7" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebappActivity7" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappActivity7" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity7" > + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.webapps.WebappActivity8" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebappActivity8" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappActivity8" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity8" > + </activity-alias> + + <activity + android:name="org.chromium.chrome.browser.webapps.WebappActivity9" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebappActivity9" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <activity-alias + android:name="com.google.android.apps.chrome.webapps.WebappActivity9" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity9" > + </activity-alias> + <!-- Activities for WebAPKs. --> + <activity + android:name="org.chromium.chrome.browser.webapps.SameTaskWebApkActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:label="@string/webapp_activity_title" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.webapps.WebApkActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:documentLaunchMode="intoExisting" + android:exported="false" + android:hardwareAccelerated="false" + android:label="@string/webapp_activity_title" + android:launchMode="singleTop" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.webapps.WebApkActivity0" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebApkActivity0" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.webapps.WebApkActivity1" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebApkActivity1" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.webapps.WebApkActivity2" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebApkActivity2" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.webapps.WebApkActivity3" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebApkActivity3" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.webapps.WebApkActivity4" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebApkActivity4" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.webapps.WebApkActivity5" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebApkActivity5" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.webapps.WebApkActivity6" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebApkActivity6" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.webapps.WebApkActivity7" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebApkActivity7" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.webapps.WebApkActivity8" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebApkActivity8" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.webapps.WebApkActivity9" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density" + android:exported="false" + android:hardwareAccelerated="false" + android:icon="@mipmap/app_shortcut_icon" + android:label="@string/webapp_activity_title" + android:launchMode="singleTask" + android:persistableMode="persistNever" + android:resizeableActivity="true" + android:supportsPictureInPicture="true" + android:taskAffinity="org.chromium.chrome.webapps.WebApkActivity9" + android:theme="@style/WebappTheme" + android:windowSoftInputMode="adjustResize" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.media.remote.ExpandedControllerActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:excludeFromRecents="true" + android:hardwareAccelerated="true" + android:label="Chrome.ExpandedControllerActivity" + android:launchMode="singleTask" + android:noHistory="true" + android:theme="@style/MainTheme" > + </activity> + <activity + android:name="org.chromium.chrome.browser.media.router.caf.remoting.CafExpandedControllerActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:excludeFromRecents="true" + android:hardwareAccelerated="true" + android:label="Chrome.CafExpandedControllerActivity" + android:launchMode="singleTask" + android:noHistory="true" + android:theme="@style/MainTheme" > + </activity> + + <!-- This activity is used to restart the main Chrome process. Should never be exported. --> + <activity + android:name="org.chromium.chrome.browser.BrowserRestartActivity" + android:excludeFromRecents="true" + android:exported="false" + android:launchMode="singleInstance" + android:process=":browser_restart_process" + android:theme="@android:style/Theme.Translucent.NoTitleBar" > + </activity> + + <!-- This activity is to expose the print option via the generic Android share action. --> + <activity + android:name="org.chromium.chrome.browser.printing.PrintShareActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:enabled="false" + android:excludeFromRecents="true" + android:exported="true" + android:icon="@drawable/print" + android:label="@string/print_share_activity_title" + android:noHistory="true" + android:theme="@android:style/Theme.NoDisplay" > + <intent-filter> + <action android:name="android.intent.action.SEND" /> + + <category android:name="android.intent.category.DEFAULT" /> + + <data android:mimeType="text/plain" /> + </intent-filter> + </activity> + <activity + android:name="org.chromium.chrome.browser.send_tab_to_self.SendTabToSelfShareActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:enabled="false" + android:excludeFromRecents="true" + android:exported="true" + android:icon="@drawable/ic_launcher" + android:label="@string/send_tab_to_self_share_activity_title" + android:noHistory="true" + android:theme="@android:style/Theme.NoDisplay" > + <intent-filter> + <action android:name="android.intent.action.SEND" /> + + <category android:name="android.intent.category.DEFAULT" /> + + <data android:mimeType="text/plain" /> + </intent-filter> + </activity> + + <!-- Activity for dispatching intents to Instant Apps. --> + <activity + android:name="org.chromium.chrome.browser.instantapps.AuthenticatedProxyActivity" + android:excludeFromRecents="true" + android:exported="false" + android:noHistory="true" + android:theme="@android:style/Theme.NoDisplay" > + </activity> + <activity + android:name="org.chromium.chrome.browser.vr.VrCancelAnimationActivity" + android:enableVrMode="@string/gvr_vr_mode_component" + android:excludeFromRecents="true" + android:exported="false" + android:noHistory="true" + android:theme="@android:style/Theme.NoDisplay" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.dummy.action" /> + + <category android:name="com.google.intent.category.DAYDREAM" /> + <category android:name="com.google.intent.category.CARDBOARD" /> + </intent-filter> + </activity> + + <!-- Activities for Browser Actions --> + <activity + android:name="org.chromium.chrome.browser.browseractions.BrowserActionActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:exported="true" + android:theme="@style/FullscreenTransparentActivityTheme" > + <intent-filter> + <action android:name="androidx.browser.browseractions.browser_action_open" /> + + <category android:name="android.intent.category.DEFAULT" /> + + <data android:scheme="http" /> + <data android:scheme="https" /> + </intent-filter> + </activity> + + <service + android:name="org.chromium.chrome.browser.browseractions.BrowserActionsService" + android:exported="false" > + </service> + + <!-- Components for Trusted Web Activities --> + <receiver + android:name="org.chromium.chrome.browser.browserservices.ClientAppBroadcastReceiver" + android:exported="true" > + <intent-filter> + <data android:scheme="package" /> + + <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" /> + <action android:name="android.intent.action.PACKAGE_DATA_CLEARED" /> + </intent-filter> + <intent-filter> + <action android:name="org.chromium.chrome.browser.browserservices.ClientAppBroadcastReceiver.DEBUG" /> + </intent-filter> + </receiver> + + <!-- Not used at this point --> + <service + android:name="org.chromium.chrome.browser.browserservices.ClearDataService" + android:exported="false" > + </service> + + <activity + android:name="org.chromium.chrome.browser.browserservices.ClearDataDialogActivity" + android:exported="false" + android:theme="@style/ClearDataDialogActivityTheme" /> + <activity + android:name="org.chromium.chrome.browser.browserservices.ManageTrustedWebActivityDataActivity" + android:exported="true" + android:theme="@style/FullscreenTransparentActivityTheme" > + <intent-filter> + <action android:name="android.support.customtabs.action.ACTION_MANAGE_TRUSTED_WEB_ACTIVITY_DATA" /> + + <category android:name="android.intent.category.DEFAULT" /> + + <data android:scheme="https" /> + </intent-filter> + </activity> + + <!-- Service for decoding images in a sandboxed process. --> + <service + android:name="org.chromium.chrome.browser.photo_picker.DecoderService" + android:description="@string/decoder_description" + android:exported="false" + android:isolatedProcess="true" + android:process=":decoder_service" /> + + <!-- Providers for chrome data. --> + <provider + android:name="org.chromium.chrome.browser.provider.ChromeBrowserProvider" + android:authorities="org.chromium.chrome.ChromeBrowserProvider;org.chromium.chrome.browser;org.chromium.chrome" + android:exported="true" > + <path-permission + android:path="/bookmarks/search_suggest_query" + android:readPermission="android.permission.GLOBAL_SEARCH" /> + </provider> + + <!-- Provider for FileProvider. --> + <provider + android:name="org.chromium.chrome.browser.util.ChromeFileProvider" + android:authorities="org.chromium.chrome.FileProvider" + android:exported="false" + android:grantUriPermissions="true" > + <meta-data + android:name="android.support.FILE_PROVIDER_PATHS" + android:resource="@xml/file_paths" /> + </provider> + + <!-- Sync adapter for browser invalidation. --> + <service + android:name="org.chromium.chrome.browser.invalidation.ChromeBrowserSyncAdapterService" + android:exported="false" > + <intent-filter> + <action android:name="android.content.SyncAdapter" /> + </intent-filter> + + <meta-data + android:name="android.content.SyncAdapter" + android:resource="@xml/syncadapter" /> + </service> + + <!-- Broadcast receiver that will be notified of account changes --> + <receiver android:name="org.chromium.chrome.browser.services.AccountsChangedReceiver" > + <intent-filter> + <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" /> + </intent-filter> + </receiver> + + <!-- Download foreground service --> + <service + android:name="org.chromium.chrome.browser.download.DownloadForegroundService" + android:exported="false" > + </service> + + <!-- Download broadcast manager service --> + <service + android:name="org.chromium.chrome.browser.download.DownloadBroadcastManager" + android:exported="false" > + </service> + + <!-- Bookmarks widget --> + <receiver + android:name="com.google.android.apps.chrome.appwidget.bookmarks.BookmarkThumbnailWidgetProvider" + android:label="@string/bookmark_widget_title" > + <intent-filter> + <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> + <action android:name=".BOOKMARK_APPWIDGET_UPDATE" /> + </intent-filter> + + <meta-data + android:name="android.appwidget.provider" + android:resource="@xml/bookmark_widget_info" /> + </receiver> + + <service + android:name="org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetService" + android:exported="false" + android:permission="android.permission.BIND_REMOTEVIEWS" /> + + <receiver + android:name="org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProxy" + android:exported="false" /> + + <!-- Search widget --> + <receiver + android:name="org.chromium.chrome.browser.searchwidget.SearchWidgetProvider" + android:label="@string/search_widget_title" > + <intent-filter> + <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> + </intent-filter> + <intent-filter> + <action android:name="org.chromium.chrome.browser.searchwidget.START_TEXT_QUERY" /> + </intent-filter> + <intent-filter> + <action android:name="org.chromium.chrome.browser.searchwidget.START_VOICE_QUERY" /> + </intent-filter> + <intent-filter> + <action android:name="org.chromium.chrome.browser.searchwidget.UPDATE_ALL_WIDGETS" /> + </intent-filter> + + <meta-data + android:name="android.appwidget.provider" + android:resource="@xml/search_widget_info" /> + </receiver> + + <!-- Search Activity --> + <activity + android:name="org.chromium.chrome.browser.searchwidget.SearchActivity" + android:clearTaskOnLaunch="true" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" + android:excludeFromRecents="true" + android:exported="false" + android:hardwareAccelerated="false" + android:label="Search" + android:launchMode="singleTask" + android:taskAffinity="" + android:theme="@style/SearchActivityTheme" + android:windowSoftInputMode="adjustResize" /> + + <!-- Receiver for GCM messages. --> + <receiver + android:name="com.google.android.gms.gcm.GcmReceiver" + android:exported="true" + android:permission="com.google.android.c2dm.permission.SEND" > + <intent-filter> + <action android:name="com.google.android.c2dm.intent.RECEIVE" /> + <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> + + <category android:name="org.chromium.chrome" /> + </intent-filter> + </receiver> + <!-- GcmTaskService for registration for Invalidations. --> + <service + android:name="com.google.ipc.invalidation.ticl.android2.channel.GcmRegistrationTaskService" + android:exported="true" + android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE" > + <intent-filter> + <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" /> + </intent-filter> + </service> + <!-- InstanceIDListenerService for token refresh events from GCM. --> + <service + android:name="com.google.ipc.invalidation.ticl.android2.channel.AndroidInstanceIDListenerService" + android:exported="false" > + <intent-filter> + <action android:name="com.google.android.gms.iid.InstanceID" /> + </intent-filter> + </service> + <!-- GcmListenerService for messages from GCM. --> + <service + android:name="org.chromium.chrome.browser.services.gcm.ChromeGcmListenerService" + android:exported="false" > + <intent-filter> + <action android:name="com.google.android.c2dm.intent.RECEIVE" /> + </intent-filter> + </service> + + <meta-data + android:name="ipc.invalidation.ticl.gcm_upstream_service_class" + android:value="org.chromium.chrome.browser.services.gcm.InvalidationGcmUpstreamSender" /> + + <service + android:name="org.chromium.chrome.browser.services.gcm.InvalidationGcmUpstreamSender" + android:exported="false" /> + + <!-- Notification service for sync. --> + <meta-data + android:name="ipc.invalidation.ticl.listener_service_class" + android:value="org.chromium.chrome.browser.invalidation.ChromeInvalidationClientService" /> + + <service + android:name="org.chromium.chrome.browser.invalidation.ChromeInvalidationClientService" + android:exported="false" > + <intent-filter> + <action android:name="com.google.ipc.invalidation.AUTH_TOKEN_REQUEST" /> + </intent-filter> + </service> + <service + android:name="com.google.ipc.invalidation.ticl.android2.TiclService" + android:exported="false" /> + <service + android:name="com.google.ipc.invalidation.ticl.android2.channel.AndroidMessageSenderService" + android:exported="false" /> + + <receiver + android:name="com.google.ipc.invalidation.ticl.android2.AndroidInternalScheduler$AlarmReceiver" + android:exported="false" /> + <receiver + android:name="com.google.ipc.invalidation.external.client.contrib.AndroidListener$AlarmReceiver" + android:exported="false" /> + + <!-- Android Notification service listener --> + <service + android:name="org.chromium.chrome.browser.notifications.NotificationService" + android:exported="false" /> + + <receiver + android:name="org.chromium.chrome.browser.notifications.NotificationService$Receiver" + android:exported="false" > + <intent-filter> + <action android:name="org.chromium.chrome.browser.notifications.CLICK_NOTIFICATION" /> + <action android:name="org.chromium.chrome.browser.notifications.CLOSE_NOTIFICATION" /> + </intent-filter> + </receiver> + + <!-- Android Notification job service --> + <service + android:name="org.chromium.chrome.browser.notifications.NotificationJobService" + android:exported="false" + android:permission="android.permission.BIND_JOB_SERVICE" /> + + <!-- Background Task Scheduler job service --> + <service + android:name="org.chromium.components.background_task_scheduler.BackgroundTaskJobService" + android:exported="false" + android:permission="android.permission.BIND_JOB_SERVICE" /> + + <!-- Background Task Scheduler GCM task service --> + <service + android:name="org.chromium.components.background_task_scheduler.BackgroundTaskGcmTaskService" + android:exported="true" + android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE" > + <intent-filter> + <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" /> + </intent-filter> + </service> + + <!-- GcmTaskService implementation to wake Chrome on scheduled events --> + <service + android:name="org.chromium.chrome.browser.ChromeBackgroundService" + android:exported="true" + android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE" > + <intent-filter> + <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" /> + </intent-filter> + </service> + <service + android:name="org.chromium.chrome.browser.prerender.ChromePrerenderService" + android:exported="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.chrome.browser.customtabs.CustomTabsConnectionService" + android:exported="true" + tools:ignore="ExportedService" > + <intent-filter> + <action android:name="android.support.customtabs.action.CustomTabsService" /> + </intent-filter> + </service> + <service android:name="android.support.customtabs.PostMessageService" /> + + <!-- Crash reporting services. --> + <service + android:name="org.chromium.chrome.browser.crash.ChromeMinidumpUploadJobService" + android:exported="false" + android:permission="android.permission.BIND_JOB_SERVICE" /> + <service + android:name="org.chromium.chrome.browser.crash.MinidumpUploadService" + android:exported="false" /> + <service + android:name="org.chromium.chrome.browser.omaha.OmahaClient" + android:exported="false" /> + <service + android:name="org.chromium.chrome.browser.incognito.IncognitoNotificationService" + android:exported="false" /> + + <!-- + The following service entries exist in order to allow us to + start more than one sandboxed process. + --> + + + <!-- + NOTE: If you change the value of "android:process" for the below services, + you also need to update kHelperProcessExecutableName in chrome_constants.cc. + --> + <meta-data + android:name="org.chromium.content.browser.NUM_SANDBOXED_SERVICES" + android:value="40" /> + + <service + android:name="org.chromium.content.app.SandboxedProcessService0" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process0" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService1" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process1" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService2" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process2" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService3" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process3" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService4" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process4" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService5" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process5" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService6" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process6" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService7" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process7" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService8" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process8" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService9" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process9" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService10" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process10" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService11" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process11" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService12" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process12" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService13" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process13" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService14" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process14" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService15" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process15" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService16" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process16" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService17" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process17" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService18" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process18" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService19" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process19" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService20" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process20" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService21" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process21" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService22" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process22" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService23" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process23" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService24" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process24" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService25" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process25" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService26" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process26" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService27" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process27" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService28" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process28" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService29" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process29" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService30" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process30" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService31" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process31" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService32" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process32" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService33" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process33" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService34" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process34" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService35" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process35" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService36" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process36" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService37" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process37" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService38" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process38" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + <service + android:name="org.chromium.content.app.SandboxedProcessService39" + android:exported="true" + android:externalService="true" + android:isolatedProcess="true" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":sandboxed_process39" + android:visibleToInstantApps="true" + tools:ignore="ExportedService" /> + + <meta-data + android:name="org.chromium.content.browser.NUM_PRIVILEGED_SERVICES" + android:value="5" /> + + <!-- TODO(tedchoc): Omit this for release builds as MultiDex is debug only. --> + <meta-data + android:name="org.chromium.chrome:privileged_process0.ignore_multidex" + android:value="true" /> + + <service + android:name="org.chromium.content.app.PrivilegedProcessService0" + android:exported="false" + android:isolatedProcess="false" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":privileged_process0" /> + <!-- TODO(tedchoc): Omit this for release builds as MultiDex is debug only. --> + <meta-data + android:name="org.chromium.chrome:privileged_process1.ignore_multidex" + android:value="true" /> + + <service + android:name="org.chromium.content.app.PrivilegedProcessService1" + android:exported="false" + android:isolatedProcess="false" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":privileged_process1" /> + <!-- TODO(tedchoc): Omit this for release builds as MultiDex is debug only. --> + <meta-data + android:name="org.chromium.chrome:privileged_process2.ignore_multidex" + android:value="true" /> + + <service + android:name="org.chromium.content.app.PrivilegedProcessService2" + android:exported="false" + android:isolatedProcess="false" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":privileged_process2" /> + <!-- TODO(tedchoc): Omit this for release builds as MultiDex is debug only. --> + <meta-data + android:name="org.chromium.chrome:privileged_process3.ignore_multidex" + android:value="true" /> + + <service + android:name="org.chromium.content.app.PrivilegedProcessService3" + android:exported="false" + android:isolatedProcess="false" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":privileged_process3" /> + <!-- TODO(tedchoc): Omit this for release builds as MultiDex is debug only. --> + <meta-data + android:name="org.chromium.chrome:privileged_process4.ignore_multidex" + android:value="true" /> + + <service + android:name="org.chromium.content.app.PrivilegedProcessService4" + android:exported="false" + android:isolatedProcess="false" + android:permission="org.chromium.chrome.permission.CHILD_SERVICE" + android:process=":privileged_process4" /> + + <receiver + android:name="org.chromium.chrome.browser.download.DownloadBroadcastReceiver" + android:exported="false" > + <intent-filter> + <action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED" /> + </intent-filter> + </receiver> + <receiver + android:name="org.chromium.chrome.browser.notifications.NotificationIntentInterceptor$Receiver" + android:exported="false" /> + <receiver + android:name="org.chromium.chrome.browser.ntp.ContentSuggestionsNotifier$OpenUrlReceiver" + android:exported="false" /> + <receiver + android:name="org.chromium.chrome.browser.ntp.ContentSuggestionsNotifier$DeleteReceiver" + android:exported="false" /> + <receiver + android:name="org.chromium.chrome.browser.ntp.ContentSuggestionsNotifier$TimeoutReceiver" + android:exported="false" /> + <receiver + android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$ClickReceiver" + android:exported="false" /> + <receiver + android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$SettingsReceiver" + android:exported="false" /> + <receiver + android:name="org.chromium.chrome.browser.offlinepages.AutoFetchNotifier$CompleteNotificationReceiver" + android:exported="false" /> + <receiver + android:name="org.chromium.chrome.browser.offlinepages.AutoFetchNotifier$InProgressCancelReceiver" + android:exported="false" /> + + <service + android:name="org.chromium.chrome.browser.media.MediaCaptureNotificationService" + android:exported="false" /> + <service + android:name="org.chromium.chrome.browser.media.ui.MediaNotificationManager$PlaybackListenerService" + android:exported="false" > + <intent-filter> + <action android:name="android.intent.action.MEDIA_BUTTON" /> + </intent-filter> + </service> + <service + android:name="org.chromium.chrome.browser.media.ui.MediaNotificationManager$PresentationListenerService" + android:exported="false" > + <intent-filter> + <action android:name="android.intent.action.MEDIA_BUTTON" /> + </intent-filter> + </service> + <service + android:name="org.chromium.chrome.browser.media.ui.MediaNotificationManager$CastListenerService" + android:exported="false" > + <intent-filter> + <action android:name="android.intent.action.MEDIA_BUTTON" /> + </intent-filter> + </service> + + <receiver android:name="org.chromium.chrome.browser.media.ui.MediaNotificationManager$PlaybackMediaButtonReceiver" > + <intent-filter> + <action android:name="android.intent.action.MEDIA_BUTTON" /> + </intent-filter> + </receiver> + <receiver android:name="org.chromium.chrome.browser.media.ui.MediaNotificationManager$PresentationMediaButtonReceiver" > + <intent-filter> + <action android:name="android.intent.action.MEDIA_BUTTON" /> + </intent-filter> + </receiver> + <receiver android:name="org.chromium.chrome.browser.media.ui.MediaNotificationManager$CastMediaButtonReceiver" > + <intent-filter> + <action android:name="android.intent.action.MEDIA_BUTTON" /> + </intent-filter> + </receiver> + + <service + android:name="org.chromium.chrome.browser.tracing.TracingNotificationService" + android:exported="false" /> + + <meta-data + android:name="org.chromium.content.browser.SMART_CLIP_PROVIDER" + android:value="org.chromium.content_public.browser.SmartClipProvider" /> + + <!-- + Media route controllers to use for remote playback (cast). + This is here, rather than in code, since it varies between upstream and downstream, + yet we need this list of classes in the notification service, which belongs upstream + and doesn't run the downstream startup code. The Cast code will, for each media element, + choose the first MediaRouteController that can play it, so the order of the list can be important. + The most specific MediaRouteControllers should be listed first, followed by more generic ones. + The downstream manifest replaces this block, and hence replaces the list of media route + controllers with its own list. + --> + <meta-data + android:name="org.chromium.content.browser.REMOTE_MEDIA_PLAYERS" + android:value="org.chromium.chrome.browser.media.remote.DefaultMediaRouteController" /> + <meta-data + android:name="com.android.webview.WebViewLibrary" + android:value="libmonochrome.so" /> + + <activity + android:name="com.android.webview.chromium.LicenseActivity" + android:label="@string/license_activity_title" > + <intent-filter> + <action android:name="android.settings.WEBVIEW_LICENSE" /> + + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + + <meta-data + android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" + android:value="true" /> + </activity> + + <provider + android:name="com.android.webview.chromium.LicenseContentProvider" + android:authorities="org.chromium.chrome.LicenseContentProvider" + android:exported="true" /> + <!-- + If you change the variations services, also see + android_webview/test/shell/AndroidManifest.xml. + --> + <service + android:name="org.chromium.android_webview.services.VariationsSeedServer" + android:exported="true" + android:process=":webview_service" /> + <service + android:name="org.chromium.android_webview.services.AwVariationsSeedFetcher" + android:exported="false" + android:permission="android.permission.BIND_JOB_SERVICE" + android:process=":webview_service" /> + <service + android:name="org.chromium.android_webview.services.CrashReceiverService" + android:exported="true" + android:process=":webview_service" /> + <service + android:name="org.chromium.android_webview.services.AwMinidumpUploadJobService" + android:exported="true" + android:permission="android.permission.BIND_JOB_SERVICE" + android:process=":webview_service" /> + + <meta-data + android:name="android.arch.lifecycle.VERSION" + android:value="27.0.0-SNAPSHOT" /> + <meta-data + android:name="com.google.android.gms.version" + android:value="@integer/google_play_services_version" /> + + <activity + android:name="com.google.android.gms.common.api.GoogleApiActivity" + android:exported="false" + android:theme="@android:style/Theme.Translucent.NoTitleBar" /> + + <receiver + android:name="com.google.android.gms.cast.framework.media.MediaIntentReceiver" + android:exported="false" /> + + <service + android:name="com.google.android.gms.cast.framework.media.MediaNotificationService" + android:exported="false" /> + <service + android:name="com.google.android.gms.cast.framework.ReconnectionService" + android:exported="false" /> + + <provider + android:name="android.support.customtabs.browseractions.BrowserServiceFileProvider" + android:authorities="org.chromium.chrome.image_provider" + android:exported="false" + android:grantUriPermissions="true" > + <meta-data + android:name="android.support.FILE_PROVIDER_PATHS" + android:resource="@xml/image_share_filepaths" /> + </provider> <!-- This activity is critical for installing ARCore when it is not already present. --> + <activity + android:name="com.google.ar.core.InstallActivity" + android:configChanges="keyboardHidden|orientation|screenSize" + android:excludeFromRecents="true" + android:exported="false" + android:launchMode="singleTop" + android:theme="@android:style/Theme.Material.Light.Dialog.Alert" /> + </application> + +</manifest> \ No newline at end of file
diff --git a/chrome/android/java/res/layout/autofill_local_card_editor.xml b/chrome/android/java/res/layout/autofill_local_card_editor.xml index 8b6ffa33..f10a6e15 100644 --- a/chrome/android/java/res/layout/autofill_local_card_editor.xml +++ b/chrome/android/java/res/layout/autofill_local_card_editor.xml
@@ -19,7 +19,7 @@ <!-- TODO(crbug.com/900912): Fix and remove lint ignore --> <EditText - tools:ignore="Autofill" + tools:ignore="Autofill,LabelFor" android:id="@+id/credit_card_name_edit" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -40,7 +40,7 @@ <!-- TODO(crbug.com/900912): Fix and remove lint ignore --> <EditText - tools:ignore="Autofill" + tools:ignore="Autofill,LabelFor" android:id="@+id/credit_card_number_edit" android:layout_width="match_parent" android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/edit_url_suggestion_layout.xml b/chrome/android/java/res/layout/edit_url_suggestion_layout.xml index 463aeac..f34571e 100644 --- a/chrome/android/java/res/layout/edit_url_suggestion_layout.xml +++ b/chrome/android/java/res/layout/edit_url_suggestion_layout.xml
@@ -9,7 +9,8 @@ android:id="@+id/suggestions_url_view" android:minHeight="@dimen/omnibox_suggestion_edit_url_min_height" android:layout_width="match_parent" - android:layout_height="wrap_content" > + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground" > <LinearLayout android:id="@+id/edit_url_suggestion_icons"
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml index de0b48f..da76acec 100644 --- a/chrome/android/java/res/values-v17/styles.xml +++ b/chrome/android/java/res/values-v17/styles.xml
@@ -829,10 +829,10 @@ </style> <style name="OmniboxSuggestionIconButton"> - <item name="android:background">@null</item> + <item name="android:background">?attr/selectableItemBackground</item> <item name="android:layout_width">@dimen/min_touch_target_size</item> - <item name="android:layout_height">@dimen/min_touch_target_size</item> - <item name="tint">@color/default_icon_color_blue</item> + <item name="android:layout_height">@dimen/omnibox_suggestion_edit_url_min_height</item> + <item name="tint">@color/default_icon_color</item> </style> <!-- Trusted Web Activities -->
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 4dbff820..5e85b28 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -203,7 +203,7 @@ <dimen name="signin_promo_cold_state_image_size">24dp</dimen> <!-- Autofill card unmasking prompt dimensions --> - <dimen name="autofill_card_unmask_tooltip_horizontal_padding">16dp</dimen> + <dimen name="autofill_card_unmask_tooltip_horizontal_padding">8dp</dimen> <dimen name="autofill_card_unmask_tooltip_vertical_padding">8dp</dimen> <!-- Button bar dimensions -->
diff --git a/chrome/android/java/res/xml/manage_sync_preferences.xml b/chrome/android/java/res/xml/manage_sync_preferences.xml new file mode 100644 index 0000000..e0e4398 --- /dev/null +++ b/chrome/android/java/res/xml/manage_sync_preferences.xml
@@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2019 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<PreferenceScreen + xmlns:android="http://schemas.android.com/apk/res/android"> + + <org.chromium.chrome.browser.preferences.ChromeSwitchPreference + android:key="sync_everything" + android:title="@string/sync_everything_pref" + android:persistent="false"/> + + <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference + android:key="sync_autofill" + android:title="@string/sync_autofill" + android:persistent="false"/> + + <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference + android:key="sync_bookmarks" + android:title="@string/sync_bookmarks" + android:persistent="false"/> + + <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference + android:key="sync_payments_integration" + android:title="@string/sync_payments_integration" + android:persistent="false"/> + + <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference + android:key="sync_history" + android:title="@string/sync_history" + android:persistent="false"/> + + <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference + android:key="sync_passwords" + android:title="@string/sync_passwords" + android:persistent="false"/> + + <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference + android:key="sync_recent_tabs" + android:title="@string/sync_recent_tabs" + android:persistent="false"/> + + <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference + android:key="sync_settings" + android:title="@string/sync_settings" + android:persistent="false"/> + + <org.chromium.chrome.browser.preferences.ChromeBasePreference + android:key="google_activity_controls" + android:title="@string/sign_in_google_activity_controls_title" + android:summary="@string/sign_in_google_activity_controls_summary"/> + + <org.chromium.chrome.browser.preferences.ChromeBasePreference + android:key="encryption" + android:title="@string/sync_encryption"/> + + <org.chromium.chrome.browser.preferences.ChromeBasePreference + android:key="sync_manage_data" + android:title="@string/sync_manage_data"/> + +</PreferenceScreen>
diff --git a/chrome/android/java/res/xml/sync_and_services_preferences.xml b/chrome/android/java/res/xml/sync_and_services_preferences.xml index e05f79e..f1e12e0a 100644 --- a/chrome/android/java/res/xml/sync_and_services_preferences.xml +++ b/chrome/android/java/res/xml/sync_and_services_preferences.xml
@@ -17,53 +17,14 @@ android:icon="@drawable/sync_error" android:title="@string/sync_error_card_title"/> <org.chromium.chrome.browser.preferences.ChromeSwitchPreference - android:persistent="false" - android:key="use_sync_and_all_services" - android:title="@string/use_sync_and_all_services"/> + android:key="sync_requested" + android:title="@string/sync_switch_title" + android:persistent="false"/> - <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference - android:key="sync_autofill" - android:persistent="false" - android:title="@string/sync_autofill"/> - <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference - android:persistent="false" - android:key="sync_bookmarks" - android:title="@string/sync_bookmarks"/> - <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference - android:persistent="false" - android:key="sync_payments_integration" - android:title="@string/sync_payments_integration"/> - <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference - android:persistent="false" - android:key="sync_history" - android:title="@string/sync_history"/> - <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference - android:persistent="false" - android:key="sync_passwords" - android:title="@string/sync_passwords"/> - <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference - android:persistent="false" - android:key="sync_recent_tabs" - android:title="@string/sync_recent_tabs"/> - <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference - android:persistent="false" - android:key="sync_settings" - android:title="@string/sync_settings"/> - <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference - android:persistent="false" - android:key="sync_activity_and_interactions" - android:title="@string/sync_activity_and_interactions_title" - android:summary="@string/sync_activity_and_interactions_summary"/> <org.chromium.chrome.browser.preferences.ChromeBasePreference - android:key="google_activity_controls" - android:title="@string/sign_in_google_activity_controls_title" - android:summary="@string/sign_in_google_activity_controls_summary"/> - <org.chromium.chrome.browser.preferences.ChromeBasePreference - android:key="encryption" - android:title="@string/sync_encryption"/> - <org.chromium.chrome.browser.preferences.ChromeBasePreference - android:key="sync_manage_data" - android:title="@string/sync_manage_data"/> + android:key="manage_sync" + android:title="@string/manage_sync_title" + android:fragment="org.chromium.chrome.browser.preferences.ManageSyncPreferences"/> </PreferenceCategory> <PreferenceCategory
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index 9709b1a8..601613f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -156,6 +156,7 @@ "AllowStartingServiceManagerOnly"; public static final String AUTOFILL_ALLOW_NON_HTTP_ACTIVATION = "AutofillAllowNonHttpActivation"; + public static final String AUTOFILL_ENABLE_COMPANY_NAME = "AutofillEnableCompanyName"; public static final String ADJUST_WEBAPK_INSTALLATION_SPACE = "AdjustWebApkInstallationSpace"; public static final String ANDROID_NIGHT_MODE = "AndroidNightMode"; public static final String ANDROID_PAY_INTEGRATION_V1 = "AndroidPayIntegrationV1";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java index e54a23c..cb82257 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
@@ -12,6 +12,12 @@ import android.view.ViewGroup; import android.widget.LinearLayout; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantCarouselCoordinator; +import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetailsCoordinator; +import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderCoordinator; +import org.chromium.chrome.browser.autofill_assistant.payment.AssistantPaymentRequestCoordinator; + /** * Coordinator responsible for the Autofill Assistant bottom bar. This coordinator allows to enable * or disable the swipeable behavior of the bottom bar and ensures that the bottom bar height is @@ -38,18 +44,21 @@ private final int mChildrenVerticalSpacing; private final int mBottomBarWithoutIndicatorPaddingTop; - // The child views. - private View mDetailsView; - private View mPaymentRequestView; - private View mCarouselView; + // Child coordinators. + private final AssistantHeaderCoordinator mHeaderCoordinator; + private final AssistantDetailsCoordinator mDetailsCoordinator; + private final AssistantPaymentRequestCoordinator mPaymentRequestCoordinator; + private final AssistantCarouselCoordinator mCarouselCoordinator; - AssistantBottomBarCoordinator(View assistantView, DisplayMetrics displayMetrics) { + AssistantBottomBarCoordinator( + ChromeActivity activity, View assistantView, AssistantModel model) { mBottomBarView = assistantView.findViewById( org.chromium.chrome.autofill_assistant.R.id.autofill_assistant_bottombar); mSwipeIndicatorView = mBottomBarView.findViewById( org.chromium.chrome.autofill_assistant.R.id.swipe_indicator); mBottomBarBehavior = BottomSheetBehavior.from(mBottomBarView); + DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics(); mChildrenHorizontalMargin = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, CHILDREN_HORIZONTAL_MARGIN_DP, displayMetrics); mDetailsOnlyVerticalMargin = (int) TypedValue.applyDimension( @@ -59,6 +68,26 @@ mBottomBarWithoutIndicatorPaddingTop = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, BOTTOM_BAR_WITHOUT_INDICATOR_PADDING_TOP_DP, displayMetrics); + + // Instantiate child components. + mHeaderCoordinator = + new AssistantHeaderCoordinator(activity, mBottomBarView, model.getHeaderModel()); + mDetailsCoordinator = new AssistantDetailsCoordinator(activity, model.getDetailsModel()); + mPaymentRequestCoordinator = new AssistantPaymentRequestCoordinator(activity); + mCarouselCoordinator = new AssistantCarouselCoordinator(activity, model.getCarouselModel()); + + // Add child views to bottom bar. + mBottomBarView.addView(mDetailsCoordinator.getView()); + mBottomBarView.addView(mPaymentRequestCoordinator.getView()); + mBottomBarView.addView(mCarouselCoordinator.getView()); + + // Ensure the margin are computed correctly from the beginning. + onChildViewVisibilityChanged(); + + // Add child views visibility listener. + mDetailsCoordinator.setVisibilityChangedListener(this::onChildViewVisibilityChanged); + mPaymentRequestCoordinator.setVisibilityChangedListener(this::onChildViewVisibilityChanged); + mCarouselCoordinator.setVisibilityChangedListener(this::onChildViewVisibilityChanged); } /** @@ -70,35 +99,6 @@ } /** - * Set the details view to {@code detailsView}. This method should be called only once, before - * {@link #setPaymentRequestView} and {@link #setCarouselView}. - */ - public void setDetailsView(View detailsView) { - assert mDetailsView == null; - mDetailsView = detailsView; - mBottomBarView.addView(mDetailsView); - } - - /** - * Set the payment request view to {@code paymentRequestView}. This method should be called only - * once, before {@link #setCarouselView}. - */ - public void setPaymentRequestView(View paymentRequestView) { - assert mPaymentRequestView == null; - mPaymentRequestView = paymentRequestView; - mBottomBarView.addView(mPaymentRequestView); - } - - /** - * Set the carousel view to {@code carouselView}. This method should be called only once. - */ - public void setCarouselView(View carouselView) { - assert mCarouselView == null; - mCarouselView = carouselView; - mBottomBarView.addView(mCarouselView); - } - - /** * Make sure the bottom bar is expanded and text is visible. */ public void expand() { @@ -122,6 +122,14 @@ } } + public AssistantPaymentRequestCoordinator getPaymentRequestCoordinator() { + return mPaymentRequestCoordinator; + } + + public AssistantCarouselCoordinator getCarouselCoordinator() { + return mCarouselCoordinator; + } + private void setBottomBarPaddingTop(int paddingPx) { mBottomBarView.setPadding(0, paddingPx, 0, 0); } @@ -130,25 +138,28 @@ * Called when one of its child views visibility has changed. This method set the margin of * those views such that the height of the bottom bar is constant most of the time. */ - public void onChildVisibilityChanged() { - boolean detailsVisible = - mDetailsView != null && mDetailsView.getVisibility() == View.VISIBLE; + private void onChildViewVisibilityChanged() { + View detailsView = mDetailsCoordinator.getView(); + View carouselView = mCarouselCoordinator.getView(); + View paymentRequestView = mPaymentRequestCoordinator.getView(); + + boolean detailsVisible = detailsView != null && detailsView.getVisibility() == View.VISIBLE; boolean carouselVisible = - mCarouselView != null && mCarouselView.getVisibility() == View.VISIBLE; + carouselView != null && carouselView.getVisibility() == View.VISIBLE; boolean paymentRequestVisible = - mPaymentRequestView != null && mPaymentRequestView.getVisibility() == View.VISIBLE; + paymentRequestView != null && paymentRequestView.getVisibility() == View.VISIBLE; int topMargin = mChildrenVerticalSpacing; if (detailsVisible) { // Set details margins. LinearLayout.LayoutParams detailsLayoutParams = - (LinearLayout.LayoutParams) mDetailsView.getLayoutParams(); + (LinearLayout.LayoutParams) detailsView.getLayoutParams(); int detailsVerticalMargin = carouselVisible || paymentRequestVisible ? topMargin : mDetailsOnlyVerticalMargin; detailsLayoutParams.setMargins(mChildrenHorizontalMargin, detailsVerticalMargin, mChildrenHorizontalMargin, detailsVerticalMargin); - mDetailsView.setLayoutParams(detailsLayoutParams); + detailsView.setLayoutParams(detailsLayoutParams); topMargin = 0; } @@ -156,10 +167,10 @@ if (paymentRequestVisible) { // Set payment request margins. LinearLayout.LayoutParams paymentRequestLayoutParams = - (LinearLayout.LayoutParams) mPaymentRequestView.getLayoutParams(); + (LinearLayout.LayoutParams) paymentRequestView.getLayoutParams(); paymentRequestLayoutParams.setMargins(mChildrenHorizontalMargin, topMargin, mChildrenVerticalSpacing, mChildrenHorizontalMargin); - mPaymentRequestView.setLayoutParams(paymentRequestLayoutParams); + paymentRequestView.setLayoutParams(paymentRequestLayoutParams); topMargin = 0; } @@ -167,10 +178,10 @@ if (carouselVisible) { // Set carousel margins. LinearLayout.LayoutParams carouselLayoutParams = - (LinearLayout.LayoutParams) mCarouselView.getLayoutParams(); + (LinearLayout.LayoutParams) carouselView.getLayoutParams(); carouselLayoutParams.setMargins( /* left= */ 0, topMargin, /* right= */ 0, mChildrenVerticalSpacing); - mCarouselView.setLayoutParams(carouselLayoutParams); + carouselView.setLayoutParams(carouselLayoutParams); } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java index b05ea01..d32fc03 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
@@ -4,16 +4,15 @@ package org.chromium.chrome.browser.autofill_assistant; +import android.support.annotation.Nullable; import android.view.View; import android.view.ViewGroup; import org.chromium.base.ThreadUtils; import org.chromium.chrome.autofill_assistant.R; import org.chromium.chrome.browser.ChromeActivity; -import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantCarouselCoordinator; -import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetailsCoordinator; -import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderCoordinator; -import org.chromium.chrome.browser.autofill_assistant.payment.AssistantPaymentRequestCoordinator; +import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetails; +import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderModel; import org.chromium.chrome.browser.help.HelpAndFeedback; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.snackbar.Snackbar; @@ -54,10 +53,6 @@ private final View mAssistantView; private final AssistantBottomBarCoordinator mBottomBarCoordinator; - private final AssistantHeaderCoordinator mHeaderCoordinator; - private final AssistantDetailsCoordinator mDetailsCoordinator; - private final AssistantPaymentRequestCoordinator mPaymentRequestCoordinator; - private final AssistantCarouselCoordinator mCarouselCoordinator; private final AssistantKeyboardCoordinator mKeyboardCoordinator; private final AssistantOverlayCoordinator mOverlayCoordinator; @@ -75,29 +70,11 @@ .findViewById(R.id.autofill_assistant); // Instantiate child components. - mBottomBarCoordinator = new AssistantBottomBarCoordinator( - mAssistantView, mActivity.getResources().getDisplayMetrics()); - mHeaderCoordinator = new AssistantHeaderCoordinator( - mActivity, mBottomBarCoordinator.getView(), mModel.getHeaderModel()); - mCarouselCoordinator = new AssistantCarouselCoordinator(mActivity, - mModel.getCarouselModel(), mBottomBarCoordinator::onChildVisibilityChanged); - mDetailsCoordinator = new AssistantDetailsCoordinator( - mActivity, mBottomBarCoordinator::onChildVisibilityChanged); - mPaymentRequestCoordinator = new AssistantPaymentRequestCoordinator( - mActivity, mBottomBarCoordinator::onChildVisibilityChanged); + mBottomBarCoordinator = + new AssistantBottomBarCoordinator(mActivity, mAssistantView, mModel); mKeyboardCoordinator = new AssistantKeyboardCoordinator(activity); mOverlayCoordinator = new AssistantOverlayCoordinator(activity, mAssistantView, this); - // Attach child views to the bottom bar. - mBottomBarCoordinator.setDetailsView(mDetailsCoordinator.getView()); - mBottomBarCoordinator.setPaymentRequestView(mPaymentRequestCoordinator.getView()); - mBottomBarCoordinator.setCarouselView(mCarouselCoordinator.getView()); - - // Details, PR and carousel are initially hidden. - mDetailsCoordinator.setVisible(false); - mPaymentRequestCoordinator.setVisible(false); - mCarouselCoordinator.setVisible(false); - showAssistantView(); } @@ -124,12 +101,12 @@ // Hide everything except header. mOverlayCoordinator.hide(); - mDetailsCoordinator.setVisible(false); - mPaymentRequestCoordinator.setVisible(false); + mModel.getDetailsModel().clearDetails(); + mBottomBarCoordinator.getPaymentRequestCoordinator().setVisible(false); mModel.getCarouselModel().clearChips(); if (showGiveUpMessage) { - mHeaderCoordinator.setStatusMessage( + mModel.getHeaderModel().set(AssistantHeaderModel.STATUS_MESSAGE, mActivity.getString(R.string.autofill_assistant_give_up)); } ThreadUtils.postOnUiThreadDelayed(this::shutdownImmediately, GRACEFUL_SHUTDOWN_DELAY_MS); @@ -149,8 +126,8 @@ */ public void showOnboarding(Runnable onAccept) { // Hide header buttons. - mHeaderCoordinator.setFeedbackButtonVisible(false); - mHeaderCoordinator.setCloseButtonVisible(false); + mModel.getHeaderModel().set(AssistantHeaderModel.FEEDBACK_VISIBLE, false); + mModel.getHeaderModel().set(AssistantHeaderModel.CLOSE_VISIBLE, false); // Show overlay to prevent user from interacting with the page during onboarding. mOverlayCoordinator.showFullOverlay(); @@ -163,8 +140,8 @@ } // Show header buttons. - mHeaderCoordinator.setFeedbackButtonVisible(true); - mHeaderCoordinator.setCloseButtonVisible(true); + mModel.getHeaderModel().set(AssistantHeaderModel.FEEDBACK_VISIBLE, true); + mModel.getHeaderModel().set(AssistantHeaderModel.CLOSE_VISIBLE, true); // Hide overlay. mOverlayCoordinator.hide(); @@ -174,15 +151,6 @@ } /** - * Show {@code message} to the user, unless we are shutting down. - */ - public void showStatusMessage(String message) { - if (!mIsShuttingDownGracefully) { - mHeaderCoordinator.setStatusMessage(message); - } - } - - /** * Get the model representing the current state of the UI. */ @@ -196,22 +164,6 @@ return mBottomBarCoordinator; } - public AssistantHeaderCoordinator getHeaderCoordinator() { - return mHeaderCoordinator; - } - - public AssistantDetailsCoordinator getDetailsCoordinator() { - return mDetailsCoordinator; - } - - public AssistantPaymentRequestCoordinator getPaymentRequestCoordinator() { - return mPaymentRequestCoordinator; - } - - public AssistantCarouselCoordinator getCarouselCoordinator() { - return mCarouselCoordinator; - } - public AssistantKeyboardCoordinator getKeyboardCoordinator() { return mKeyboardCoordinator; } @@ -260,12 +212,12 @@ /** * Show the Chrome feedback form. */ - public void showFeedback(String debugContext) { + public void showFeedback( + String debugContext, @Nullable AssistantDetails details, String statusMessage) { HelpAndFeedback.getInstance(mActivity).showFeedback(mActivity, Profile.getLastUsedProfile(), mActivity.getActivityTab().getUrl(), FEEDBACK_CATEGORY_TAG, - FeedbackContext.buildContextString(mActivity, debugContext, - mDetailsCoordinator.getCurrentDetails(), - mHeaderCoordinator.getStatusMessage(), 4)); + FeedbackContext.buildContextString( + mActivity, debugContext, details, statusMessage, 4)); } // Implementation of methods from {@link TouchEventFilterView.Delegate}.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantModel.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantModel.java index 9c5f16d..2648ae9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantModel.java
@@ -7,6 +7,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantCarouselModel; +import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetailsModel; import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderModel; /** @@ -15,6 +16,7 @@ @JNINamespace("autofill_assistant") class AssistantModel { private final AssistantHeaderModel mHeaderModel = new AssistantHeaderModel(); + private final AssistantDetailsModel mDetailsModel = new AssistantDetailsModel(); private final AssistantCarouselModel mCarouselModel = new AssistantCarouselModel(); @CalledByNative @@ -23,6 +25,11 @@ } @CalledByNative + public AssistantDetailsModel getDetailsModel() { + return mDetailsModel; + } + + @CalledByNative public AssistantCarouselModel getCarouselModel() { return mCarouselModel; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java index b027f06f..f4837d8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
@@ -22,8 +22,6 @@ import org.chromium.payments.mojom.PaymentOptions; import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; import java.util.List; /** @@ -175,7 +173,8 @@ paymentOptions.shippingType = shippingType; mCoordinator.getBottomBarCoordinator().allowSwipingBottomSheet(false); - mCoordinator.getPaymentRequestCoordinator() + mCoordinator.getBottomBarCoordinator() + .getPaymentRequestCoordinator() .reset(paymentOptions, supportedBasicCardNetworks, defaultEmail) .then(this::onRequestPaymentInformationSuccess, this::onRequestPaymentInformationFailed); @@ -196,38 +195,6 @@ } @CalledByNative - private void onHideDetails() { - mCoordinator.getDetailsCoordinator().hideDetails(); - } - - @CalledByNative - private void onShowInitialDetails(String title, String description, String mid, String date) { - mCoordinator.getDetailsCoordinator().showInitialDetails(title, description, mid, date); - } - - @CalledByNative - private void onShowDetails(String title, String url, String description, String mId, - String price, int year, int month, int day, int hour, int minute, int second, - boolean userApprovalRequired, boolean highlightTitle, boolean highlightDate) { - Date date; - if (year > 0 && month > 0 && day > 0 && hour >= 0 && minute >= 0 && second >= 0) { - Calendar calendar = Calendar.getInstance(); - calendar.clear(); - // Month in Java Date is 0-based, but the one we receive from the server is 1-based. - calendar.set(year, month - 1, day, hour, minute, second); - date = calendar.getTime(); - } else { - date = null; - } - - if (price.length() == 0) price = null; - - mCoordinator.getDetailsCoordinator().showDetails(new AssistantDetails(title, url, date, - description, mId, price, userApprovalRequired, highlightTitle, highlightDate, - /* showPlaceholdersForEmptyFields= */ false)); - } - - @CalledByNative private void onShowOnboarding(Runnable onAccept) { mCoordinator.showOnboarding(onAccept); } @@ -238,8 +205,9 @@ } @CalledByNative - private void showFeedback(String debugContext) { - mCoordinator.showFeedback(debugContext); + private void showFeedback( + String debugContext, @Nullable AssistantDetails details, String statusMessage) { + mCoordinator.showFeedback(debugContext, details, statusMessage); } @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java index 4e2184ce..4aad5ce 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java
@@ -25,15 +25,13 @@ private static final int CHIPS_INNER_SPACING_DP = 16; private static final int CHIPS_OUTER_SPACING_DP = 24; - private final Runnable mOnVisibilityChanged; + @Nullable + private Runnable mOnVisibilityChanged; private final LinearLayoutManager mLayoutManager; private final RecyclerView mView; - public AssistantCarouselCoordinator( - Context context, AssistantCarouselModel model, Runnable onVisibilityChanged) { - mOnVisibilityChanged = onVisibilityChanged; - + public AssistantCarouselCoordinator(Context context, AssistantCarouselModel model) { mLayoutManager = new LinearLayoutManager( context, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false); mView = new RecyclerView(context); @@ -48,6 +46,9 @@ AssistantChipViewHolder::bind), AssistantChipViewHolder::create)); + // Carousel is initially hidden. + setVisible(false); + // Listen for changes on REVERSE_LAYOUT. model.addObserver((source, propertyKey) -> { if (AssistantCarouselModel.REVERSE_LAYOUT == propertyKey) { @@ -92,15 +93,25 @@ * Show or hide this carousel within its parent and call the {@code mOnVisibilityChanged} * listener. */ - public void setVisible(boolean visible) { + private void setVisible(boolean visible) { int visibility = visible ? View.VISIBLE : View.GONE; boolean changed = mView.getVisibility() != visibility; if (changed) { mView.setVisibility(visibility); - mOnVisibilityChanged.run(); + if (mOnVisibilityChanged != null) { + mOnVisibilityChanged.run(); + } } } + /** + * Set the listener that should be triggered when changing the listener of this coordinator + * view. + */ + public void setVisibilityChangedListener(Runnable listener) { + mOnVisibilityChanged = listener; + } + private class SpaceItemDecoration extends RecyclerView.ItemDecoration { private final int mInnerSpacePx; private final int mOuterSpacePx;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetails.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetails.java index 3b051645..d5e1c79 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetails.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetails.java
@@ -9,12 +9,22 @@ import org.json.JSONException; import org.json.JSONObject; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Date; +import java.util.Locale; /** * Java side equivalent of autofill_assistant::DetailsProto. */ +@JNINamespace("autofill_assistant") public class AssistantDetails { + private static final String RFC_3339_FORMAT_WITHOUT_TIMEZONE = "yyyy'-'MM'-'dd'T'HH':'mm':'ss"; + private final String mTitle; private final String mUrl; @Nullable @@ -109,11 +119,51 @@ } /** - * Clears all flags that indicate that this Details object has been changed. + * Create details with given {@code title}, {@code description}, {@code mid} and {@code date} + * (given in the RFC 3339 format). */ - public void clearChangedFlags() { - mUserApprovalRequired = false; - mHighlightTitle = false; - mHighlightDate = false; + @CalledByNative + private static AssistantDetails createInitial( + String title, String description, String mId, String dateString) { + Date date = null; + if (!dateString.isEmpty()) { + try { + // The parameter contains the timezone shift from the current location, that we + // don't care about. + date = new SimpleDateFormat(RFC_3339_FORMAT_WITHOUT_TIMEZONE, Locale.ROOT) + .parse(dateString); + } catch (ParseException e) { + // Ignore. + } + } + + return new AssistantDetails(title, /* url= */ "", date, description, mId, /* price= */ "", + /* userApprovalRequired= */ false, /* highlightTitle= */ false, + /* highlightDate= */ false, /* showPlaceholdersForEmptyFields= */ true); + } + + /** + * Create details with the given values. + */ + @CalledByNative + private static AssistantDetails create(String title, String url, String description, String mId, + String price, int year, int month, int day, int hour, int minute, int second, + boolean userApprovalRequired, boolean highlightTitle, boolean highlightDate) { + Date date; + if (year > 0 && month > 0 && day > 0 && hour >= 0 && minute >= 0 && second >= 0) { + Calendar calendar = Calendar.getInstance(); + calendar.clear(); + // Month in Java Date is 0-based, but the one we receive from the server is 1-based. + calendar.set(year, month - 1, day, hour, minute, second); + date = calendar.getTime(); + } else { + date = null; + } + + if (price.length() == 0) price = null; + + return new AssistantDetails(title, url, date, description, mId, price, userApprovalRequired, + highlightTitle, highlightDate, + /* showPlaceholdersForEmptyFields= */ false); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsCoordinator.java index 8b9f31cd..646d14c0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsCoordinator.java
@@ -4,93 +4,44 @@ package org.chromium.chrome.browser.autofill_assistant.details; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ArgbEvaluator; -import android.animation.ValueAnimator; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.GradientDrawable; -import android.media.ThumbnailUtils; -import android.os.Build; import android.support.annotation.Nullable; -import android.support.v4.graphics.drawable.RoundedBitmapDrawable; -import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; -import android.text.TextUtils; -import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; -import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.autofill_assistant.R; import org.chromium.chrome.browser.ChromeActivity; -import org.chromium.chrome.browser.cached_image_fetcher.CachedImageFetcher; -import org.chromium.chrome.browser.compositor.animation.CompositorAnimator; - -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; +import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetailsViewBinder.ViewHolder; +import org.chromium.ui.modelutil.PropertyModelChangeProcessor; /** * Coordinator responsible for showing details. */ public class AssistantDetailsCoordinator { - private static final int IMAGE_BORDER_RADIUS = 4; - private static final int PULSING_DURATION_MS = 1_000; - private static final String DETAILS_TIME_FORMAT = "H:mma"; - private static final String DETAILS_DATE_FORMAT = "EEE, MMM d"; - private static final String RFC_3339_FORMAT_WITHOUT_TIMEZONE = "yyyy'-'MM'-'dd'T'HH':'mm':'ss"; - - private final Context mContext; - private final Runnable mOnVisibilityChanged; - - private final View mView; - private final GradientDrawable mDefaultImage; - private final ImageView mImageView; - private final TextView mTitleView; - private final TextView mSubtextView; - - private final int mImageWidth; - private final int mImageHeight; - private final int mPulseAnimationStartColor; - private final int mPulseAnimationEndColor; - - private final Set<View> mViewsToAnimate = new HashSet<>(); - private ValueAnimator mPulseAnimation; - @Nullable - private AssistantDetails mCurrentDetails; + private Runnable mOnVisibilityChanged; + private final View mView; - public AssistantDetailsCoordinator(ChromeActivity activity, Runnable onVisibilityChanged) { - mContext = activity; - mOnVisibilityChanged = onVisibilityChanged; - + public AssistantDetailsCoordinator(ChromeActivity activity, AssistantDetailsModel model) { mView = LayoutInflater.from(activity).inflate( R.layout.autofill_assistant_details, /* root= */ null); + ViewHolder viewHolder = new ViewHolder(activity, mView); + AssistantDetailsViewBinder viewBinder = new AssistantDetailsViewBinder(activity); + PropertyModelChangeProcessor.create(model, viewHolder, viewBinder); - mDefaultImage = (GradientDrawable) activity.getResources().getDrawable( - R.drawable.autofill_assistant_default_details); - mImageView = mView.findViewById(R.id.details_image); - mTitleView = mView.findViewById(R.id.details_title); - mSubtextView = mView.findViewById(R.id.details_text); + // Details view is initially hidden. + setVisible(false); - mImageWidth = mContext.getResources().getDimensionPixelSize( - R.dimen.autofill_assistant_details_image_size); - mImageHeight = mContext.getResources().getDimensionPixelSize( - R.dimen.autofill_assistant_details_image_size); - mPulseAnimationStartColor = mContext.getResources().getColor(R.color.modern_grey_100); - mPulseAnimationEndColor = mContext.getResources().getColor(R.color.modern_grey_50); + // Observe details in model to hide or show this coordinator view. + model.addObserver((source, propertyKey) -> { + if (AssistantDetailsModel.DETAILS == propertyKey) { + AssistantDetails details = model.get(AssistantDetailsModel.DETAILS); + if (details != null) { + setVisible(true); + } else { + setVisible(false); + } + } + }); } /** @@ -104,230 +55,23 @@ * Show or hide the details within its parent and call the {@code mOnVisibilityChanged} * listener. */ - public void setVisible(boolean visible) { + private void setVisible(boolean visible) { int visibility = visible ? View.VISIBLE : View.GONE; boolean changed = mView.getVisibility() != visibility; if (changed) { mView.setVisibility(visibility); - mOnVisibilityChanged.run(); - } - } - - /** - * Hide the details. - */ - public void hideDetails() { - setVisible(false); - } - - /** - * Return the current details. - */ - @Nullable - public AssistantDetails getCurrentDetails() { - return mCurrentDetails; - } - - /** - * Show details with given {@code title}, {@code description}, {@code mid} and {@code date} - * (given in the RFC 3339 format). - */ - // TODO(crbug.com/806868): Move extraction to native side and call showDetails once we can parse - // details (date) natively. - public void showInitialDetails( - String title, String description, String mId, String dateString) { - Date date = null; - if (!dateString.isEmpty()) { - try { - // The parameter contains the timezone shift from the current location, that we - // don't care about. - date = new SimpleDateFormat(RFC_3339_FORMAT_WITHOUT_TIMEZONE, Locale.ROOT) - .parse(dateString); - } catch (ParseException e) { - // Ignore. + if (mOnVisibilityChanged != null) { + mOnVisibilityChanged.run(); } } - - showDetails( - new AssistantDetails(title, /* url= */ "", date, description, mId, /* price= */ "", - /* userApprovalRequired= */ false, /* highlightTitle= */ false, - /* highlightDate= */ false, /* showPlaceholdersForEmptyFields= */ true)); } /** - * Update the details. + * Set the listener that should be triggered when changing the listener of this coordinator + * view. */ - public void showDetails(AssistantDetails details) { - String detailsText = makeDetailsText(details); - mTitleView.setText(details.getTitle()); - mSubtextView.setText(detailsText); - - if (mCurrentDetails == null) { - // Set default image if no image was set before. - mImageView.setImageDrawable(mDefaultImage); - } - - setTextStyles(details); - - // Download image and then set it in the model. - if (!details.getUrl().isEmpty()) { - CachedImageFetcher.getInstance().fetchImage(details.getUrl(), image -> { - if (image != null) { - mImageView.setImageDrawable(getRoundedImage(image)); - } - }); - } - - setVisible(true); - mCurrentDetails = details; + public void setVisibilityChangedListener(Runnable listener) { + mOnVisibilityChanged = listener; } - /** - * Whether details are currently displayed. - */ - public boolean isVisible() { - return mView.getVisibility() == View.VISIBLE; - } - - private void setTextStyles(AssistantDetails details) { - setTitleStyle(details); - setSubtextStyle(details); - } - - private void setTitleStyle(AssistantDetails details) { - boolean animateBackground = false; - - if (details.getUserApprovalRequired() && !details.getHighlightTitle()) { - // De-emphasize title if user needs to accept details but the title should not be - // highlighted. - mTitleView.setTextColor(ApiCompatibilityUtils.getColor( - mContext.getResources(), R.color.modern_grey_300)); - } else { - // Normal style: bold black text. - ApiCompatibilityUtils.setTextAppearance( - mTitleView, R.style.TextAppearance_BlackCaptionDefault); - mTitleView.setTypeface(mTitleView.getTypeface(), Typeface.BOLD); - - if (mTitleView.length() == 0 && details.getShowPlaceholdersForEmptyFields()) { - animateBackground = true; - } - } - - if (animateBackground) { - addViewToAnimation(mTitleView); - } else { - removeViewFromAnimation(mTitleView); - } - } - - private void setSubtextStyle(AssistantDetails details) { - boolean animateBackground = false; - - if (details.getUserApprovalRequired()) { - if (details.getHighlightDate()) { - // Emphasized style. - mSubtextView.setTypeface(mSubtextView.getTypeface(), Typeface.BOLD_ITALIC); - } else { - // De-emphasized style. - mSubtextView.setTextColor(ApiCompatibilityUtils.getColor( - mContext.getResources(), R.color.modern_grey_300)); - } - } else { - // Normal style. - ApiCompatibilityUtils.setTextAppearance( - mSubtextView, R.style.TextAppearance_BlackCaption); - - if (mSubtextView.length() == 0 && details.getShowPlaceholdersForEmptyFields()) { - animateBackground = true; - } - } - - if (animateBackground) { - addViewToAnimation(mSubtextView); - } else { - removeViewFromAnimation(mSubtextView); - } - } - - private String makeDetailsText(AssistantDetails details) { - List<String> parts = new ArrayList<>(); - Date date = details.getDate(); - if (date != null) { - parts.add(formatDetailsTime(date)); - parts.add(formatDetailsDate(date)); - } - - String description = details.getDescription(); - if (description != null && !description.isEmpty()) { - parts.add(description); - } - - // TODO(crbug.com/806868): Use a view instead of this dot text. - return TextUtils.join(" • ", parts); - } - - private Locale getLocale() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N - ? mContext.getResources().getConfiguration().getLocales().get(0) - : mContext.getResources().getConfiguration().locale; - } - - private String formatDetailsTime(Date date) { - DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()); - String timeFormatPattern = (df instanceof SimpleDateFormat) - ? ((SimpleDateFormat) df).toPattern() - : DETAILS_TIME_FORMAT; - return new SimpleDateFormat(timeFormatPattern, getLocale()).format(date); - } - - private String formatDetailsDate(Date date) { - return new SimpleDateFormat(DETAILS_DATE_FORMAT, getLocale()).format(date); - } - - private Drawable getRoundedImage(Bitmap bitmap) { - RoundedBitmapDrawable roundedBitmap = - RoundedBitmapDrawableFactory.create(mContext.getResources(), - ThumbnailUtils.extractThumbnail(bitmap, mImageWidth, mImageHeight)); - roundedBitmap.setCornerRadius(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, - IMAGE_BORDER_RADIUS, mContext.getResources().getDisplayMetrics())); - return roundedBitmap; - } - - private void addViewToAnimation(View view) { - if (mViewsToAnimate.add(view) && mPulseAnimation == null) { - mPulseAnimation = - ValueAnimator.ofInt(mPulseAnimationStartColor, mPulseAnimationEndColor); - mPulseAnimation.setDuration(PULSING_DURATION_MS); - mPulseAnimation.setEvaluator(new ArgbEvaluator()); - mPulseAnimation.setRepeatCount(ValueAnimator.INFINITE); - mPulseAnimation.setRepeatMode(ValueAnimator.REVERSE); - mPulseAnimation.setInterpolator(CompositorAnimator.ACCELERATE_INTERPOLATOR); - mPulseAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationCancel(Animator animation) { - mTitleView.setBackgroundColor(Color.WHITE); - mSubtextView.setBackgroundColor(Color.WHITE); - mDefaultImage.setColor(mPulseAnimationStartColor); - } - }); - mPulseAnimation.addUpdateListener(animation -> { - int animatedValue = (int) animation.getAnimatedValue(); - for (View viewToAnimate : mViewsToAnimate) { - viewToAnimate.setBackgroundColor(animatedValue); - } - mDefaultImage.setColor(animatedValue); - }); - mPulseAnimation.start(); - } - } - - private void removeViewFromAnimation(View view) { - if (mViewsToAnimate.remove(view) && mPulseAnimation != null) { - mPulseAnimation.cancel(); - mPulseAnimation = null; - } - - // Reset background to white. - view.setBackgroundColor(Color.WHITE); - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsModel.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsModel.java new file mode 100644 index 0000000..0ca9deb --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsModel.java
@@ -0,0 +1,45 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.autofill_assistant.details; + +import android.support.annotation.Nullable; + +import org.chromium.base.VisibleForTesting; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; +import org.chromium.ui.modelutil.PropertyModel; + +/** + * State for the details of the Autofill Assistant. + */ +@JNINamespace("autofill_assistant") +public class AssistantDetailsModel extends PropertyModel { + // TODO(crbug.com/806868): We might want to split this property into multiple, simpler + // properties. + @VisibleForTesting + public static final WritableObjectPropertyKey<AssistantDetails> DETAILS = + new WritableObjectPropertyKey<>(); + + public AssistantDetailsModel() { + super(DETAILS); + } + + @CalledByNative + private void setDetails(AssistantDetails details) { + set(DETAILS, details); + } + + @CalledByNative + // TODO(crbug.com/806868): Make private once this is only called by native. + public void clearDetails() { + set(DETAILS, null); + } + + @CalledByNative + @Nullable + private AssistantDetails getDetails() { + return get(DETAILS); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsViewBinder.java new file mode 100644 index 0000000..d7d773b8 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsViewBinder.java
@@ -0,0 +1,273 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.autofill_assistant.details; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ArgbEvaluator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.media.ThumbnailUtils; +import android.os.Build; +import android.support.v4.graphics.drawable.RoundedBitmapDrawable; +import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.chrome.autofill_assistant.R; +import org.chromium.chrome.browser.cached_image_fetcher.CachedImageFetcher; +import org.chromium.chrome.browser.compositor.animation.CompositorAnimator; +import org.chromium.ui.modelutil.PropertyKey; +import org.chromium.ui.modelutil.PropertyModelChangeProcessor; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +/** + * This class is responsible for pushing updates to the Autofill Assistant details view. These + * updates are pulled from the {@link AssistantDetailsModel} when a notification of an update is + * received. + */ +class AssistantDetailsViewBinder + implements PropertyModelChangeProcessor.ViewBinder<AssistantDetailsModel, + AssistantDetailsViewBinder.ViewHolder, PropertyKey> { + private static final int IMAGE_BORDER_RADIUS = 4; + private static final int PULSING_DURATION_MS = 1_000; + private static final String DETAILS_TIME_FORMAT = "H:mma"; + private static final String DETAILS_DATE_FORMAT = "EEE, MMM d"; + + /** + * A wrapper class that holds the different views of the header. + */ + static class ViewHolder { + final GradientDrawable mDefaultImage; + final ImageView mImageView; + final TextView mTitleView; + final TextView mSubtextView; + + public ViewHolder(Context context, View detailsView) { + mDefaultImage = (GradientDrawable) context.getResources().getDrawable( + R.drawable.autofill_assistant_default_details); + mImageView = detailsView.findViewById(R.id.details_image); + mTitleView = detailsView.findViewById(R.id.details_title); + mSubtextView = detailsView.findViewById(R.id.details_text); + } + } + + private final Context mContext; + + private final int mImageWidth; + private final int mImageHeight; + private final int mPulseAnimationStartColor; + private final int mPulseAnimationEndColor; + + private final Set<View> mViewsToAnimate = new HashSet<>(); + private ValueAnimator mPulseAnimation; + + AssistantDetailsViewBinder(Context context) { + mContext = context; + mImageWidth = context.getResources().getDimensionPixelSize( + R.dimen.autofill_assistant_details_image_size); + mImageHeight = context.getResources().getDimensionPixelSize( + R.dimen.autofill_assistant_details_image_size); + mPulseAnimationStartColor = context.getResources().getColor(R.color.modern_grey_100); + mPulseAnimationEndColor = context.getResources().getColor(R.color.modern_grey_50); + } + + @Override + public void bind(AssistantDetailsModel model, ViewHolder view, PropertyKey propertyKey) { + if (AssistantDetailsModel.DETAILS == propertyKey) { + AssistantDetails details = model.get(AssistantDetailsModel.DETAILS); + if (details == null) { + // Handled by the AssistantDetailsCoordinator. + return; + } + + setDetails(details, view); + } else { + assert false : "Unhandled property detected in AssistantDetailsViewBinder!"; + } + } + + private void setDetails(AssistantDetails details, ViewHolder viewHolder) { + String detailsText = makeDetailsText(details); + viewHolder.mTitleView.setText(details.getTitle()); + viewHolder.mSubtextView.setText(detailsText); + + if (viewHolder.mImageView.getDrawable() == null) { + // Set default image if no image was set before. + viewHolder.mImageView.setImageDrawable(viewHolder.mDefaultImage); + } + + setTextStyles(details, viewHolder); + + // Download image and then set it in the model. + if (!details.getUrl().isEmpty()) { + CachedImageFetcher.getInstance().fetchImage(details.getUrl(), image -> { + if (image != null) { + viewHolder.mImageView.setImageDrawable(getRoundedImage(image)); + } + }); + } + } + + private void setTextStyles(AssistantDetails details, ViewHolder viewHolder) { + setTitleStyle(details, viewHolder); + setSubtextStyle(details, viewHolder); + } + + private void setTitleStyle(AssistantDetails details, ViewHolder viewHolder) { + boolean animateBackground = false; + TextView titleView = viewHolder.mTitleView; + + if (details.getUserApprovalRequired() && !details.getHighlightTitle()) { + // De-emphasize title if user needs to accept details but the title should not be + // highlighted. + titleView.setTextColor(ApiCompatibilityUtils.getColor( + mContext.getResources(), R.color.modern_grey_300)); + } else { + // Normal style: bold black text. + ApiCompatibilityUtils.setTextAppearance( + titleView, R.style.TextAppearance_BlackCaptionDefault); + titleView.setTypeface(titleView.getTypeface(), Typeface.BOLD); + + if (titleView.length() == 0 && details.getShowPlaceholdersForEmptyFields()) { + animateBackground = true; + } + } + + if (animateBackground) { + addViewToAnimation(titleView, viewHolder); + } else { + removeViewFromAnimation(titleView); + } + } + + private void setSubtextStyle(AssistantDetails details, ViewHolder viewHolder) { + boolean animateBackground = false; + TextView subtextView = viewHolder.mSubtextView; + + if (details.getUserApprovalRequired()) { + if (details.getHighlightDate()) { + // Emphasized style. + subtextView.setTypeface(subtextView.getTypeface(), Typeface.BOLD_ITALIC); + } else { + // De-emphasized style. + subtextView.setTextColor(ApiCompatibilityUtils.getColor( + mContext.getResources(), R.color.modern_grey_300)); + } + } else { + // Normal style. + ApiCompatibilityUtils.setTextAppearance( + subtextView, R.style.TextAppearance_BlackCaption); + + if (subtextView.length() == 0 && details.getShowPlaceholdersForEmptyFields()) { + animateBackground = true; + } + } + + if (animateBackground) { + addViewToAnimation(subtextView, viewHolder); + } else { + removeViewFromAnimation(subtextView); + } + } + + private String makeDetailsText(AssistantDetails details) { + List<String> parts = new ArrayList<>(); + Date date = details.getDate(); + if (date != null) { + parts.add(formatDetailsTime(date)); + parts.add(formatDetailsDate(date)); + } + + String description = details.getDescription(); + if (description != null && !description.isEmpty()) { + parts.add(description); + } + + // TODO(crbug.com/806868): Use a view instead of this dot text. + return TextUtils.join(" • ", parts); + } + + private Locale getLocale() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N + ? mContext.getResources().getConfiguration().getLocales().get(0) + : mContext.getResources().getConfiguration().locale; + } + + private String formatDetailsTime(Date date) { + DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()); + String timeFormatPattern = (df instanceof SimpleDateFormat) + ? ((SimpleDateFormat) df).toPattern() + : DETAILS_TIME_FORMAT; + return new SimpleDateFormat(timeFormatPattern, getLocale()).format(date); + } + + private String formatDetailsDate(Date date) { + return new SimpleDateFormat(DETAILS_DATE_FORMAT, getLocale()).format(date); + } + + private Drawable getRoundedImage(Bitmap bitmap) { + RoundedBitmapDrawable roundedBitmap = + RoundedBitmapDrawableFactory.create(mContext.getResources(), + ThumbnailUtils.extractThumbnail(bitmap, mImageWidth, mImageHeight)); + roundedBitmap.setCornerRadius(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + IMAGE_BORDER_RADIUS, mContext.getResources().getDisplayMetrics())); + return roundedBitmap; + } + + private void addViewToAnimation(View view, ViewHolder viewHolder) { + mViewsToAnimate.add(view); + if (mPulseAnimation == null) { + mPulseAnimation = + ValueAnimator.ofInt(mPulseAnimationStartColor, mPulseAnimationEndColor); + mPulseAnimation.setDuration(PULSING_DURATION_MS); + mPulseAnimation.setEvaluator(new ArgbEvaluator()); + mPulseAnimation.setRepeatCount(ValueAnimator.INFINITE); + mPulseAnimation.setRepeatMode(ValueAnimator.REVERSE); + mPulseAnimation.setInterpolator(CompositorAnimator.ACCELERATE_INTERPOLATOR); + mPulseAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + viewHolder.mTitleView.setBackgroundColor(Color.WHITE); + viewHolder.mSubtextView.setBackgroundColor(Color.WHITE); + viewHolder.mDefaultImage.setColor(mPulseAnimationStartColor); + } + }); + mPulseAnimation.addUpdateListener(animation -> { + int animatedValue = (int) animation.getAnimatedValue(); + for (View viewToAnimate : mViewsToAnimate) { + viewToAnimate.setBackgroundColor(animatedValue); + } + viewHolder.mDefaultImage.setColor(animatedValue); + }); + mPulseAnimation.start(); + } + } + + private void removeViewFromAnimation(View view) { + mViewsToAnimate.remove(view); + if (mViewsToAnimate.isEmpty() && mPulseAnimation != null) { + mPulseAnimation.cancel(); + mPulseAnimation = null; + } + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java index 884459f3..86c521986 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java
@@ -13,45 +13,11 @@ * Coordinator for the header of the Autofill Assistant. */ public class AssistantHeaderCoordinator { - private final AssistantHeaderMediator mMediator; - public AssistantHeaderCoordinator(Context context, View root, AssistantHeaderModel model) { // Bind view and mediator through the model. AssistantHeaderViewBinder.ViewHolder viewHolder = new AssistantHeaderViewBinder.ViewHolder(context, root); AssistantHeaderViewBinder viewBinder = new AssistantHeaderViewBinder(); PropertyModelChangeProcessor.create(model, viewHolder, viewBinder); - mMediator = new AssistantHeaderMediator(model); - } - - // TODO(crbug.com/806868): Remove all methods here and delete mediator once UI is modified only - // in native side. - - /** - * Get the current status message. - */ - public String getStatusMessage() { - return mMediator.getCurrentStatusMessage(); - } - - /** - * Set the status message. - */ - public void setStatusMessage(String message) { - mMediator.setStatusMessage(message); - } - - /** - * Show or hide the feedback button. - */ - public void setFeedbackButtonVisible(boolean visible) { - mMediator.setFeedbackButtonVisible(visible); - } - - /** - * Show or hide the close button. - */ - public void setCloseButtonVisible(boolean visible) { - mMediator.setCloseButtonVisible(visible); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderMediator.java deleted file mode 100644 index 4d3f951..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderMediator.java +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.autofill_assistant.header; - -/** - * Mediator that updates the model for the Autofill Assistant header. - */ -class AssistantHeaderMediator { - private final AssistantHeaderModel mModel; - - AssistantHeaderMediator(AssistantHeaderModel model) { - mModel = model; - } - - String getCurrentStatusMessage() { - return mModel.get(AssistantHeaderModel.STATUS_MESSAGE); - } - - void setStatusMessage(String message) { - if (message != null && !message.isEmpty()) { - mModel.set(AssistantHeaderModel.STATUS_MESSAGE, message); - } - } - - void setFeedbackButtonVisible(boolean visible) { - mModel.set(AssistantHeaderModel.FEEDBACK_VISIBLE, visible); - } - - void setCloseButtonVisible(boolean visible) { - mModel.set(AssistantHeaderModel.CLOSE_VISIBLE, visible); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderModel.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderModel.java index 7005863..c083a1ac 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderModel.java
@@ -14,12 +14,18 @@ */ @JNINamespace("autofill_assistant") public class AssistantHeaderModel extends PropertyModel { - static final WritableObjectPropertyKey<String> STATUS_MESSAGE = + @VisibleForTesting + public static final WritableObjectPropertyKey<String> STATUS_MESSAGE = new WritableObjectPropertyKey<>(); - static final WritableBooleanPropertyKey FEEDBACK_VISIBLE = new WritableBooleanPropertyKey(); + // TODO(crbug.com/806868): Change visibility to package-private once this is only set through + // native calls. + public static final WritableBooleanPropertyKey FEEDBACK_VISIBLE = + new WritableBooleanPropertyKey(); - static final WritableBooleanPropertyKey CLOSE_VISIBLE = new WritableBooleanPropertyKey(); + // TODO(crbug.com/806868): Change visibility to package-private once this is only set through + // native calls. + public static final WritableBooleanPropertyKey CLOSE_VISIBLE = new WritableBooleanPropertyKey(); static final WritableIntPropertyKey PROGRESS = new WritableIntPropertyKey();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java index d701ed5..c7b5682 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.autofill_assistant.payment; +import android.support.annotation.Nullable; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; @@ -21,19 +22,21 @@ */ public class AssistantPaymentRequestCoordinator { private final WebContents mWebContents; - private final Runnable mOnVisibilityChanged; + @Nullable + private Runnable mOnVisibilityChanged; private final ViewGroup mView; private Promise<SelectedPaymentInformation> mCurrentPromise; - public AssistantPaymentRequestCoordinator( - ChromeActivity activity, Runnable onVisibilityChanged) { + public AssistantPaymentRequestCoordinator(ChromeActivity activity) { mWebContents = activity.getCurrentWebContents(); - mOnVisibilityChanged = onVisibilityChanged; // TODO(crbug.com/806868): Remove this. mView = new LinearLayout(activity); mView.addView(new View(activity)); + + // Payment request is initially hidden. + setVisible(false); } public View getView() { @@ -45,10 +48,20 @@ boolean changed = mView.getVisibility() != visibility; if (changed) { mView.setVisibility(visibility); - mOnVisibilityChanged.run(); + if (mOnVisibilityChanged != null) { + mOnVisibilityChanged.run(); + } } } + /** + * Set the listener that should be triggered when changing the listener of this coordinator + * view. + */ + public void setVisibilityChangedListener(Runnable listener) { + mOnVisibilityChanged = listener; + } + public Promise<SelectedPaymentInformation> reset( PaymentOptions options, String[] supportedBasicCardNetworks, String defaultEmail) { assert mCurrentPromise
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java index f376bf48..7224f913 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java
@@ -40,7 +40,12 @@ getTopBarView().addView(mTopBarContentView); } if (mTopBarContentView != null) { - mTopBarContentView.setVisibility(isVisible ? View.VISIBLE : View.GONE); + if (mTopBarHeight != null && mTopBarHeight == 0) { + // Hide the top bar when its height is specifically set to 0. + mTopBarContentView.setVisibility(View.GONE); + } else { + mTopBarContentView.setVisibility(isVisible ? View.VISIBLE : View.GONE); + } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java index 5409614..4cb79bd4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -56,6 +56,7 @@ import org.chromium.chrome.browser.browserservices.Origin; import org.chromium.chrome.browser.browserservices.PostMessageHandler; import org.chromium.chrome.browser.customtabs.dynamicmodule.ModuleLoader; +import org.chromium.chrome.browser.customtabs.dynamicmodule.ModuleMetrics; import org.chromium.chrome.browser.device.DeviceClassManager; import org.chromium.chrome.browser.init.ChainedTasks; import org.chromium.chrome.browser.init.ChromeBrowserInitializer; @@ -1455,17 +1456,15 @@ resourceId = 0; } + if (mModuleLoader != null && + (!componentName.equals(mModuleLoader.getComponentName()) || + resourceId != mModuleLoader.getDexResourceId())) { + mModuleLoader.destroyModule(ModuleMetrics.DestructionReason.MODULE_LOADER_CHANGED); + mModuleLoader = null; + } + if (mModuleLoader == null) mModuleLoader = new ModuleLoader(componentName, resourceId); - if (!componentName.equals(mModuleLoader.getComponentName())) { - throw new IllegalStateException("The given component name " + componentName - + " does not match the initialized component name " - + mModuleLoader.getComponentName()); - } - if (resourceId != mModuleLoader.getDexResourceId()) { - throw new IllegalStateException("The given resource ID " + resourceId - + " does not match the initialized resource ID " - + mModuleLoader.getDexResourceId()); - } + return mModuleLoader; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityDelegate.java index dd2db69c..d959ed16 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityDelegate.java
@@ -171,6 +171,12 @@ safeRun(() -> mActivityDelegate.onNavigationEvent(navigationEvent, extras)); } + public void onPageMetricEvent(String metricName, long navigationStart, + long offset, long navigationId) { + safeRun(() -> mActivityDelegate.onPageMetricEvent( + metricName, navigationStart, offset, navigationId)); + } + public void onMessageChannelReady() { safeRun(mActivityDelegate::onMessageChannelReady); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleConstants.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleConstants.java index b42ae10..1e3a141 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleConstants.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleConstants.java
@@ -14,12 +14,17 @@ public static final String MANAGED_URL_HEADER = "X-CCT-Client-Data"; /** + * The module version when {@link IActivityDelegate#onBackPressedAsync} is introduced. + */ + public static final int ON_BACK_PRESSED_ASYNC_API_VERSION = 2; + + /** * The module version when {@link IActivityDelegate#onNavigationEvent} is introduced. */ public static final int ON_NAVIGATION_EVENT_MODULE_API_VERSION = 4; /** - * The module version when {@link IActivityDelegate#onBackPressedAsync} is introduced. + * The module version when {@link IActivityDelegate#onPageMetricEvent} is introduced. */ - public static final int ON_BACK_PRESSED_ASYNC_API_VERSION = 2; + public static final int ON_PAGE_LOAD_METRIC_API_VERSION = 10; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleCoordinator.java index 239fef7..39f1860 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleCoordinator.java
@@ -38,6 +38,7 @@ import org.chromium.chrome.browser.init.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.Destroyable; import org.chromium.chrome.browser.lifecycle.NativeInitObserver; +import org.chromium.chrome.browser.metrics.PageLoadMetrics; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabObserver; @@ -156,6 +157,7 @@ private final DynamicModuleNavigationEventObserver mModuleNavigationEventObserver = new DynamicModuleNavigationEventObserver(); + private final DynamicModulePageLoadObserver mPageLoadObserver; @Inject public DynamicModuleCoordinator(CustomTabIntentDataProvider intentDataProvider, @@ -167,7 +169,8 @@ Lazy<CustomTabBottomBarDelegate> bottomBarDelegate, Lazy<ChromeFullscreenManager> fullscreenManager, CustomTabsConnection connection, ChromeActivity activity, - CustomTabActivityTabController tabController) { + CustomTabActivityTabController tabController, + DynamicModulePageLoadObserver pageLoadObserver) { mIntentDataProvider = intentDataProvider; mTabObserverRegistrar = tabObserverRegistrar; mActivity = activity; @@ -178,6 +181,9 @@ mTabObserverRegistrar.registerTabObserver(mHeaderVisibilityObserver); mTabObserverRegistrar.registerTabObserver(mCustomRequestHeaderModifier); + mPageLoadObserver = pageLoadObserver; + mTabObserverRegistrar.registerPageLoadMetricsObserver(mPageLoadObserver); + mActivityDelegate = activityDelegate; mTopBarDelegate = topBarDelegate; mBottomBarDelegate = bottomBarDelegate; @@ -357,6 +363,13 @@ unregisterObserver(mModuleNavigationEventObserver); } + if (mModuleEntryPoint.getModuleVersion() + >= DynamicModuleConstants.ON_PAGE_LOAD_METRIC_API_VERSION) { + mPageLoadObserver.setActivityDelegate(mActivityDelegate); + } else { + PageLoadMetrics.removeObserver(mPageLoadObserver); + } + // Initialise the PostMessageHandler for the current web contents. maybeInitialiseDynamicModulePostMessageHandler( @@ -400,15 +413,22 @@ public void setTopBarHeight(int height) { mTopBarDelegate.get().setTopBarHeight(height); - maybeCustomizeCctHeader(mIntentDataProvider.getUrlToLoad()); + maybeCustomizeCctHeader(getContentUrl()); + } + + private String getContentUrl() { + Tab tab = mTabController.getTab(); + if (tab != null && tab.getWebContents() != null && !tab.getWebContents().isDestroyed() + && tab.getWebContents().getLastCommittedUrl() != null) { + return tab.getWebContents().getLastCommittedUrl(); + } + return mIntentDataProvider.getUrlToLoad(); } private int getTopBarHeight() { Integer topBarHeight = mTopBarDelegate.get().getTopBarHeight(); - // Custom top bar height must not be too small compared to the default top control container - // height, nor shall it be larger than the height of the web content. + // Custom top bar height must not be larger than the height of the web content. if (topBarHeight != null && topBarHeight >= 0 - && topBarHeight > mDefaultTopControlContainerHeight / 2 && mActivity.getWindow() != null && topBarHeight < mActivity.getWindow().getDecorView().getHeight() / 2) { return topBarHeight; @@ -428,6 +448,19 @@ mIntentDataProvider.getSession()); } + private View getProgressBarAnchorView(boolean isModuleManagedUrl) { + View anchorView = null; + if (isModuleManagedUrl) { + View topBarContentView = mTopBarDelegate.get().getTopBarContentView(); + if (topBarContentView != null && topBarContentView.getVisibility() == View.VISIBLE) { + anchorView = topBarContentView; + } + } else { + anchorView = mActivity.getToolbarManager().getToolbarView(); + } + return anchorView; + } + private void maybeCustomizeCctHeader(String url) { if (!isModuleLoaded() && !isModuleLoading()) return; @@ -440,9 +473,8 @@ isModuleManagedUrl ? View.GONE : mDefaultToolbarShadowVisibility); mFullscreenManager.get().setTopControlsHeight( isModuleManagedUrl ? getTopBarHeight() : mDefaultTopControlContainerHeight); - mActivity.getToolbarManager().setProgressBarAnchorView(isModuleManagedUrl - ? mTopBarDelegate.get().getTopBarContentView() - : mActivity.getToolbarManager().getToolbarView()); + mActivity.getToolbarManager().setProgressBarAnchorView( + getProgressBarAnchorView(isModuleManagedUrl)); } } @@ -450,6 +482,7 @@ unregisterObserver(mModuleNavigationEventObserver); unregisterObserver(mHeaderVisibilityObserver); unregisterObserver(mCustomRequestHeaderModifier); + PageLoadMetrics.removeObserver(mPageLoadObserver); } private void unregisterObserver(TabObserver observer) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModulePageLoadObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModulePageLoadObserver.java new file mode 100644 index 0000000..b9b7abbc --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModulePageLoadObserver.java
@@ -0,0 +1,101 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.customtabs.dynamicmodule; + +import android.os.SystemClock; +import android.support.annotation.Nullable; + +import org.chromium.base.TimeUtils; +import org.chromium.chrome.browser.ActivityTabProvider; +import org.chromium.chrome.browser.metrics.PageLoadMetrics; +import org.chromium.content_public.browser.WebContents; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +/** + * Class to notify a CCT dynamic module of page load metrics. + */ +public class DynamicModulePageLoadObserver implements PageLoadMetrics.Observer { + @Nullable + private ActivityDelegate mActivityDelegate; + private ActivityTabProvider mActivityTabProvider; + + // SystemClock.uptimeMillis() is used here as it (as of June 2017) uses the same system call + // as all the native side of Chrome, that is clock_gettime(CLOCK_MONOTONIC). Meaning that + // the offset relative to navigationStart is to be compared with a + // SystemClock.uptimeMillis() value. + private long mNativeTickOffsetUs; + private final List<PageMetric> mPageMetricEvents = new ArrayList<>(); + + private static class PageMetric { + final String mMetricName; + final long mNavigationStart; + final long mOffset; + final long mNavigationId; + + private PageMetric(String metricName, long navigationStart, long offset, + long navigationId) { + mMetricName = metricName; + mNavigationStart = navigationStart; + mOffset = offset; + mNavigationId = navigationId; + } + } + + @Inject + public DynamicModulePageLoadObserver(ActivityTabProvider activityTabProvider) { + mActivityTabProvider = activityTabProvider; + + long nativeNowUs = TimeUtils.nativeGetTimeTicksNowUs(); + long javaNowUs = SystemClock.uptimeMillis() * 1000; + mNativeTickOffsetUs = nativeNowUs - javaNowUs; + } + + /** + * Set ActivityDelegate which will be notified on page load events. + */ + public void setActivityDelegate(ActivityDelegate activityDelegate) { + assert activityDelegate != null && mActivityDelegate == null; + mActivityDelegate = activityDelegate; + for (PageMetric metric: mPageMetricEvents) { + mActivityDelegate.onPageMetricEvent(metric.mMetricName, metric.mNavigationStart, + metric.mOffset, metric.mNavigationId); + } + mPageMetricEvents.clear(); + } + + @Override + public void onFirstContentfulPaint(WebContents webContents, long navigationId, + long navigationStartTick, long firstContentfulPaintMs) { + notifyOnPageMetricEvent(webContents, + PageLoadMetrics.FIRST_CONTENTFUL_PAINT, + navigationStartTick, firstContentfulPaintMs, navigationId); + } + + @Override + public void onLoadEventStart(WebContents webContents, long navigationId, + long navigationStartTick, long loadEventStartMs) { + notifyOnPageMetricEvent(webContents, + PageLoadMetrics.LOAD_EVENT_START, + navigationStartTick, loadEventStartMs, navigationId); + } + + private void notifyOnPageMetricEvent(WebContents webContents, + String metricName, long navigationStartTick, long offset, long navigationId) { + if (webContents != mActivityTabProvider.getActivityTab().getWebContents()) return; + long navigationStartMs = (navigationStartTick - mNativeTickOffsetUs) / 1000; + + if (mActivityDelegate == null) { + mPageMetricEvents.add( + new PageMetric(metricName, navigationStartMs, offset, navigationId)); + return; + } + + mActivityDelegate.onPageMetricEvent(metricName, navigationStartMs, offset, navigationId); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleLoader.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleLoader.java index 5eaf086a9..ff5787da 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleLoader.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleLoader.java
@@ -232,7 +232,7 @@ return ModuleMetrics.now() - mModuleUnusedTimeMs > limit; } - private void destroyModule(@DestructionReason int reason) { + public void destroyModule(@DestructionReason int reason) { assert mModuleEntryPoint != null; ModuleMetrics.recordDestruction(reason);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleMetrics.java index 2d62582..cb2e042 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleMetrics.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleMetrics.java
@@ -79,12 +79,13 @@ /** * Possible reasons for destroying a dynamic module. Keep in sync with the - * CustomTabs.DynamicModule.DestructionReason enum in histograms.xml. Do not remove - * or change existing values other than NUM_ENTRIES. + * CustomTabs.DynamicModule.DestructionReason enum in tools/metrics/histograms/enums.xml. + * Do not remove or change existing values other than NUM_ENTRIES. */ @IntDef({DestructionReason.NO_CACHING_UNUSED, DestructionReason.CACHED_SEVERE_MEMORY_PRESSURE, DestructionReason.CACHED_MILD_MEMORY_PRESSURE_TIME_EXCEEDED, - DestructionReason.CACHED_UI_HIDDEN_TIME_EXCEEDED}) + DestructionReason.CACHED_UI_HIDDEN_TIME_EXCEEDED, + DestructionReason.MODULE_LOADER_CHANGED}) @Retention(RetentionPolicy.SOURCE) public @interface DestructionReason { /** No caching enabled and the module is unused. */ @@ -95,8 +96,10 @@ int CACHED_MILD_MEMORY_PRESSURE_TIME_EXCEEDED = 2; /** Cached and app hidden and time exceeded. */ int CACHED_UI_HIDDEN_TIME_EXCEEDED = 3; + /** Module loader setup is changed. */ + int MODULE_LOADER_CHANGED = 4; /** Upper bound for legal sample values - all sample values have to be strictly lower. */ - int NUM_ENTRIES = 4; + int NUM_ENTRIES = 5; } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java index 258cbb1..98d60622 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
@@ -422,7 +422,8 @@ if (mControlsPosition == ControlsPosition.NONE) return; if (getTopControlsHeight() == 0) { - mControlOffsetRatio = 0; + // Treat the case of 0 height as controls being totally offscreen. + mControlOffsetRatio = 1.0f; } else { mControlOffsetRatio = Math.abs((float) mRendererTopControlOffset / getTopControlsHeight());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/SideSlideLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/SideSlideLayout.java index 6d70fc8..2697a55b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/SideSlideLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/SideSlideLayout.java
@@ -88,7 +88,7 @@ private boolean mNavigating; private int mCurrentTargetOffset; - private float mTotalMotionY; + private float mTotalMotion; // Whether or not the starting offset has been determined. private boolean mOriginalOffsetCalculated; @@ -134,9 +134,9 @@ public void applyTransformation(float interpolatedTime, Transformation t) { int targetTop = mFrom + (int) ((mOriginalOffset - mFrom) * interpolatedTime); int offset = targetTop - mCircleView.getLeft(); - mTotalMotionY += offset; + mTotalMotion += offset; - float progress = Math.min(1.f, Math.abs(mTotalMotionY) / mTotalDragDistance); + float progress = Math.min(1.f, getOverscroll() / mTotalDragDistance); mCircleView.setProgress(progress); setTargetOffsetLeftAndRight(offset); } @@ -197,6 +197,10 @@ } } + private float getOverscroll() { + return mIsForward ? -Math.min(0, mTotalMotion) : Math.max(0, mTotalMotion); + } + private void startScaleDownAnimation(AnimationListener listener) { if (mScaleDownAnimation == null) { mScaleDownAnimation = new Animation() { @@ -257,7 +261,7 @@ public boolean start() { if (!isEnabled() || mNavigating || mListener == null) return false; mCircleView.clearAnimation(); - mTotalMotionY = 0; + mTotalMotion = 0; mIsBeingDragged = true; mArrow.setAlpha(STARTING_ALPHA); mArrow.setDirection(mIsForward); @@ -275,10 +279,10 @@ float maxDelta = mTotalDragDistance / MIN_PULLS_TO_ACTIVATE; delta = Math.max(-maxDelta, Math.min(maxDelta, delta)); - mTotalMotionY += delta; + mTotalMotion += delta; - float overscroll = mTotalMotionY; - float extraOs = Math.abs(overscroll) - mTotalDragDistance; + float overscroll = getOverscroll(); + float extraOs = overscroll - mTotalDragDistance; float slingshotDist = mTotalDragDistance; float tensionSlingshotPercent = Math.max(0, Math.min(extraOs, slingshotDist * 2) / slingshotDist); @@ -290,7 +294,7 @@ mCircleView.setScaleX(1f); mCircleView.setScaleY(1f); - float originalDragPercent = Math.abs(overscroll) / mTotalDragDistance; + float originalDragPercent = overscroll / mTotalDragDistance; float dragPercent = Math.min(1f, Math.abs(originalDragPercent)); float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3; mArrow.setArrowScale(Math.min(1f, adjustedPercent)); @@ -321,8 +325,7 @@ // See ACTION_UP handling in {@link #onTouchEvent(...)}. mIsBeingDragged = false; - final float overscroll = Math.abs(mTotalMotionY); - if (isEnabled() && allowNav && overscroll > mTotalDragDistance) { + if (isEnabled() && allowNav && getOverscroll() > mTotalDragDistance) { setNavigating(true); return; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChromeNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChromeNotificationBuilder.java index a75413c..ea63751 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChromeNotificationBuilder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChromeNotificationBuilder.java
@@ -47,10 +47,18 @@ ChromeNotificationBuilder setShowWhen(boolean showWhen); + @Deprecated ChromeNotificationBuilder addAction(int icon, CharSequence title, PendingIntent intent); + ChromeNotificationBuilder addAction(int icon, CharSequence title, PendingIntentProvider intent, + @NotificationUmaTracker.ActionType int actionType); + + @Deprecated ChromeNotificationBuilder addAction(Notification.Action action); + ChromeNotificationBuilder addAction(Notification.Action action, int flags, + @NotificationUmaTracker.ActionType int actionType); + @Deprecated ChromeNotificationBuilder setDeleteIntent(PendingIntent intent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilder.java index bc473d10..df09a54 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilder.java
@@ -163,6 +163,18 @@ } @Override + public ChromeNotificationBuilder addAction(int icon, CharSequence title, + PendingIntentProvider pendingIntentProvider, + @NotificationUmaTracker.ActionType int actionType) { + assert (mMetadata != null); + PendingIntent pendingIntent = NotificationIntentInterceptor.createInterceptPendingIntent( + NotificationIntentInterceptor.IntentType.ACTION_INTENT, actionType, mMetadata, + pendingIntentProvider); + addAction(icon, title, pendingIntent); + return this; + } + + @Override public ChromeNotificationBuilder addAction(Notification.Action action) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { mBuilder.addAction(action); @@ -171,6 +183,21 @@ } @Override + public ChromeNotificationBuilder addAction(Notification.Action action, int flags, + @NotificationUmaTracker.ActionType int actionType) { + assert (mMetadata != null); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { + PendingIntent pendingIntent = + NotificationIntentInterceptor.createInterceptPendingIntent( + NotificationIntentInterceptor.IntentType.ACTION_INTENT, actionType, + mMetadata, new PendingIntentProvider(action.actionIntent, flags)); + action.actionIntent = pendingIntent; + addAction(action); + } + return this; + } + + @Override public ChromeNotificationBuilder setDeleteIntent(PendingIntent intent) { mBuilder.setDeleteIntent(intent); return this;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java index 552426e..bfa7d8a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java
@@ -138,11 +138,29 @@ } @Override + public ChromeNotificationBuilder addAction(int icon, CharSequence title, + PendingIntentProvider pendingIntentProvider, + @NotificationUmaTracker.ActionType int actionType) { + assert (mMetadata != null); + PendingIntent pendingIntent = NotificationIntentInterceptor.createInterceptPendingIntent( + NotificationIntentInterceptor.IntentType.ACTION_INTENT, actionType, mMetadata, + pendingIntentProvider); + addAction(icon, title, pendingIntent); + return this; + } + + @Override public ChromeNotificationBuilder addAction(Notification.Action action) { return this; } @Override + public ChromeNotificationBuilder addAction(Notification.Action action, int flags, + @NotificationUmaTracker.ActionType int actionType) { + return this; + } + + @Override public ChromeNotificationBuilder setDeleteIntent(PendingIntent intent) { mBuilder.setDeleteIntent(intent); return this;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java index b07bc6d..bec9dfe 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java
@@ -32,6 +32,8 @@ "notifications.NotificationIntentInterceptor.EXTRA_INTENT_TYPE"; private static final String EXTRA_NOTIFICATION_TYPE = "notifications.NotificationIntentInterceptor.EXTRA_NOTIFICATION_TYPE"; + private static final String EXTRA_ACTION_TYPE = + "notifications.NotificationIntentInterceptor.EXTRA_ACTION_TYPE"; /** * Enum that defines type of notification intent. @@ -72,7 +74,9 @@ NotificationUmaTracker.getInstance().onNotificationDismiss(notificationType); break; case IntentType.ACTION_INTENT: - // TODO(xingliu): Tracks action click event. + int actionType = intent.getIntExtra( + EXTRA_ACTION_TYPE, NotificationUmaTracker.ActionType.UNKNOWN); + NotificationUmaTracker.getInstance().onNotificationActionClick(actionType); break; } @@ -106,6 +110,9 @@ intent.putExtra(EXTRA_PENDING_INTENT, pendingIntent); intent.putExtra(EXTRA_INTENT_TYPE, intentType); intent.putExtra(EXTRA_NOTIFICATION_TYPE, metadata.type); + if (intentType == IntentType.ACTION_INTENT) { + intent.putExtra(EXTRA_ACTION_TYPE, intentId); + } // This flag ensures the broadcast is delivered with foreground priority to speed up the // broadcast delivery.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java index 2c25d0f5..df6833f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
@@ -68,6 +68,23 @@ int NUM_ENTRIES = 15; } + /* + * A list of notification action types, each maps to a notification button. + * To add a type to this list please update SystemNotificationActionType in enums.xml and make + * sure to keep this list in sync. Additions should be treated as APPEND ONLY to keep the UMA + * metric semantics the same over time. + */ + @IntDef({ActionType.UNKNOWN}) + @Retention(RetentionPolicy.SOURCE) + public @interface ActionType { + int UNKNOWN = -1; + // Pause button when an user download is in progress. + int DOWNLOAD_FILES_IN_PROGRESS_PAUSE = 0; + // Resume button when an user download is in progress. + int DOWNLOAD_FILES_IN_PROGRESS_RESUME = 1; + int NUM_ENTRIES = 2; + } + private static final String LAST_SHOWN_NOTIFICATION_TYPE_KEY = "NotificationUmaTracker.LastShownNotificationType"; @@ -134,6 +151,21 @@ .record(type); } + /** + * Logs notification button click event. + * @param type Type of the notification action button. + */ + public void onNotificationActionClick(@ActionType int type) { + if (type == ActionType.UNKNOWN) return; + + // TODO(xingliu): This may not work if Android kill Chrome before native library is loaded. + // Cache data in Android shared preference and flush them to native when available. + new CachedMetrics + .EnumeratedHistogramSample( + "Mobile.SystemNotification.Action.Click", ActionType.NUM_ENTRIES) + .record(type); + } + private void logNotificationShown( @SystemNotificationType int type, @ChannelDefinitions.ChannelId String channelId) { if (!mNotificationManager.areNotificationsEnabled()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/PendingIntentProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/PendingIntentProvider.java index acd37e2..2fa46f0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/PendingIntentProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/PendingIntentProvider.java
@@ -45,7 +45,7 @@ PendingIntent.getActivity(context, requestCode, intent, flags), flags); } - private PendingIntentProvider(PendingIntent pendingIntent, int flags) { + public PendingIntentProvider(PendingIntent pendingIntent, int flags) { mPendingIntent = pendingIntent; mFlags = flags; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java index d11f8f3c..cdb41c8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator.java
@@ -73,6 +73,11 @@ void onUrlFocusChange(boolean hasFocus); /** + * Signals that native initialization has completed. + */ + void onNativeInitialized(); + + /** * Create a model for a suggestion at the specified position. * @param suggestion The suggestion to create the model for. * @return A model for the suggestion. @@ -185,6 +190,8 @@ list.setClipToPadding(false); // Register a view type for a default omnibox suggestion. + // Note: clang-format does a bad job formatting lambdas so we turn it off here. + // clang-format off adapter.registerType( OmniboxSuggestionUiType.DEFAULT, () -> new SuggestionView(mListView.getContext()), @@ -194,6 +201,7 @@ OmniboxSuggestionUiType.EDIT_URL_SUGGESTION, () -> EditUrlSuggestionProcessor.createView(mListView.getContext()), EditUrlSuggestionViewBinder::bind); + // clang-format on mHolder = new SuggestionListViewHolder(container, list, adapter);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java index bacc34eb..e7f792e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -266,6 +266,8 @@ } mDeferredNativeRunnables.clear(); mAnswerSuggestionProcessor.onNativeInitialized(); + mBasicSuggestionProcessor.onNativeInitialized(); + if (mEditUrlProcessor != null) mEditUrlProcessor.onNativeInitialized(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/AnswerSuggestionProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/AnswerSuggestionProcessor.java index b965b6f..810d0c0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/AnswerSuggestionProcessor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/AnswerSuggestionProcessor.java
@@ -52,9 +52,7 @@ return suggestion.hasAnswer(); } - /** - * Signals that native initialization has completed. - */ + @Override public void onNativeInitialized() { // Experiment: controls presence of certain answer icon types. mEnableNewAnswerLayout = @@ -138,50 +136,46 @@ if (numAnswerLines == -1) numAnswerLines = 1; model.set(SuggestionViewProperties.IS_ANSWER, true); - if (mEnableNewAnswerLayout) { - model.set(SuggestionViewProperties.TEXT_LINE_2_SIZING, - Pair.create(TypedValue.COMPLEX_UNIT_SP, - (float) AnswerTextBuilder.getMaxTextHeightSp(firstLine))); - model.set(SuggestionViewProperties.TEXT_LINE_2_TEXT, - new SuggestionTextContainer( - AnswerTextBuilder.buildSpannable(firstLine, density))); - - model.set(SuggestionViewProperties.TEXT_LINE_1_SIZING, - Pair.create(TypedValue.COMPLEX_UNIT_SP, - (float) AnswerTextBuilder.getMaxTextHeightSp(secondLine))); - model.set(SuggestionViewProperties.TEXT_LINE_1_TEXT, - new SuggestionTextContainer( - AnswerTextBuilder.buildSpannable(secondLine, density))); - model.set(SuggestionViewProperties.TEXT_LINE_1_MAX_LINES, numAnswerLines); - model.set(SuggestionViewProperties.TEXT_LINE_2_MAX_LINES, 1); - model.set(SuggestionViewProperties.TEXT_LINE_2_TEXT_COLOR, - SuggestionViewViewBinder.getStandardFontColor( - mContext, model.get(SuggestionCommonProperties.USE_DARK_COLORS))); - model.set(SuggestionViewProperties.TEXT_LINE_1_TEXT_DIRECTION, - View.TEXT_DIRECTION_INHERIT); - } else { - model.set(SuggestionViewProperties.TEXT_LINE_1_SIZING, - Pair.create(TypedValue.COMPLEX_UNIT_SP, - (float) AnswerTextBuilder.getMaxTextHeightSp(firstLine))); - model.set(SuggestionViewProperties.TEXT_LINE_1_TEXT, - new SuggestionTextContainer( - AnswerTextBuilder.buildSpannable(firstLine, density))); - - model.set(SuggestionViewProperties.TEXT_LINE_2_SIZING, - Pair.create(TypedValue.COMPLEX_UNIT_SP, - (float) AnswerTextBuilder.getMaxTextHeightSp(secondLine))); - model.set(SuggestionViewProperties.TEXT_LINE_2_TEXT, - new SuggestionTextContainer( - AnswerTextBuilder.buildSpannable(secondLine, density))); - model.set(SuggestionViewProperties.TEXT_LINE_1_MAX_LINES, 1); - model.set(SuggestionViewProperties.TEXT_LINE_2_MAX_LINES, numAnswerLines); - model.set(SuggestionViewProperties.TEXT_LINE_2_TEXT_COLOR, - SuggestionViewViewBinder.getStandardFontColor( - mContext, model.get(SuggestionCommonProperties.USE_DARK_COLORS))); - model.set(SuggestionViewProperties.TEXT_LINE_2_TEXT_DIRECTION, - View.TEXT_DIRECTION_INHERIT); + // New answer layout is specific to all definitions except dictionary. + // There are few changes when compared to classic layout, most notably the order + // of the items on the card is reverse. + boolean applyNewLayout = + mEnableNewAnswerLayout && answer.getType() != AnswerType.DICTIONARY; + if (applyNewLayout) { + SuggestionAnswer.ImageLine temp = firstLine; + firstLine = secondLine; + secondLine = temp; } + model.set(SuggestionViewProperties.TEXT_LINE_1_SIZING, + Pair.create(TypedValue.COMPLEX_UNIT_SP, + (float) AnswerTextBuilder.getMaxTextHeightSp(firstLine))); + model.set(SuggestionViewProperties.TEXT_LINE_2_SIZING, + Pair.create(TypedValue.COMPLEX_UNIT_SP, + (float) AnswerTextBuilder.getMaxTextHeightSp(secondLine))); + + model.set(SuggestionViewProperties.TEXT_LINE_1_TEXT, + new SuggestionTextContainer( + AnswerTextBuilder.buildSpannable(firstLine, density, applyNewLayout))); + model.set(SuggestionViewProperties.TEXT_LINE_2_TEXT, + new SuggestionTextContainer( + AnswerTextBuilder.buildSpannable(secondLine, density, applyNewLayout))); + + model.set(SuggestionViewProperties.TEXT_LINE_1_MAX_LINES, + applyNewLayout ? 1 : numAnswerLines); + model.set(SuggestionViewProperties.TEXT_LINE_2_MAX_LINES, + applyNewLayout ? numAnswerLines : 1); + + model.set(SuggestionViewProperties.TEXT_LINE_1_TEXT_COLOR, + SuggestionViewViewBinder.getStandardFontColor( + mContext, model.get(SuggestionCommonProperties.USE_DARK_COLORS))); + model.set(SuggestionViewProperties.TEXT_LINE_2_TEXT_COLOR, + SuggestionViewViewBinder.getStandardFontColor( + mContext, model.get(SuggestionCommonProperties.USE_DARK_COLORS))); + + model.set(SuggestionViewProperties.TEXT_LINE_1_TEXT_DIRECTION, View.TEXT_DIRECTION_INHERIT); + model.set(SuggestionViewProperties.TEXT_LINE_2_TEXT_DIRECTION, View.TEXT_DIRECTION_INHERIT); + model.set(SuggestionViewProperties.HAS_ANSWER_IMAGE, secondLine.hasImage()); model.set(SuggestionViewProperties.REFINABLE, true);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/AnswerTextBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/AnswerTextBuilder.java index aa5a9b9..7c10e89 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/AnswerTextBuilder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/AnswerTextBuilder.java
@@ -48,7 +48,8 @@ * @param density Screen density which will be used to properly size and layout images and top- * aligned text. */ - static Spannable buildSpannable(SuggestionAnswer.ImageLine line, float density) { + static Spannable buildSpannable( + SuggestionAnswer.ImageLine line, float density, boolean useNewAnswerLayout) { SpannableStringBuilder builder = new SpannableStringBuilder(); // Determine the height of the largest text element in the line. This @@ -57,17 +58,19 @@ List<SuggestionAnswer.TextField> textFields = line.getTextFields(); for (int i = 0; i < textFields.size(); i++) { - appendAndStyleText(builder, textFields.get(i), maxTextHeightSp, density); + appendAndStyleText( + builder, textFields.get(i), maxTextHeightSp, density, useNewAnswerLayout); } if (line.hasAdditionalText()) { builder.append(" "); SuggestionAnswer.TextField additionalText = line.getAdditionalText(); - appendAndStyleText(builder, additionalText, maxTextHeightSp, density); + appendAndStyleText( + builder, additionalText, maxTextHeightSp, density, useNewAnswerLayout); } if (line.hasStatusText()) { builder.append(" "); SuggestionAnswer.TextField statusText = line.getStatusText(); - appendAndStyleText(builder, statusText, maxTextHeightSp, density); + appendAndStyleText(builder, statusText, maxTextHeightSp, density, useNewAnswerLayout); } return builder; @@ -117,7 +120,8 @@ */ @SuppressWarnings("deprecation") // Update usage of Html.fromHtml when API min is 24 private static void appendAndStyleText(SpannableStringBuilder builder, - SuggestionAnswer.TextField textField, int maxTextHeightSp, float density) { + SuggestionAnswer.TextField textField, int maxTextHeightSp, float density, + boolean useNewAnswerLayout) { String text = textField.getText(); int type = textField.getType(); @@ -133,7 +137,8 @@ AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(getAnswerTextSizeSp(type), true); builder.setSpan(sizeSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - ForegroundColorSpan colorSpan = new ForegroundColorSpan(getAnswerTextColor(type)); + ForegroundColorSpan colorSpan = + new ForegroundColorSpan(getAnswerTextColor(type, useNewAnswerLayout)); builder.setSpan(colorSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); if (type == AnswerTextType.TOP_ALIGNED) { @@ -179,7 +184,7 @@ * * @param type The answer type as specified at http://goto.google.com/ais_api. */ - private static int getAnswerTextColor(@AnswerTextType int type) { + private static int getAnswerTextColor(@AnswerTextType int type, boolean useNewAnswerLayout) { Resources resources = ContextUtils.getApplicationContext().getResources(); switch (type) { case AnswerTextType.DESCRIPTION_NEGATIVE: @@ -191,17 +196,25 @@ resources, R.color.answers_description_text_positive); case AnswerTextType.SUGGESTION: - return ApiCompatibilityUtils.getColor(resources, R.color.url_emphasis_default_text); - case AnswerTextType.PERSONALIZED_SUGGESTION: - return ApiCompatibilityUtils.getColor(resources, R.color.url_emphasis_default_text); + if (useNewAnswerLayout) { + return ApiCompatibilityUtils.getColor(resources, R.color.answers_answer_text); + } else { + return ApiCompatibilityUtils.getColor( + resources, R.color.url_emphasis_default_text); + } case AnswerTextType.TOP_ALIGNED: case AnswerTextType.ANSWER_TEXT_MEDIUM: case AnswerTextType.ANSWER_TEXT_LARGE: case AnswerTextType.SUGGESTION_SECONDARY_TEXT_SMALL: case AnswerTextType.SUGGESTION_SECONDARY_TEXT_MEDIUM: - return ApiCompatibilityUtils.getColor(resources, R.color.answers_answer_text); + if (useNewAnswerLayout) { + return ApiCompatibilityUtils.getColor( + resources, R.color.url_emphasis_default_text); + } else { + return ApiCompatibilityUtils.getColor(resources, R.color.answers_answer_text); + } default: Log.w(TAG, "Unknown answer type: " + type);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java index b0e7daf72..3c098ca 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java
@@ -13,6 +13,9 @@ import android.util.TypedValue; import android.view.View; +import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.omnibox.MatchClassificationStyle; import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType; import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider; @@ -32,6 +35,7 @@ private final Context mContext; private final SuggestionHost mSuggestionHost; private final UrlBarEditingTextStateProvider mUrlBarEditingTextProvider; + private boolean mEnableNewAnswerLayout; /** * @param context An Android context. @@ -73,6 +77,16 @@ @Override public void onUrlFocusChange(boolean hasFocus) {} + /** + * Signals that native initialization has completed. + */ + @Override + public void onNativeInitialized() { + // Experiment: controls presence of certain answer icon types. + mEnableNewAnswerLayout = + ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_NEW_ANSWER_LAYOUT); + } + private void setStateForSuggestion(PropertyModel model, OmniboxSuggestion suggestion) { int suggestionType = suggestion.getType(); @SuggestionIcon @@ -95,8 +109,10 @@ urlHighlighted = applyHighlightToMatchRegions( str, suggestion.getDisplayTextClassifications()); textLine2 = str; - textLine2Color = SuggestionViewViewBinder.getStandardUrlColor( - mContext, model.get(SuggestionCommonProperties.USE_DARK_COLORS)); + textLine2Color = ApiCompatibilityUtils.getColor(mContext.getResources(), + model.get(SuggestionCommonProperties.USE_DARK_COLORS) + ? R.color.suggestion_url_dark_modern + : R.color.suggestion_url_light_modern); textLine2Direction = View.TEXT_DIRECTION_LTR; } else { textLine2 = null; @@ -118,6 +134,15 @@ textLine2Color = SuggestionViewViewBinder.getStandardFontColor( mContext, model.get(SuggestionCommonProperties.USE_DARK_COLORS)); textLine2Direction = View.TEXT_DIRECTION_INHERIT; + } else if (mEnableNewAnswerLayout + && suggestionType == OmniboxSuggestionType.CALCULATOR) { + suggestionIcon = SuggestionIcon.CALCULATOR; + textLine2 = SpannableString.valueOf( + mUrlBarEditingTextProvider.getTextWithAutocomplete()); + + textLine2Color = ApiCompatibilityUtils.getColor( + mContext.getResources(), R.color.answers_answer_text); + textLine2Direction = View.TEXT_DIRECTION_INHERIT; } else { textLine2 = null; } @@ -204,6 +229,16 @@ new OmniboxSuggestion.MatchClassification( 0, MatchClassificationStyle.NONE)); } + } else if (mEnableNewAnswerLayout + && suggestion.getType() == OmniboxSuggestionType.CALCULATOR) { + // Trim preceding equal sign since we're going to present an icon instead. + // This is probably best placed in search_suggestion_parser.cc file, but at this point + // this would affect other devices that still want to present the sign (eg. iOS) so + // until these devices adopt the new entities we need to manage this here. + if (suggestedQuery.subSequence(0, 2).equals("= ")) { + suggestedQuery = suggestedQuery.substring(2); + } + shouldHighlight = false; } Spannable str = SpannableString.valueOf(suggestedQuery);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewViewBinder.java index 2a8db99..dca5eab 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewViewBinder.java
@@ -207,18 +207,4 @@ : R.color.url_emphasis_light_default_text; return ApiCompatibilityUtils.getColor(context.getResources(), res); } - - /** - * Get the appropriate font color to be used for URL text in suggestions. - * @param context The context to load the color. - * @param useDarkColors Whether dark colors should be used. - * @return The font color to be used. - */ - @ColorInt - public static int getStandardUrlColor(Context context, boolean useDarkColors) { - @ColorRes - int res = useDarkColors ? R.color.suggestion_url_dark_modern - : R.color.suggestion_url_light_modern; - return ApiCompatibilityUtils.getColor(context.getResources(), res); - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor.java index 2b7d73b7..29629da9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor.java
@@ -172,6 +172,9 @@ model.set(EditUrlSuggestionProperties.URL_TEXT, mLastProcessedSuggestion.getUrl()); } + @Override + public void onNativeInitialized() {} + /** * @param provider A means of accessing the activity's tab. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManageSyncPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManageSyncPreferences.java new file mode 100644 index 0000000..fbd9263 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManageSyncPreferences.java
@@ -0,0 +1,441 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.preferences; + +import android.app.DialogFragment; +import android.app.FragmentManager; +import android.app.FragmentTransaction; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.Preference; +import android.preference.PreferenceFragment; +import android.support.annotation.Nullable; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + +import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.base.ThreadUtils; +import org.chromium.base.VisibleForTesting; +import org.chromium.base.metrics.RecordUserAction; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.AppHooks; +import org.chromium.chrome.browser.autofill.PersonalDataManager; +import org.chromium.chrome.browser.help.HelpAndFeedback; +import org.chromium.chrome.browser.invalidation.InvalidationController; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.sync.ProfileSyncService; +import org.chromium.chrome.browser.sync.ui.PassphraseCreationDialogFragment; +import org.chromium.chrome.browser.sync.ui.PassphraseDialogFragment; +import org.chromium.chrome.browser.sync.ui.PassphraseTypeDialogFragment; +import org.chromium.components.signin.ChromeSigninController; +import org.chromium.components.sync.ModelType; +import org.chromium.components.sync.PassphraseType; + +import java.util.HashSet; +import java.util.Set; + +/** + * Settings fragment to customize Sync options (data types, encryption). Can be accessed from + * {@link SyncAndServicesPreferences}. + */ +public class ManageSyncPreferences extends PreferenceFragment + implements PassphraseDialogFragment.Listener, PassphraseCreationDialogFragment.Listener, + PassphraseTypeDialogFragment.Listener, Preference.OnPreferenceChangeListener, + ProfileSyncService.SyncStateChangedListener { + @VisibleForTesting + public static final String FRAGMENT_ENTER_PASSPHRASE = "enter_password"; + @VisibleForTesting + public static final String FRAGMENT_CUSTOM_PASSPHRASE = "custom_password"; + @VisibleForTesting + public static final String FRAGMENT_PASSPHRASE_TYPE = "password_type"; + + private static final String PREF_SYNC_EVERYTHING = "sync_everything"; + private static final String PREF_SYNC_AUTOFILL = "sync_autofill"; + private static final String PREF_SYNC_BOOKMARKS = "sync_bookmarks"; + private static final String PREF_SYNC_PAYMENTS_INTEGRATION = "sync_payments_integration"; + private static final String PREF_SYNC_HISTORY = "sync_history"; + private static final String PREF_SYNC_PASSWORDS = "sync_passwords"; + private static final String PREF_SYNC_RECENT_TABS = "sync_recent_tabs"; + private static final String PREF_SYNC_SETTINGS = "sync_settings"; + private static final String PREF_GOOGLE_ACTIVITY_CONTROLS = "google_activity_controls"; + private static final String PREF_ENCRYPTION = "encryption"; + private static final String PREF_SYNC_MANAGE_DATA = "sync_manage_data"; + + private static final String DASHBOARD_URL = "https://www.google.com/settings/chrome/sync"; + + private final ProfileSyncService mProfileSyncService = ProfileSyncService.get(); + + private ChromeSwitchPreference mSyncEverything; + private CheckBoxPreference mSyncAutofill; + private CheckBoxPreference mSyncBookmarks; + private CheckBoxPreference mSyncPaymentsIntegration; + private CheckBoxPreference mSyncHistory; + private CheckBoxPreference mSyncPasswords; + private CheckBoxPreference mSyncRecentTabs; + private CheckBoxPreference mSyncSettings; + // Contains preferences for all sync data types. + private CheckBoxPreference[] mSyncTypePreferences; + + private Preference mGoogleActivityControls; + private Preference mSyncEncryption; + private Preference mManageSyncData; + + private ProfileSyncService.SyncSetupInProgressHandle mSyncSetupInProgressHandle; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getActivity().setTitle(R.string.manage_sync_title); + setHasOptionsMenu(true); + + PreferenceUtils.addPreferencesFromResource(this, R.xml.manage_sync_preferences); + + mSyncEverything = (ChromeSwitchPreference) findPreference(PREF_SYNC_EVERYTHING); + mSyncEverything.setOnPreferenceChangeListener(this); + + mSyncAutofill = (CheckBoxPreference) findPreference(PREF_SYNC_AUTOFILL); + mSyncBookmarks = (CheckBoxPreference) findPreference(PREF_SYNC_BOOKMARKS); + mSyncPaymentsIntegration = + (CheckBoxPreference) findPreference(PREF_SYNC_PAYMENTS_INTEGRATION); + mSyncHistory = (CheckBoxPreference) findPreference(PREF_SYNC_HISTORY); + mSyncPasswords = (CheckBoxPreference) findPreference(PREF_SYNC_PASSWORDS); + mSyncRecentTabs = (CheckBoxPreference) findPreference(PREF_SYNC_RECENT_TABS); + mSyncSettings = (CheckBoxPreference) findPreference(PREF_SYNC_SETTINGS); + + mGoogleActivityControls = findPreference(PREF_GOOGLE_ACTIVITY_CONTROLS); + mSyncEncryption = findPreference(PREF_ENCRYPTION); + mSyncEncryption.setOnPreferenceClickListener( + SyncPreferenceUtils.toOnClickListener(this, this::onSyncEncryptionClicked)); + mManageSyncData = findPreference(PREF_SYNC_MANAGE_DATA); + mManageSyncData.setOnPreferenceClickListener(SyncPreferenceUtils.toOnClickListener( + this, this::openDashboardTabInNewActivityStack)); + + mSyncTypePreferences = + new CheckBoxPreference[] {mSyncAutofill, mSyncBookmarks, mSyncPaymentsIntegration, + mSyncHistory, mSyncPasswords, mSyncRecentTabs, mSyncSettings}; + for (CheckBoxPreference type : mSyncTypePreferences) { + type.setOnPreferenceChangeListener(this); + } + + if (Profile.getLastUsedProfile().isChild()) { + mGoogleActivityControls.setSummary( + R.string.sign_in_google_activity_controls_summary_child_account); + } + + // Prevent sync settings changes from taking effect until the user leaves this screen. + mSyncSetupInProgressHandle = mProfileSyncService.getSetupInProgressHandle(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mSyncSetupInProgressHandle.close(); + + if (mProfileSyncService.isSyncRequested()) { + InvalidationController.get().ensureStartedAndUpdateRegisteredTypes(); + } + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + menu.clear(); + MenuItem help = + menu.add(Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help); + help.setIcon(R.drawable.ic_help_and_feedback); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.menu_id_targeted_help) { + HelpAndFeedback.getInstance(getActivity()) + .show(getActivity(), getString(R.string.help_context_sync_and_services), + Profile.getLastUsedProfile(), null); + return true; + } + return false; + } + + @Override + public void onStart() { + super.onStart(); + mProfileSyncService.addSyncStateChangedListener(this); + } + + @Override + public void onStop() { + super.onStop(); + mProfileSyncService.removeSyncStateChangedListener(this); + } + + @Override + public void onResume() { + super.onResume(); + updateSyncPreferences(); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object o) { + // A change to Preference state hasn't been applied yet. Defer + // updateSyncStateFromSelectedModelTypes so it gets the updated state from isChecked(). + ThreadUtils.postOnUiThread(this::updateSyncStateFromSelectedModelTypes); + return true; + } + + /** + * ProfileSyncService.SyncStateChangedListener implementation, listens to sync state changes. + * + * If the user has just turned on sync, this listener is needed in order to enable + * the encryption settings once the engine has initialized. + */ + @Override + public void syncStateChanged() { + // This is invoked synchronously from ProfileSyncService.setChosenDataTypes, postpone the + // update to let updateSyncStateFromSelectedModelTypes finish saving the state. + ThreadUtils.postOnUiThread(this::updateSyncPreferences); + } + + /** + * Gets the current state of data types from {@link ProfileSyncService} and updates UI elements + * from this state. + */ + private void updateSyncPreferences() { + String signedInAccountName = ChromeSigninController.get().getSignedInAccountName(); + if (signedInAccountName == null) { + // May happen if account is removed from the device while this screen is shown. + getActivity().finish(); + return; + } + + mGoogleActivityControls.setOnPreferenceClickListener(SyncPreferenceUtils.toOnClickListener( + this, () -> onGoogleActivityControlsClicked(signedInAccountName))); + + updateDataTypeState(); + updateEncryptionState(); + } + + /** + * Gets the state from data type checkboxes and saves this state into {@link ProfileSyncService} + * and {@link PersonalDataManager}. + */ + private void updateSyncStateFromSelectedModelTypes() { + mProfileSyncService.setChosenDataTypes( + mSyncEverything.isChecked(), getSelectedModelTypes()); + PersonalDataManager.setPaymentsIntegrationEnabled(mSyncPaymentsIntegration.isChecked()); + // Some calls to setChosenDataTypes don't trigger syncStateChanged, so schedule update here. + ThreadUtils.postOnUiThread(this::updateSyncPreferences); + } + + /** + * Update the encryption state. + * + * If sync's engine is initialized, the button is enabled and the dialog will present the + * valid encryption options for the user. Otherwise, any encryption dialogs will be closed + * and the button will be disabled because the engine is needed in order to know and + * modify the encryption state. + */ + private void updateEncryptionState() { + boolean isEngineInitialized = mProfileSyncService.isEngineInitialized(); + mSyncEncryption.setEnabled(isEngineInitialized); + mSyncEncryption.setSummary(null); + if (!isEngineInitialized) { + // If sync is not initialized, encryption state is unavailable and can't be changed. + // Leave the button disabled and the summary empty. Additionally, close the dialogs in + // case they were open when a stop and clear comes. + closeDialogIfOpen(FRAGMENT_CUSTOM_PASSPHRASE); + closeDialogIfOpen(FRAGMENT_ENTER_PASSPHRASE); + return; + } + if (!mProfileSyncService.isPassphraseRequiredForDecryption()) { + closeDialogIfOpen(FRAGMENT_ENTER_PASSPHRASE); + } + if (mProfileSyncService.isPassphraseRequiredForDecryption() && isAdded()) { + mSyncEncryption.setSummary( + errorSummary(getString(R.string.sync_need_passphrase), getActivity())); + } + } + + /** Applies a span to the given string to give it an error color. */ + private static Spannable errorSummary(String string, Context context) { + SpannableString summary = new SpannableString(string); + summary.setSpan(new ForegroundColorSpan(ApiCompatibilityUtils.getColor( + context.getResources(), R.color.input_underline_error_color)), + 0, summary.length(), 0); + return summary; + } + + private Set<Integer> getSelectedModelTypes() { + Set<Integer> types = new HashSet<>(); + if (mSyncAutofill.isChecked()) types.add(ModelType.AUTOFILL); + if (mSyncBookmarks.isChecked()) types.add(ModelType.BOOKMARKS); + if (mSyncHistory.isChecked()) types.add(ModelType.TYPED_URLS); + if (mSyncPasswords.isChecked()) types.add(ModelType.PASSWORDS); + if (mSyncRecentTabs.isChecked()) types.add(ModelType.PROXY_TABS); + if (mSyncSettings.isChecked()) types.add(ModelType.PREFERENCES); + return types; + } + + private void displayPassphraseTypeDialog() { + FragmentTransaction ft = getFragmentManager().beginTransaction(); + PassphraseTypeDialogFragment dialog = + PassphraseTypeDialogFragment.create(mProfileSyncService.getPassphraseType(), + mProfileSyncService.getExplicitPassphraseTime(), + mProfileSyncService.isEncryptEverythingAllowed()); + dialog.show(ft, FRAGMENT_PASSPHRASE_TYPE); + dialog.setTargetFragment(this, -1); + } + + private void displayPassphraseDialog() { + FragmentTransaction ft = getFragmentManager().beginTransaction(); + PassphraseDialogFragment.newInstance(this).show(ft, FRAGMENT_ENTER_PASSPHRASE); + } + + private void displayCustomPassphraseDialog() { + FragmentTransaction ft = getFragmentManager().beginTransaction(); + PassphraseCreationDialogFragment dialog = new PassphraseCreationDialogFragment(); + dialog.setTargetFragment(this, -1); + dialog.show(ft, FRAGMENT_CUSTOM_PASSPHRASE); + } + + private void closeDialogIfOpen(String tag) { + FragmentManager manager = getFragmentManager(); + if (manager == null) { + // Do nothing if the manager doesn't exist yet; see http://crbug.com/480544. + return; + } + DialogFragment df = (DialogFragment) manager.findFragmentByTag(tag); + if (df != null) { + df.dismiss(); + } + } + + /** Returns whether the passphrase successfully decrypted the pending keys. */ + private boolean handleDecryption(String passphrase) { + if (passphrase.isEmpty() || !mProfileSyncService.setDecryptionPassphrase(passphrase)) { + return false; + } + // PassphraseDialogFragment doesn't handle closing itself, so do it here. This is not done + // in updateSyncStateFromAndroidSyncSettings() because that happens onResume and possibly in + // other cases where the dialog should stay open. + closeDialogIfOpen(FRAGMENT_ENTER_PASSPHRASE); + // Update our configuration UI. + updateSyncPreferences(); + return true; + } + + /** Callback for PassphraseDialogFragment.Listener */ + @Override + public boolean onPassphraseEntered(String passphrase) { + if (!mProfileSyncService.isEngineInitialized() + || !mProfileSyncService.isPassphraseRequiredForDecryption()) { + // If the engine was shut down since the dialog was opened, or the passphrase isn't + // required anymore, do nothing. + return false; + } + return handleDecryption(passphrase); + } + + /** Callback for PassphraseDialogFragment.Listener */ + @Override + public void onPassphraseCanceled() {} + + /** Callback for PassphraseCreationDialogFragment.Listener */ + @Override + public void onPassphraseCreated(String passphrase) { + if (!mProfileSyncService.isEngineInitialized()) { + // If the engine was shut down since the dialog was opened, do nothing. + return; + } + mProfileSyncService.enableEncryptEverything(); + mProfileSyncService.setEncryptionPassphrase(passphrase); + // Save the current state of data types - this tells the sync engine to + // apply our encryption configuration changes. + updateSyncStateFromSelectedModelTypes(); + } + + /** Callback for PassphraseTypeDialogFragment.Listener */ + @Override + public void onPassphraseTypeSelected(PassphraseType type) { + if (!mProfileSyncService.isEngineInitialized()) { + // If the engine was shut down since the dialog was opened, do nothing. + return; + } + + boolean isAllDataEncrypted = mProfileSyncService.isEncryptEverythingEnabled(); + boolean isUsingSecondaryPassphrase = mProfileSyncService.isUsingSecondaryPassphrase(); + + // The passphrase type should only ever be selected if the account doesn't have + // full encryption enabled. Otherwise both options should be disabled. + assert !isAllDataEncrypted; + assert !isUsingSecondaryPassphrase; + displayCustomPassphraseDialog(); + } + + private void onGoogleActivityControlsClicked(String signedInAccountName) { + AppHooks.get().createGoogleActivityController().openWebAndAppActivitySettings( + getActivity(), signedInAccountName); + RecordUserAction.record("Signin_AccountSettings_GoogleActivityControlsClicked"); + } + + private void onSyncEncryptionClicked() { + if (!mProfileSyncService.isEngineInitialized()) return; + + if (mProfileSyncService.isPassphraseRequiredForDecryption()) { + displayPassphraseDialog(); + } else { + displayPassphraseTypeDialog(); + } + } + + /** Opens the Google Dashboard where the user can control the data stored for the account. */ + private void openDashboardTabInNewActivityStack() { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(DASHBOARD_URL)); + intent.setPackage(getActivity().getPackageName()); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } + + /** + * Gets the current state of data types from {@link ProfileSyncService} and updates the UI. + */ + private void updateDataTypeState() { + boolean syncEverything = mProfileSyncService.hasKeepEverythingSynced(); + mSyncEverything.setChecked(syncEverything); + if (syncEverything) { + for (CheckBoxPreference pref : mSyncTypePreferences) { + pref.setChecked(true); + pref.setEnabled(false); + } + return; + } + + Set<Integer> syncTypes = mProfileSyncService.getChosenDataTypes(); + mSyncAutofill.setChecked(syncTypes.contains(ModelType.AUTOFILL)); + mSyncAutofill.setEnabled(true); + mSyncBookmarks.setChecked(syncTypes.contains(ModelType.BOOKMARKS)); + mSyncBookmarks.setEnabled(true); + mSyncHistory.setChecked(syncTypes.contains(ModelType.TYPED_URLS)); + mSyncHistory.setEnabled(true); + mSyncPasswords.setChecked(syncTypes.contains(ModelType.PASSWORDS)); + mSyncPasswords.setEnabled(true); + mSyncRecentTabs.setChecked(syncTypes.contains(ModelType.PROXY_TABS)); + mSyncRecentTabs.setEnabled(true); + mSyncSettings.setChecked(syncTypes.contains(ModelType.PREFERENCES)); + mSyncSettings.setEnabled(true); + + // Payments integration requires AUTOFILL model type + boolean syncAutofill = syncTypes.contains(ModelType.AUTOFILL); + mSyncPaymentsIntegration.setChecked( + syncAutofill && PersonalDataManager.isPaymentsIntegrationEnabled()); + mSyncPaymentsIntegration.setEnabled(syncAutofill); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java index 43824eef..3ad3a2a8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
@@ -8,12 +8,10 @@ import android.app.DialogFragment; import android.app.FragmentManager; import android.app.FragmentTransaction; -import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.net.Uri; import android.os.Bundle; -import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; @@ -21,24 +19,16 @@ import android.provider.Settings; import android.support.annotation.IntDef; import android.support.annotation.Nullable; -import android.support.v4.util.ArraySet; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.style.ForegroundColorSpan; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.BuildInfo; import org.chromium.base.ContextUtils; import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; -import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; -import org.chromium.chrome.browser.AppHooks; -import org.chromium.chrome.browser.autofill.PersonalDataManager; import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsEnabledStateUtils; import org.chromium.chrome.browser.contextualsearch.ContextualSearchFieldTrial; import org.chromium.chrome.browser.help.HelpAndFeedback; @@ -51,58 +41,34 @@ import org.chromium.chrome.browser.signin.UnifiedConsentServiceBridge; import org.chromium.chrome.browser.sync.GoogleServiceAuthError; import org.chromium.chrome.browser.sync.ProfileSyncService; -import org.chromium.chrome.browser.sync.ui.PassphraseCreationDialogFragment; import org.chromium.chrome.browser.sync.ui.PassphraseDialogFragment; -import org.chromium.chrome.browser.sync.ui.PassphraseTypeDialogFragment; import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.components.signin.AccountManagerFacade; import org.chromium.components.signin.ChromeSigninController; import org.chromium.components.sync.AndroidSyncSettings; -import org.chromium.components.sync.ModelType; -import org.chromium.components.sync.PassphraseType; import org.chromium.components.sync.ProtocolErrorClientAction; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.HashSet; -import java.util.Set; /** - * Settings fragment to customize Sync options (data types, encryption) and other services that - * communicate with Google. + * Settings fragment to enable Sync and other services that communicate with Google. */ public class SyncAndServicesPreferences extends PreferenceFragment - implements PassphraseDialogFragment.Listener, PassphraseCreationDialogFragment.Listener, - PassphraseTypeDialogFragment.Listener, Preference.OnPreferenceChangeListener, + implements PassphraseDialogFragment.Listener, Preference.OnPreferenceChangeListener, ProfileSyncService.SyncStateChangedListener { private static final String IS_FROM_SIGNIN_SCREEN = "SyncAndServicesPreferences.isFromSigninScreen"; @VisibleForTesting public static final String FRAGMENT_ENTER_PASSPHRASE = "enter_password"; - @VisibleForTesting - public static final String FRAGMENT_CUSTOM_PASSPHRASE = "custom_password"; - @VisibleForTesting - public static final String FRAGMENT_PASSPHRASE_TYPE = "password_type"; private static final String PREF_SIGNIN = "sign_in"; private static final String PREF_SYNC_CATEGORY = "sync_category"; private static final String PREF_SYNC_ERROR_CARD = "sync_error_card"; - private static final String PREF_USE_SYNC_AND_ALL_SERVICES = "use_sync_and_all_services"; - private static final String PREF_SYNC_AUTOFILL = "sync_autofill"; - private static final String PREF_SYNC_BOOKMARKS = "sync_bookmarks"; - private static final String PREF_SYNC_PAYMENTS_INTEGRATION = "sync_payments_integration"; - private static final String PREF_SYNC_HISTORY = "sync_history"; - private static final String PREF_SYNC_PASSWORDS = "sync_passwords"; - private static final String PREF_SYNC_RECENT_TABS = "sync_recent_tabs"; - private static final String PREF_SYNC_SETTINGS = "sync_settings"; - private static final String PREF_SYNC_ACTIVITY_AND_INTERACTIONS = - "sync_activity_and_interactions"; - private static final String PREF_GOOGLE_ACTIVITY_CONTROLS = "google_activity_controls"; - private static final String PREF_ENCRYPTION = "encryption"; - private static final String PREF_SYNC_MANAGE_DATA = "sync_manage_data"; + private static final String PREF_SYNC_REQUESTED = "sync_requested"; private static final String PREF_SERVICES_CATEGORY = "services_category"; private static final String PREF_SEARCH_SUGGESTIONS = "search_suggestions"; @@ -128,8 +94,6 @@ int OTHER_ERRORS = 128; } - private static final String DASHBOARD_URL = "https://www.google.com/settings/chrome/sync"; - private final ProfileSyncService mProfileSyncService = ProfileSyncService.get(); private final PrefServiceBridge mPrefServiceBridge = PrefServiceBridge.getInstance(); private final PrivacyPreferencesManager mPrivacyPrefManager = @@ -143,21 +107,7 @@ private PreferenceCategory mSyncCategory; private Preference mSyncErrorCard; - private ChromeSwitchPreference mUseSyncAndAllServices; - private CheckBoxPreference mSyncAutofill; - private CheckBoxPreference mSyncBookmarks; - private CheckBoxPreference mSyncPaymentsIntegration; - private CheckBoxPreference mSyncHistory; - private CheckBoxPreference mSyncPasswords; - private CheckBoxPreference mSyncRecentTabs; - private CheckBoxPreference mSyncSettings; - private CheckBoxPreference mSyncActivityAndInteractions; - // Contains preferences for all sync data types. - private CheckBoxPreference[] mSyncAllTypes; - - private Preference mGoogleActivityControls; - private Preference mSyncEncryption; - private Preference mManageSyncData; + private ChromeSwitchPreference mSyncRequested; private ChromeSwitchPreference mSearchSuggestions; private ChromeSwitchPreference mNetworkPredictions; @@ -203,36 +153,9 @@ mSyncCategory = (PreferenceCategory) findPreference(PREF_SYNC_CATEGORY); mSyncErrorCard = findPreference(PREF_SYNC_ERROR_CARD); mSyncErrorCard.setOnPreferenceClickListener( - toOnClickListener(this::onSyncErrorCardClicked)); - mUseSyncAndAllServices = - (ChromeSwitchPreference) findPreference(PREF_USE_SYNC_AND_ALL_SERVICES); - mUseSyncAndAllServices.setOnPreferenceChangeListener(this); - - mSyncAutofill = (CheckBoxPreference) findPreference(PREF_SYNC_AUTOFILL); - mSyncBookmarks = (CheckBoxPreference) findPreference(PREF_SYNC_BOOKMARKS); - mSyncPaymentsIntegration = - (CheckBoxPreference) findPreference(PREF_SYNC_PAYMENTS_INTEGRATION); - mSyncHistory = (CheckBoxPreference) findPreference(PREF_SYNC_HISTORY); - mSyncPasswords = (CheckBoxPreference) findPreference(PREF_SYNC_PASSWORDS); - mSyncRecentTabs = (CheckBoxPreference) findPreference(PREF_SYNC_RECENT_TABS); - mSyncSettings = (CheckBoxPreference) findPreference(PREF_SYNC_SETTINGS); - mSyncActivityAndInteractions = - (CheckBoxPreference) findPreference(PREF_SYNC_ACTIVITY_AND_INTERACTIONS); - - mGoogleActivityControls = findPreference(PREF_GOOGLE_ACTIVITY_CONTROLS); - mSyncEncryption = findPreference(PREF_ENCRYPTION); - mSyncEncryption.setOnPreferenceClickListener( - toOnClickListener(this::onSyncEncryptionClicked)); - mManageSyncData = findPreference(PREF_SYNC_MANAGE_DATA); - mManageSyncData.setOnPreferenceClickListener( - toOnClickListener(this::openDashboardTabInNewActivityStack)); - - mSyncAllTypes = new CheckBoxPreference[] {mSyncAutofill, mSyncBookmarks, - mSyncPaymentsIntegration, mSyncHistory, mSyncPasswords, mSyncRecentTabs, - mSyncSettings, mSyncActivityAndInteractions}; - for (CheckBoxPreference type : mSyncAllTypes) { - type.setOnPreferenceChangeListener(this); - } + SyncPreferenceUtils.toOnClickListener(this, this::onSyncErrorCardClicked)); + mSyncRequested = (ChromeSwitchPreference) findPreference(PREF_SYNC_REQUESTED); + mSyncRequested.setOnPreferenceChangeListener(this); mSearchSuggestions = (ChromeSwitchPreference) findPreference(PREF_SEARCH_SUGGESTIONS); mSearchSuggestions.setOnPreferenceChangeListener(this); @@ -280,11 +203,6 @@ mContextualSuggestions = null; } - if (Profile.getLastUsedProfile().isChild()) { - mGoogleActivityControls.setSummary( - R.string.sign_in_google_activity_controls_summary_child_account); - } - // Prevent sync settings changes from taking effect until the user leaves this screen. mSyncSetupInProgressHandle = mProfileSyncService.getSetupInProgressHandle(); @@ -295,18 +213,10 @@ public void onDestroy() { super.onDestroy(); mSyncSetupInProgressHandle.close(); - } - private Preference.OnPreferenceClickListener toOnClickListener(Runnable runnable) { - return preference -> { - if (!isResumed()) { - // This event could come in after onPause if the user clicks back and the preference - // at roughly the same time. See http://b/5983282. - return false; - } - runnable.run(); - return false; - }; + if (mProfileSyncService.isSyncRequested()) { + InvalidationController.get().ensureStartedAndUpdateRegisteredTypes(); + } } @Override @@ -332,8 +242,6 @@ public void onStart() { super.onStart(); mProfileSyncService.addSyncStateChangedListener(this); - updateSyncStateFromAndroidSyncSettings(); - mSigninPreference.registerForUpdates(); } @@ -343,10 +251,6 @@ mSigninPreference.unregisterForUpdates(); mProfileSyncService.removeSyncStateChangedListener(this); - - // Save the new data type state. - configureSyncDataTypes(); - PersonalDataManager.setPaymentsIntegrationEnabled(mSyncPaymentsIntegration.isChecked()); } @Override @@ -358,11 +262,9 @@ @Override public boolean onPreferenceChange(Preference preference, Object newValue) { String key = preference.getKey(); - if (PREF_USE_SYNC_AND_ALL_SERVICES.equals(key)) { - boolean enabled = (boolean) newValue; - UnifiedConsentServiceBridge.setUnifiedConsentGiven(enabled); - ThreadUtils.postOnUiThread(this::updateSyncStateFromSelectedModelTypes); - ThreadUtils.postOnUiThread(this::updateDataTypeState); + if (PREF_SYNC_REQUESTED.equals(key)) { + assert canDisableSync(); + SyncPreferenceUtils.enableSync((boolean) newValue); ThreadUtils.postOnUiThread(this::updatePreferences); } else if (PREF_SEARCH_SUGGESTIONS.equals(key)) { mPrefServiceBridge.setSearchSuggestEnabled((boolean) newValue); @@ -380,24 +282,6 @@ } else if (PREF_URL_KEYED_ANONYMIZED_DATA.equals(key)) { UnifiedConsentServiceBridge.setUrlKeyedAnonymizedDataCollectionEnabled( (boolean) newValue); - } else if (isSyncTypePreference(preference)) { - ThreadUtils.postOnUiThread(() -> { - boolean preferenceChecked = (boolean) newValue; - if (preference == mSyncAutofill) { - // If the user checks the autofill sync checkbox, then enable and check the - // payments integration checkbox. - // - // If the user unchecks the autofill sync checkbox, then disable and uncheck - // the payments integration checkbox. - mSyncPaymentsIntegration.setEnabled(preferenceChecked); - mSyncPaymentsIntegration.setChecked(preferenceChecked); - } else if (preference == mSyncHistory) { - // Disable 'Activity and interactions' if history is disabled, enable otherwise. - mSyncActivityAndInteractions.setEnabled(preferenceChecked); - mSyncActivityAndInteractions.setChecked(preferenceChecked); - } - updateSyncStateFromSelectedModelTypes(); - }); } return true; } @@ -410,7 +294,7 @@ */ @Override public void syncStateChanged() { - updateSyncPreferences(); + updatePreferences(); } /** Returns whether Sync can be disabled. */ @@ -418,121 +302,11 @@ return !Profile.getLastUsedProfile().isChild(); } - private boolean isSyncTypePreference(Preference preference) { - for (Preference pref : mSyncAllTypes) { - if (pref == preference) return true; - } - return false; - } - - /** - * Update the state of all settings from sync. - * - * This sets the state of the sync switch from external sync state and then calls - * updateSyncPreferences, which uses that as its source of truth. - */ - private void updateSyncStateFromAndroidSyncSettings() { - updateSyncPreferences(); - } - - /** Update sync preferences. */ - private void updateSyncPreferences() { - updateDataTypeState(); - updateEncryptionState(); - updateSyncErrorCard(); - } - - /** Enables sync if any of the data types is selected, otherwise disables sync. */ - private void updateSyncStateFromSelectedModelTypes() { - boolean shouldEnableSync = UnifiedConsentServiceBridge.isUnifiedConsentGiven() - || !getSelectedModelTypes().isEmpty() || !canDisableSync(); - SyncPreferenceUtils.enableSync(shouldEnableSync); - updateSyncPreferences(); - } - - /** - * Update the encryption state. - * - * If sync's engine is initialized, the button is enabled and the dialog will present the - * valid encryption options for the user. Otherwise, any encryption dialogs will be closed - * and the button will be disabled because the engine is needed in order to know and - * modify the encryption state. - */ - private void updateEncryptionState() { - boolean isEngineInitialized = mProfileSyncService.isEngineInitialized(); - mSyncEncryption.setEnabled(isEngineInitialized); - mSyncEncryption.setSummary(null); - if (!isEngineInitialized) { - // If sync is not initialized, encryption state is unavailable and can't be changed. - // Leave the button disabled and the summary empty. Additionally, close the dialogs in - // case they were open when a stop and clear comes. - closeDialogIfOpen(FRAGMENT_CUSTOM_PASSPHRASE); - closeDialogIfOpen(FRAGMENT_ENTER_PASSPHRASE); - return; - } - if (!mProfileSyncService.isPassphraseRequiredForDecryption()) { - closeDialogIfOpen(FRAGMENT_ENTER_PASSPHRASE); - } - if (mProfileSyncService.isPassphraseRequiredForDecryption() && isAdded()) { - mSyncEncryption.setSummary( - errorSummary(getString(R.string.sync_need_passphrase), getActivity())); - } - } - - /** Applies a span to the given string to give it an error color. */ - private static Spannable errorSummary(String string, Context context) { - SpannableString summary = new SpannableString(string); - summary.setSpan(new ForegroundColorSpan(ApiCompatibilityUtils.getColor( - context.getResources(), R.color.input_underline_error_color)), - 0, summary.length(), 0); - return summary; - } - - private void configureSyncDataTypes() { - updateSyncStateFromSelectedModelTypes(); - if (!mProfileSyncService.isSyncRequested()) return; - - boolean syncEverything = UnifiedConsentServiceBridge.isUnifiedConsentGiven(); - mProfileSyncService.setChosenDataTypes(syncEverything, getSelectedModelTypes()); - // Update the invalidation listener with the set of types we are enabling. - InvalidationController invController = InvalidationController.get(); - invController.ensureStartedAndUpdateRegisteredTypes(); - } - - private Set<Integer> getSelectedModelTypes() { - Set<Integer> types = new HashSet<>(); - if (mSyncAutofill.isChecked()) types.add(ModelType.AUTOFILL); - if (mSyncBookmarks.isChecked()) types.add(ModelType.BOOKMARKS); - if (mSyncHistory.isChecked()) types.add(ModelType.TYPED_URLS); - if (mSyncPasswords.isChecked()) types.add(ModelType.PASSWORDS); - if (mSyncRecentTabs.isChecked()) types.add(ModelType.PROXY_TABS); - if (mSyncSettings.isChecked()) types.add(ModelType.PREFERENCES); - if (mSyncActivityAndInteractions.isChecked()) types.add(ModelType.USER_EVENTS); - return types; - } - - private void displayPassphraseTypeDialog() { - FragmentTransaction ft = getFragmentManager().beginTransaction(); - PassphraseTypeDialogFragment dialog = - PassphraseTypeDialogFragment.create(mProfileSyncService.getPassphraseType(), - mProfileSyncService.getExplicitPassphraseTime(), - mProfileSyncService.isEncryptEverythingAllowed()); - dialog.show(ft, FRAGMENT_PASSPHRASE_TYPE); - dialog.setTargetFragment(this, -1); - } - private void displayPassphraseDialog() { FragmentTransaction ft = getFragmentManager().beginTransaction(); PassphraseDialogFragment.newInstance(this).show(ft, FRAGMENT_ENTER_PASSPHRASE); } - private void displayCustomPassphraseDialog() { - FragmentTransaction ft = getFragmentManager().beginTransaction(); - PassphraseCreationDialogFragment dialog = new PassphraseCreationDialogFragment(); - dialog.setTargetFragment(this, -1); - dialog.show(ft, FRAGMENT_CUSTOM_PASSPHRASE); - } - private void closeDialogIfOpen(String tag) { FragmentManager manager = getFragmentManager(); if (manager == null) { @@ -550,12 +324,7 @@ if (passphrase.isEmpty() || !mProfileSyncService.setDecryptionPassphrase(passphrase)) { return false; } - // PassphraseDialogFragment doesn't handle closing itself, so do it here. This is not done - // in updateSyncStateFromAndroidSyncSettings() because that happens onResume and possibly in - // other cases where the dialog should stay open. - closeDialogIfOpen(FRAGMENT_ENTER_PASSPHRASE); - // Update our configuration UI. - updateSyncStateFromAndroidSyncSettings(); + updatePreferences(); return true; } @@ -575,127 +344,6 @@ @Override public void onPassphraseCanceled() {} - /** Callback for PassphraseCreationDialogFragment.Listener */ - @Override - public void onPassphraseCreated(String passphrase) { - if (!mProfileSyncService.isEngineInitialized()) { - // If the engine was shut down since the dialog was opened, do nothing. - return; - } - mProfileSyncService.enableEncryptEverything(); - mProfileSyncService.setEncryptionPassphrase(passphrase); - // Configure the current set of data types - this tells the sync engine to - // apply our encryption configuration changes. - configureSyncDataTypes(); - // Re-display our config UI to properly reflect the new state. - updateSyncStateFromAndroidSyncSettings(); - } - - /** Callback for PassphraseTypeDialogFragment.Listener */ - @Override - public void onPassphraseTypeSelected(PassphraseType type) { - if (!mProfileSyncService.isEngineInitialized()) { - // If the engine was shut down since the dialog was opened, do nothing. - return; - } - - boolean isAllDataEncrypted = mProfileSyncService.isEncryptEverythingEnabled(); - boolean isUsingSecondaryPassphrase = mProfileSyncService.isUsingSecondaryPassphrase(); - - // The passphrase type should only ever be selected if the account doesn't have - // full encryption enabled. Otherwise both options should be disabled. - assert !isAllDataEncrypted; - assert !isUsingSecondaryPassphrase; - displayCustomPassphraseDialog(); - } - - private void onGoogleActivityControlsClicked(String signedInAccountName) { - AppHooks.get().createGoogleActivityController().openWebAndAppActivitySettings( - getActivity(), signedInAccountName); - RecordUserAction.record("Signin_AccountSettings_GoogleActivityControlsClicked"); - } - - private void onSyncEncryptionClicked() { - if (!mProfileSyncService.isEngineInitialized()) return; - - if (mProfileSyncService.isPassphraseRequiredForDecryption()) { - displayPassphraseDialog(); - } else { - displayPassphraseTypeDialog(); - } - } - - /** Opens the Google Dashboard where the user can control the data stored for the account. */ - private void openDashboardTabInNewActivityStack() { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(DASHBOARD_URL)); - intent.setPackage(getActivity().getPackageName()); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - } - - /** - * Update the data type switch state. - * - * If sync is on, load the prefs from native. Otherwise, all data types are disabled and - * checked. Note that the Password data type will be shown as disabled and unchecked between - * sync being turned on and the engine initialization completing. - */ - private void updateDataTypeState() { - boolean syncEverything = UnifiedConsentServiceBridge.isUnifiedConsentGiven(); - if (syncEverything) { - for (CheckBoxPreference pref : mSyncAllTypes) { - pref.setChecked(true); - pref.setEnabled(false); - } - return; - } - - Set<Integer> syncTypes = mProfileSyncService.isSyncRequested() - ? mProfileSyncService.getChosenDataTypes() - : new ArraySet<>(); - mSyncAutofill.setChecked(syncTypes.contains(ModelType.AUTOFILL)); - mSyncAutofill.setEnabled(true); - mSyncBookmarks.setChecked(syncTypes.contains(ModelType.BOOKMARKS)); - mSyncBookmarks.setEnabled(true); - mSyncHistory.setChecked(syncTypes.contains(ModelType.TYPED_URLS)); - mSyncHistory.setEnabled(true); - mSyncPasswords.setChecked(syncTypes.contains(ModelType.PASSWORDS)); - mSyncPasswords.setEnabled(true); - mSyncRecentTabs.setChecked(syncTypes.contains(ModelType.PROXY_TABS)); - mSyncRecentTabs.setEnabled(true); - mSyncSettings.setChecked(syncTypes.contains(ModelType.PREFERENCES)); - mSyncSettings.setEnabled(true); - - // Payments integration requires AUTOFILL model type - boolean syncAutofill = syncTypes.contains(ModelType.AUTOFILL); - mSyncPaymentsIntegration.setChecked( - syncAutofill && PersonalDataManager.isPaymentsIntegrationEnabled()); - mSyncPaymentsIntegration.setEnabled(syncAutofill); - - // USER_EVENTS sync type doesn't work with custom passphrase and needs history sync - boolean userEventsConfigurable = - !hasCustomPassphrase() && syncTypes.contains(ModelType.TYPED_URLS); - mSyncActivityAndInteractions.setChecked( - userEventsConfigurable && syncTypes.contains(ModelType.USER_EVENTS)); - mSyncActivityAndInteractions.setEnabled(userEventsConfigurable); - } - - private boolean hasCustomPassphrase() { - return mProfileSyncService.isEngineInitialized() - && mProfileSyncService.getPassphraseType() == PassphraseType.CUSTOM_PASSPHRASE; - } - - private void updateSyncErrorCard() { - mCurrentSyncError = getSyncError(); - if (mCurrentSyncError == SyncError.NO_ERROR) { - mSyncCategory.removePreference(mSyncErrorCard); - } else { - String summary = getSyncErrorHint(mCurrentSyncError); - mSyncErrorCard.setSummary(summary); - mSyncCategory.addPreference(mSyncErrorCard); - } - } - @SyncError private int getSyncError() { if (!AndroidSyncSettings.get().isMasterSyncEnabled()) { @@ -803,37 +451,18 @@ } private void updatePreferences() { - boolean useSyncAndAllServices = UnifiedConsentServiceBridge.isUnifiedConsentGiven(); - String signedInAccountName = ChromeSigninController.get().getSignedInAccountName(); - if (signedInAccountName != null) { - getPreferenceScreen().addPreference(mSyncCategory); - - mUseSyncAndAllServices.setChecked(useSyncAndAllServices); - mUseSyncAndAllServices.setEnabled(!hasCustomPassphrase()); - - mGoogleActivityControls.setOnPreferenceClickListener( - toOnClickListener(() -> onGoogleActivityControlsClicked(signedInAccountName))); - } else { - getPreferenceScreen().removePreference(mSyncCategory); - } + updateSyncPreferences(); mSearchSuggestions.setChecked(mPrefServiceBridge.isSearchSuggestEnabled()); - mSearchSuggestions.setEnabled(!useSyncAndAllServices); mNetworkPredictions.setChecked(mPrefServiceBridge.getNetworkPredictionEnabled()); - mNetworkPredictions.setEnabled(!useSyncAndAllServices); mNavigationError.setChecked(mPrefServiceBridge.isResolveNavigationErrorEnabled()); - mNavigationError.setEnabled(!useSyncAndAllServices); mSafeBrowsing.setChecked(mPrefServiceBridge.isSafeBrowsingEnabled()); - mSafeBrowsing.setEnabled(!useSyncAndAllServices); mSafeBrowsingReporting.setChecked( mPrefServiceBridge.isSafeBrowsingExtendedReportingEnabled()); - mSafeBrowsingReporting.setEnabled(!useSyncAndAllServices); mUsageAndCrashReporting.setChecked( mPrivacyPrefManager.isUsageAndCrashReportingPermittedByUser()); - mUsageAndCrashReporting.setEnabled(!useSyncAndAllServices); mUrlKeyedAnonymizedData.setChecked( UnifiedConsentServiceBridge.isUrlKeyedAnonymizedDataCollectionEnabled()); - mUrlKeyedAnonymizedData.setEnabled(!useSyncAndAllServices); if (mContextualSearch != null) { boolean isContextualSearchEnabled = !mPrefServiceBridge.isContextualSearchDisabled(); @@ -848,6 +477,31 @@ } } + private void updateSyncPreferences() { + if (!mProfileSyncService.isEngineInitialized() + || !mProfileSyncService.isPassphraseRequiredForDecryption()) { + closeDialogIfOpen(FRAGMENT_ENTER_PASSPHRASE); + } + + if (!ChromeSigninController.get().isSignedIn()) { + getPreferenceScreen().removePreference(mSyncCategory); + return; + } + getPreferenceScreen().addPreference(mSyncCategory); + + mCurrentSyncError = getSyncError(); + if (mCurrentSyncError == SyncError.NO_ERROR) { + mSyncCategory.removePreference(mSyncErrorCard); + } else { + String summary = getSyncErrorHint(mCurrentSyncError); + mSyncErrorCard.setSummary(summary); + mSyncCategory.addPreference(mSyncErrorCard); + } + + mSyncRequested.setChecked(AndroidSyncSettings.get().isChromeSyncEnabled()); + mSyncRequested.setEnabled(canDisableSync()); + } + private ManagedPreferenceDelegate createManagedPreferenceDelegate() { return preference -> { String key = preference.getKey();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreferenceUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreferenceUtils.java index 4b1cf283..978c2ad 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreferenceUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreferenceUtils.java
@@ -5,6 +5,8 @@ import android.content.Context; import android.content.res.Resources; +import android.preference.Preference; +import android.preference.PreferenceFragment; import org.chromium.base.BuildInfo; import org.chromium.base.metrics.RecordHistogram; @@ -118,4 +120,24 @@ profileSyncService.requestStop(); } } + + /** + * Creates a wrapper around {@link Runnable} that calls the runnable only if + * {@link PreferenceFragment} is still in resumed state. Click events that arrive after the + * fragment has been paused will be ignored. See http://b/5983282. + * @param fragment The fragment that hosts the preference. + * @param runnable The runnable to call from {@link Preference.OnPreferenceClickListener}. + */ + static Preference.OnPreferenceClickListener toOnClickListener( + PreferenceFragment fragment, Runnable runnable) { + return preference -> { + if (!fragment.isResumed()) { + // This event could come in after onPause if the user clicks back and the preference + // at roughly the same time. See http://b/5983282. + return false; + } + runnable.run(); + return false; + }; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java index e251dc89..c5f5425ee 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -1527,7 +1527,7 @@ return true; } return !(mTabSwitcherState == TAB_SWITCHER || mTabSwitcherModeAnimation != null - || urlHasFocus() || mUrlFocusChangeInProgress); + || urlHasFocus() || mUrlFocusChangeInProgress || mNtpSearchBoxScrollPercent > 0); } @Override @@ -1676,6 +1676,7 @@ // Request a texture update to ensure a texture is captured before the user // re-enters the tab switcher. + postInvalidate(); mLayoutUpdateHost.requestUpdate(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java index 008b16e..6aa21a5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java
@@ -89,6 +89,9 @@ @VisibleForTesting public static void setAlwaysUseFallbackDelegate(boolean useFallbackDelegate) { + // TODO(bsheedy): Change this to an "assert sDelegateProvider == null" once we change the + // restriction checking code to use the Daydream API directly so that a delegate provider + // doesn't get created during pre-test setup. sDelegateProvider = null; sAlwaysUseFallbackDelegate = useFallbackDelegate; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameActivityWebappSplashDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameActivityWebappSplashDelegate.java index 62b153a..4d19a75 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameActivityWebappSplashDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameActivityWebappSplashDelegate.java
@@ -38,9 +38,6 @@ /** Whether native was loaded. Native must be loaded in order to record metrics. */ private boolean mNativeLoaded; - /** Whether the splash screen layout was initialized. */ - private boolean mInitializedLayout; - private SameActivityWebappUmaCache mUmaCache; private WebApkOfflineDialog mOfflineDialog; @@ -73,7 +70,6 @@ @Override public void showSplash(ViewGroup parentView, WebappInfo webappInfo) { mParentView = parentView; - mUmaCache = new SameActivityWebappUmaCache(); mIsSplashVisible = true; Context context = ContextUtils.getApplicationContext(); @@ -108,7 +104,7 @@ @Override public void onNativeLoaded() { mNativeLoaded = true; - if (mInitializedLayout) mUmaCache.commitMetrics(); + if (mUmaCache != null) mUmaCache.commitMetrics(); } @Override @@ -157,7 +153,6 @@ /** Sets the splash screen layout and sets the splash screen's title and icon. */ private void initializeLayout(WebappInfo webappInfo, int backgroundColor, Bitmap splashImage) { - mInitializedLayout = true; Context context = ContextUtils.getApplicationContext(); Resources resources = context.getResources(); @@ -193,6 +188,7 @@ private void recordUma(Resources resources, WebappInfo webappInfo, @SplashLayout.IconClassification int selectedIconClassification, Bitmap selectedIcon, boolean usingDedicatedIcon) { + mUmaCache = new SameActivityWebappUmaCache(); mUmaCache.recordSplashscreenBackgroundColor(webappInfo.hasValidBackgroundColor() ? SameActivityWebappUmaCache.SplashColorStatus.CUSTOM : SameActivityWebappUmaCache.SplashColorStatus.DEFAULT);
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 6d21a3a..34ec87af 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -340,12 +340,15 @@ <message name="IDS_SIGN_OUT_AND_TURN_OFF_SYNC" desc="The text for a preferences row that for signs out the user and turns off sync."> Sign out and turn off sync </message> - <message name="IDS_USE_SYNC_AND_ALL_SERVICES" desc="Title for switch preference which enables sync'ing of all data types and turns on all Chrome services that communicate with Google."> - Use sync and all services - </message> <message name="IDS_SYNC_CATEGORY_TITLE" desc="Title for the group of Sync-related entries in Settings. This group contains preferences for data tied to user's Google Account."> Sync </message> + <message name="IDS_SYNC_SWITCH_TITLE" desc="Title for the switch preference that enables sync. Displayed in 'Sync and Google services' screen."> + Sync your Chrome data + </message> + <message name="IDS_MANAGE_SYNC_TITLE" desc="Title for the preference row that opens the screen that allows configuring separate data types. Displayed in 'Sync and Google services' screen."> + Manage sync + </message> <message name="IDS_SERVICES_CATEGORY_TITLE" desc="Title for the group of preferences that control non-personalized Google services. This group contains preferences for data that is not tied to user's Google Account."> Other Google services </message> @@ -1214,10 +1217,16 @@ Revoke device permission </message> - <!-- Data Saver --> + <!-- Data Saver and Lite Mode--> + <message name="IDS_DATA_SAVER_IPH_REBRAND_LITE_MODE" desc="An onscreen notification to the user that the Chrome feature previously named 'Data Saver' is now named 'Lite mode'."> + Data Saver is now Lite mode + </message> <message name="IDS_DATA_REDUCTION_TITLE" desc="Menu item for Data Saver, which allows users to save mobile data by compressing network traffic."> Data Saver </message> + <message name="IDS_DATA_REDUCTION_TITLE_LITE_MODE" desc="Menu item for Lite mode, which allows users to save mobile data by compressing network traffic."> + Lite mode + </message> <message name="IDS_DATA_REDUCTION_INITIAL_TITLE" desc="This title states that the below chart will contain the user's data savings after they have started browsing."> Your data savings will appear here </message> @@ -1230,12 +1239,21 @@ <message name="IDS_DATA_REDUCTION_BENEFITS_DESCRIPTION" desc="Description text about the benefits of the Data Saver feature. Seen only before the user has enabled the feature."> Use up to 60 percent less data and speed up the web. </message> + <message name="IDS_DATA_REDUCTION_BENEFITS_DESCRIPTION_LITE_MODE" desc="Description text about the benefits of the Data Saver feature. Seen only before the user has enabled the feature."> + In Lite mode, Chrome loads pages faster and uses up to 60 percent less data. + </message> <message name="IDS_DATA_REDUCTION_DESCRIPTION" desc="Text descripting how the Data Saver feature works. Seen only before the user has enabled the feature."> When Data Saver is turned on, Chrome uses Google servers to speed up and compress page loads. On especially slow pages, Data Saver rewrites the page to load only the essential content. Data Saver does not optimize pages loaded in Incognito mode. </message> + <message name="IDS_DATA_REDUCTION_DESCRIPTION_LITE_MODE" desc="Text describing how the Lite mode feature works. Seen only before the user has enabled the feature."> + When Lite mode is on, Chrome uses Google servers to make pages load faster. Lite mode rewrites very slow pages to load only essential content. Lite mode does not apply to Incognito tabs. + </message> <message name="IDS_DATA_REDUCTION_MENU_ITEM_SUMMARY" desc="Summary text for data reduction menu item."> <ph name="PERCENT">%1$s<ex>49%</ex></ph> data savings </message> + <message name="IDS_DATA_REDUCTION_MENU_ITEM_SUMMARY_LITE_MODE" desc="Label that states the percent of mobile data that was saved by Lite mode. Lite mode allows users to to reduce their mobile data usage by compressing network traffic."> + <ph name="PERCENT">%1$s<ex>49%</ex></ph> data savings + </message> <message name="IDS_DATA_REDUCTION_SAVINGS_LABEL" desc="Data Reduction statistics label that states the amount of mobile data that was saved by Data Saver. Data Saver allows users to to reduce their mobile data usage by compressing network traffic."> data saved </message> @@ -1293,32 +1311,56 @@ <message name="IDS_DATA_REDUCTION_USAGE_RESET_STATISTICS_CONFIRMATION_TITLE" desc="Text to be displayed on the confirmation dialog to reset the Data Reduction statistics."> Reset Data Saver? </message> + <message name="IDS_DATA_REDUCTION_USAGE_RESET_STATISTICS_CONFIRMATION_TITLE_LITE_MODE" desc="Text to be displayed on the confirmation dialog to reset the user's history of data savings."> + Reset Lite mode? + </message> <message name="IDS_DATA_REDUCTION_USAGE_RESET_STATISTICS_CONFIRMATION_DIALOG" desc="Text to be displayed on the confirmation dialog to reset the Data Reduction statistics."> Resetting erases Data Saver history, including the list of visited sites. </message> - <message name="IDS_DATA_REDUCTION_USAGE_RESET_STATISTICS_CONFIRMATION_BUTTON" desc="Text to be displayed on the confirmation button to proceed with resetting the Data Reduction statistics."> + <message name="IDS_DATA_REDUCTION_USAGE_RESET_STATISTICS_CONFIRMATION_DIALOG_LITE_MODE" desc="Text to be displayed on the confirmation dialog to reset the user's history of data savings."> + Resetting erases your history of data savings, including the list of visited sites. + </message> + <message name="IDS_DATA_REDUCTION_USAGE_RESET_STATISTICS_CONFIRMATION_BUTTON" desc="Text to be displayed on the confirmation button to proceed with resetting the history of data savings."> Reset </message> - <!-- Data Saver Promo and FRE card --> + <!-- Data Saver or Lite Mode Promo and FRE card --> <message name="IDS_DATA_REDUCTION_PROMO_TITLE" desc="The title for the promo inviting users to enable Data Saver" > Save data and browse faster </message> + <message name="IDS_DATA_REDUCTION_PROMO_TITLE_LITE_MODE" desc="The title for the promo inviting users to enable Lite mode" > + Browse faster. Use less data. + </message> <message name="IDS_DATA_REDUCTION_PROMO_SUMMARY" desc="Description for the promo inviting users to enable Data Saver" > Use up to 60 percent less data and speed up the web. Google servers will optimize the pages you visit. </message> + <message name="IDS_DATA_REDUCTION_PROMO_SUMMARY_LITE_MODE" desc="Description for the promo inviting users to enable Lite mode" > + In Lite mode, Chrome loads pages faster and uses up to 60 percent less data. Google's cloud technology optimizes the pages you visit. + </message> <message name="IDS_DATA_REDUCTION_ENABLE_BUTTON" desc="Button the user presses if they want to enable Data Saver" > Turn on Data Saver </message> + <message name="IDS_DATA_REDUCTION_ENABLE_BUTTON_LITE_MODE" desc="Button the user presses if they want to enable Lite mode" > + Turn on Lite mode + </message> <message name="IDS_DATA_REDUCTION_ENABLED_SWITCH" desc="Message to show when the Data Saver feature is enabled via the switch on the First Run Experience card" > Data Saver is on </message> + <message name="IDS_DATA_REDUCTION_ENABLED_SWITCH_LITE_MODE" desc="Message to show when the Lite mode feature is enabled via the switch on the First Run Experience card" > + Lite mode is on + </message> <message name="IDS_DATA_REDUCTION_DISABLED_SWITCH" desc="Message to show when the Data Saver feature is disabled via the switch on the First Run Experience card" > Data Saver is off </message> + <message name="IDS_DATA_REDUCTION_DISABLED_SWITCH_LITE_MODE" desc="Message to show when the Lite mode feature is disabled via the switch on the First Run Experience card" > + Lite mode is off + </message> <message name="IDS_DATA_REDUCTION_ENABLED_TOAST" desc="Toast message displayed after the user enables Data Saver from the promo" > Data Saver is on. Manage it in Settings. </message> + <message name="IDS_DATA_REDUCTION_ENABLED_TOAST_LITE_MODE" desc="Toast message displayed after the user enables Lite mode from the promo" > + Lite mode is on. Manage it in Settings. + </message> <message name="IDS_DATA_REDUCTION_PROMO_INFOBAR_TITLE" desc="Text to be displayed in the data reduction promo infobar title"> Save up to 60% of your data </message> @@ -1626,12 +1668,6 @@ <message name="IDS_SYNC_PAYMENTS_INTEGRATION" desc="Title for preference which enables import of Google Pay data for Autofill. 'Google Pay' should not be translated as it is the product name."> Credit cards and addresses using Google Pay </message> - <message name="IDS_SYNC_ACTIVITY_AND_INTERACTIONS_TITLE" desc="Title for preference which enables sync'ing of activity and interactions."> - Activity and interactions - </message> - <message name="IDS_SYNC_ACTIVITY_AND_INTERACTIONS_SUMMARY" desc="Summary for preference which enables sync'ing of activity and interactions."> - Uses content on sites you visit, plus browser activity and interactions, for personalization - </message> <message name="IDS_SYNC_ENCRYPTION" desc="Preference category name for sync encryption. [CHAR-LIMT=32]"> Encryption </message>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index dafaf41..d98a9c4 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -154,10 +154,11 @@ "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java", "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetails.java", "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsCoordinator.java", + "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsModel.java", + "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsViewBinder.java", "java/src/org/chromium/chrome/browser/autofill_assistant/header/AnimatedProgressBar.java", "java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java", "java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderDelegate.java", - "java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderMediator.java", "java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderModel.java", "java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderViewBinder.java", "java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java", @@ -490,6 +491,7 @@ "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleConstants.java", "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleCoordinator.java", "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleNavigationEventObserver.java", + "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModulePageLoadObserver.java", "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleEntryPoint.java", "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleHostImpl.java", "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleLoader.java", @@ -1291,6 +1293,7 @@ "java/src/org/chromium/chrome/browser/preferences/MainPreferences.java", "java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegate.java", "java/src/org/chromium/chrome/browser/preferences/ManagedPreferencesUtils.java", + "java/src/org/chromium/chrome/browser/preferences/ManageSyncPreferences.java", "java/src/org/chromium/chrome/browser/preferences/NotificationsPreferences.java", "java/src/org/chromium/chrome/browser/preferences/PrefChangeRegistrar.java", "java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java", @@ -2017,6 +2020,7 @@ "javatests/src/org/chromium/chrome/browser/download/SystemDownloadNotifierTest.java", "javatests/src/org/chromium/chrome/browser/download/TestDownloadDirectoryProvider.java", "javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java", + "javatests/src/org/chromium/chrome/browser/download/home/StubbedOfflineContentProvider.java", "javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java", "javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java", "javatests/src/org/chromium/chrome/browser/engagement/SiteEngagementServiceTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java index a490f32..f006648 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
@@ -33,6 +33,7 @@ import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChip; import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChipType; import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetails; +import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetailsModel; import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderModel; import org.chromium.chrome.browser.customtabs.CustomTabActivity; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; @@ -126,8 +127,8 @@ String testStatusMessage = "test message"; ThreadUtils.runOnUiThreadBlocking( () - -> assistantCoordinator.getHeaderCoordinator().setStatusMessage( - testStatusMessage)); + -> assistantCoordinator.getModel().getHeaderModel().set( + AssistantHeaderModel.STATUS_MESSAGE, testStatusMessage)); TextView statusMessageView = bottomSheet.findViewById(R.id.status_message); Assert.assertEquals(statusMessageView.getText(), testStatusMessage); @@ -146,7 +147,8 @@ () -> assistantCoordinator.getModel().getCarouselModel().getChipsModel().set( chips)); - RecyclerView chipsViewContainer = assistantCoordinator.getCarouselCoordinator().getView(); + RecyclerView chipsViewContainer = + assistantCoordinator.getBottomBarCoordinator().getCarouselCoordinator().getView(); Assert.assertEquals(2, chipsViewContainer.getAdapter().getItemCount()); // Choose the second chip. @@ -157,15 +159,17 @@ // Show movie details. String movieTitle = "testTitle"; String movieDescription = "This is a fancy test movie"; - ThreadUtils.runOnUiThreadBlocking(() -> { - assistantCoordinator.getDetailsCoordinator().showDetails(new AssistantDetails( - movieTitle, /* url = */ "", Calendar.getInstance().getTime(), movieDescription, - /* mId = */ "", - /* price = */ null, - /* userApprovalRequired= */ false, - /* highlightTitle= */ false, /* highlightDate= */ - false, /* showPlaceholdersForEmptyFields= */ false)); - }); + ThreadUtils.runOnUiThreadBlocking( + () + -> assistantCoordinator.getModel().getDetailsModel().set( + AssistantDetailsModel.DETAILS, + new AssistantDetails(movieTitle, /* url = */ "", + Calendar.getInstance().getTime(), movieDescription, + /* mId = */ "", + /* price = */ null, + /* userApprovalRequired= */ false, + /* highlightTitle= */ false, /* highlightDate= */ + false, /* showPlaceholdersForEmptyFields= */ false))); TextView detailsTitle = (TextView) bottomSheet.findViewById(R.id.details_title); TextView detailsText = (TextView) bottomSheet.findViewById(R.id.details_text); Assert.assertEquals(detailsTitle.getText(), movieTitle);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleNavigationTest.java index f4d4c7b..59cf764 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleNavigationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleNavigationTest.java
@@ -122,6 +122,7 @@ 0, 3); activityDelegate.waitForNavigationEvent(CustomTabsCallback.NAVIGATION_FINISHED, 0, 3); + activityDelegate.waitForFirstContentfulPaint(0, 3); } private CustomTabActivity getActivity() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleTestUtils.java index c93167d4..bf9158c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleTestUtils.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleTestUtils.java
@@ -9,6 +9,8 @@ import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.EXTRA_MODULE_MANAGED_URLS_HEADER_VALUE; import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.EXTRA_MODULE_MANAGED_URLS_REGEX; import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.EXTRA_MODULE_PACKAGE_NAME; +import static org.chromium.chrome.browser.customtabs.dynamicmodule.DynamicModuleConstants.ON_NAVIGATION_EVENT_MODULE_API_VERSION; +import static org.chromium.chrome.browser.customtabs.dynamicmodule.DynamicModuleConstants.ON_PAGE_LOAD_METRIC_API_VERSION; import static org.chromium.chrome.browser.customtabs.dynamicmodule.DynamicModuleNavigationEventObserver.PENDING_URL_KEY; import static org.chromium.chrome.browser.customtabs.dynamicmodule.DynamicModuleNavigationEventObserver.URL_KEY; @@ -16,6 +18,7 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.SystemClock; import android.support.annotation.Nullable; import android.support.customtabs.CustomTabsCallback; import android.support.test.InstrumentationRegistry; @@ -27,6 +30,7 @@ import org.chromium.chrome.browser.AppHooksModule; import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.externalauth.ExternalAuthUtils; +import org.chromium.chrome.browser.metrics.PageLoadMetrics; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -117,6 +121,7 @@ public static class FakeCCTActivityDelegate extends BaseActivityDelegate { private final CallbackHelper mOnNavigationStarted = new CallbackHelper(); private final CallbackHelper mOnNavigationFinished = new CallbackHelper(); + private final CallbackHelper mOnFirstContentfulPaint = new CallbackHelper(); public FakeCCTActivityDelegate() { } @@ -180,9 +185,10 @@ @Override public void onNavigationEvent(int navigationEvent, Bundle extras) { - // Introduced in API version 4. - if (sModuleVersion < 4) { - Assert.fail("onNavigationEvent must not be used if module version less than 4"); + if (sModuleVersion < ON_NAVIGATION_EVENT_MODULE_API_VERSION) { + Assert.fail(String.format( + "onNavigationEvent must not be used if module version less than %d", + ON_NAVIGATION_EVENT_MODULE_API_VERSION)); } if (navigationEvent == CustomTabsCallback.NAVIGATION_STARTED) { @@ -194,18 +200,44 @@ } } + @Override + public void onPageMetricEvent(String metricName, long navigationStart, + long offset, long navigationId) { + if (sModuleVersion < ON_PAGE_LOAD_METRIC_API_VERSION) { + Assert.fail(String.format( + "onPageMetricEvent must not be used if module version less than %d", + ON_PAGE_LOAD_METRIC_API_VERSION)); + } + + long current = SystemClock.uptimeMillis(); + Assert.assertTrue(navigationStart <= current); + Assert.assertTrue(offset <= (current - navigationStart)); + + if (PageLoadMetrics.FIRST_CONTENTFUL_PAINT.equals(metricName)) { + mOnFirstContentfulPaint.notifyCalled(); + } + } + /** * Waits for expected number of navigation events happen. */ /* package */ void waitForNavigationEvent(int navigationEvent, int currentCallCount, int numberOfCallsToWaitFor) throws TimeoutException, InterruptedException { - if (sModuleVersion < 4) return; + if (sModuleVersion < ON_NAVIGATION_EVENT_MODULE_API_VERSION) return; + if (navigationEvent == CustomTabsCallback.NAVIGATION_STARTED) { mOnNavigationStarted.waitForCallback(currentCallCount, numberOfCallsToWaitFor); } else if (navigationEvent == CustomTabsCallback.NAVIGATION_FINISHED) { mOnNavigationFinished.waitForCallback(currentCallCount, numberOfCallsToWaitFor); } } + + /* package */ void waitForFirstContentfulPaint(int currentCallCount, + int numberOfCallsToWaitFor) throws TimeoutException, InterruptedException { + if (sModuleVersion < ON_PAGE_LOAD_METRIC_API_VERSION) return; + + mOnFirstContentfulPaint.waitForCallback(currentCallCount, numberOfCallsToWaitFor); + } } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleUITest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleUITest.java index 4b1b23d..015b870 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleUITest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleUITest.java
@@ -465,6 +465,27 @@ @Test @SmallTest + @Features.EnableFeatures({ + ChromeFeatureList.CCT_MODULE, ChromeFeatureList.CCT_MODULE_CUSTOM_HEADER, + ChromeFeatureList.CCT_MODULE_USE_INTENT_EXTRAS}) + public void testSetTopBarHeight_zeroHeightHidesTopBar() throws Exception { + Intent intent = new IntentBuilder(mModuleManagedPage) + .setModuleManagedUrlRegex(getModuleManagedRegex()) + .build(); + mActivityRule.startCustomTabActivityWithIntent(intent); + waitForModuleLoading(); + + runOnUiThreadBlocking(() -> { + CustomTabActivity cctActivity = getActivity(); + View anyView = new View(cctActivity); + getModuleCoordinator().setTopBarContentView(anyView); + getModuleCoordinator().setTopBarHeight(0); + assertEquals(View.GONE, anyView.getVisibility()); + }); + } + + @Test + @SmallTest @Features.EnableFeatures(ChromeFeatureList.CCT_MODULE_USE_INTENT_EXTRAS) @Features.DisableFeatures(ChromeFeatureList.CCT_MODULE_CUSTOM_HEADER) public void testSetTopBarContentView_featureDisabled_progressBarNoChange() throws Exception {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java index 3e342e9..9d05052d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java
@@ -64,20 +64,20 @@ public void setUpTest() throws Exception { super.setUpTest(); MockitoAnnotations.initMocks(this); - // TODO(yliuyliu): Write a new StubbedOfflineContentProvider for new Download UI testing. - StubbedProvider stubbedProvider = new StubbedProvider(); + StubbedOfflineContentProvider stubbedOfflineContentProvider = + new StubbedOfflineContentProvider(); OfflineContentAggregatorFactory.setOfflineContentProviderForTests( - stubbedProvider.getOfflineContentProvider()); + stubbedOfflineContentProvider); OfflineItem item0 = StubbedProvider.createOfflineItem(0, "20151019 07:26"); OfflineItem item1 = StubbedProvider.createOfflineItem(1, "20151020 07:27"); OfflineItem item2 = StubbedProvider.createOfflineItem(2, "20151021 07:28"); OfflineItem item3 = StubbedProvider.createOfflineItem(3, "20151021 07:29"); - stubbedProvider.getOfflineContentProvider().items.add(item0); - stubbedProvider.getOfflineContentProvider().items.add(item1); - stubbedProvider.getOfflineContentProvider().items.add(item2); - stubbedProvider.getOfflineContentProvider().items.add(item3); + stubbedOfflineContentProvider.addItem(item0); + stubbedOfflineContentProvider.addItem(item1); + stubbedOfflineContentProvider.addItem(item2); + stubbedOfflineContentProvider.addItem(item3); TrackerFactory.setTrackerForTests(mTracker);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/StubbedOfflineContentProvider.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/StubbedOfflineContentProvider.java new file mode 100644 index 0000000..ac9d13d3 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/StubbedOfflineContentProvider.java
@@ -0,0 +1,111 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.download.home; + +import static junit.framework.Assert.assertEquals; + +import android.os.Handler; +import android.os.Looper; + +import org.chromium.base.Callback; +import org.chromium.base.test.util.CallbackHelper; +import org.chromium.components.offline_items_collection.ContentId; +import org.chromium.components.offline_items_collection.LaunchLocation; +import org.chromium.components.offline_items_collection.OfflineContentProvider; +import org.chromium.components.offline_items_collection.OfflineItem; +import org.chromium.components.offline_items_collection.ShareCallback; +import org.chromium.components.offline_items_collection.VisualsCallback; + +import java.util.ArrayList; + +/** Stubs out the OfflineContentProvider. */ +public class StubbedOfflineContentProvider implements OfflineContentProvider { + private final Handler mHandler; + private final CallbackHelper mAddObserverCallback; + private final CallbackHelper mRemoveObserverCallback; + private final CallbackHelper mDeleteItemCallback; + private final ArrayList<OfflineItem> mItems; + private OfflineContentProvider.Observer mObserver; + + public StubbedOfflineContentProvider() { + mHandler = new Handler(Looper.getMainLooper()); + mAddObserverCallback = new CallbackHelper(); + mRemoveObserverCallback = new CallbackHelper(); + mDeleteItemCallback = new CallbackHelper(); + mItems = new ArrayList<>(); + } + + public ArrayList<OfflineItem> getItems() { + return mItems; + } + + public void addItem(OfflineItem item) { + mItems.add(item); + } + + @Override + public void addObserver(OfflineContentProvider.Observer addedObserver) { + assertEquals(mObserver, null); + mObserver = addedObserver; + mAddObserverCallback.notifyCalled(); + } + + @Override + public void removeObserver(OfflineContentProvider.Observer removedObserver) { + assertEquals(mObserver, removedObserver); + mObserver = null; + mRemoveObserverCallback.notifyCalled(); + } + + @Override + public void getItemById(ContentId id, Callback<OfflineItem> callback) { + mHandler.post(() -> callback.onResult(null)); + } + + @Override + public void getAllItems(Callback<ArrayList<OfflineItem>> callback) { + mHandler.post(() -> callback.onResult(mItems)); + } + + @Override + public void getVisualsForItem(ContentId id, VisualsCallback callback) { + mHandler.post(() -> callback.onVisualsAvailable(id, null)); + } + + @Override + public void getShareInfoForItem(ContentId id, ShareCallback callback) { + mHandler.post(() -> callback.onShareInfoAvailable(id, null)); + } + + @Override + public void removeItem(ContentId id) { + for (OfflineItem item : mItems) { + if (item.id.equals(id)) { + mItems.remove(item); + break; + } + } + + mHandler.post(new Runnable() { + @Override + public void run() { + mObserver.onItemRemoved(id); + mDeleteItemCallback.notifyCalled(); + } + }); + } + + @Override + public void openItem(@LaunchLocation int location, ContentId id) {} + + @Override + public void pauseDownload(ContentId id) {} + + @Override + public void resumeDownload(ContentId id, boolean hasUserGesture) {} + + @Override + public void cancelDownload(ContentId id) {} +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedAppLifecycleTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedAppLifecycleTest.java index 8f705fc..e88cfa9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedAppLifecycleTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/feed/FeedAppLifecycleTest.java
@@ -5,13 +5,13 @@ package org.chromium.chrome.browser.feed; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Activity; -import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import com.google.android.libraries.feed.api.lifecycle.AppLifecycleListener; @@ -79,14 +79,13 @@ "ContentSuggestions.Feed.AppLifecycle.Events"; @Before - public void setUp() throws InterruptedException, TimeoutException { + public void setUp() throws InterruptedException { MockitoAnnotations.initMocks(this); when(mMockFeatureList.get(anyString())).thenReturn(true); ChromeFeatureList.setTestFeatures(mMockFeatureList); ThreadUtils.runOnUiThreadBlocking(() -> { try { - ChromeBrowserInitializer.getInstance(InstrumentationRegistry.getTargetContext()) - .handleSynchronousStartup(); + ChromeBrowserInitializer.getInstance().handleSynchronousStartup(); } catch (ProcessInitException e) { Assert.fail("Native initialization failed"); } @@ -117,21 +116,15 @@ @Feature({"InterestFeedContentSuggestions"}) public void testActivityStateChangesIncrementStateCounters() throws InterruptedException, TimeoutException { - assertEquals(0, - RecordHistogram.getHistogramValueCountForTesting( - mHistogramAppLifecycleEvents, AppLifecycleEvent.ENTER_BACKGROUND)); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.ENTER_BACKGROUND, 0); verify(mAppLifecycleListener, times(1)).onEnterForeground(); signalActivityStop(mActivity); signalActivityStart(mActivity); verify(mAppLifecycleListener, times(1)).onEnterBackground(); verify(mAppLifecycleListener, times(2)).onEnterForeground(); - assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - mHistogramAppLifecycleEvents, AppLifecycleEvent.ENTER_BACKGROUND)); - assertEquals(2, - RecordHistogram.getHistogramValueCountForTesting( - mHistogramAppLifecycleEvents, AppLifecycleEvent.ENTER_FOREGROUND)); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.ENTER_BACKGROUND, 1); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.ENTER_FOREGROUND, 2); } @Test @@ -146,61 +139,97 @@ // Opening the NTP again shouldn't trigger another call to initialize(). mActivityTestRule.loadUrlInNewTab(UrlConstants.NTP_URL); verify(mAppLifecycleListener, times(1)).initialize(); - assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - mHistogramAppLifecycleEvents, AppLifecycleEvent.INITIALIZE)); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.INITIALIZE, 1); } @Test @SmallTest @Feature({"InterestFeedContentSuggestions"}) - public void testHistoryDeletionTriggersClearAll() throws InterruptedException { + public void testOnHistoryDeleted() { verify(mAppLifecycleListener, times(0)).onClearAll(); + verify(mAppLifecycleListener, times(0)).onClearAllWithRefresh(); + verify(mFeedScheduler, times(0)).onArticlesCleared(anyBoolean()); + // Note that typically calling onArticlesCleared(true) will not return true, but the + // FeedAppLifecycle should not necessarily care. + when(mFeedScheduler.onArticlesCleared(anyBoolean())).thenReturn(true).thenReturn(false); + + mAppLifecycle.onHistoryDeleted(); + verify(mAppLifecycleListener, times(1)).onClearAllWithRefresh(); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL, 1); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.HISTORY_DELETED, 1); + verify(mFeedScheduler, times(1)).onArticlesCleared(true); + mAppLifecycle.onHistoryDeleted(); verify(mAppLifecycleListener, times(1)).onClearAll(); - assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL)); - verify(mFeedScheduler, times(1)).onArticlesCleared(true); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL, 2); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.HISTORY_DELETED, 2); + verify(mFeedScheduler, times(2)).onArticlesCleared(true); } @Test @SmallTest @Feature({"InterestFeedContentSuggestions"}) - public void testCachedDataRemovalTriggersClearAll() throws InterruptedException { + public void testOnCachedDataCleared() { verify(mAppLifecycleListener, times(0)).onClearAll(); + verify(mAppLifecycleListener, times(0)).onClearAllWithRefresh(); + verify(mFeedScheduler, times(0)).onArticlesCleared(anyBoolean()); + when(mFeedScheduler.onArticlesCleared(anyBoolean())).thenReturn(true).thenReturn(false); + + mAppLifecycle.onCachedDataCleared(); + verify(mAppLifecycleListener, times(1)).onClearAllWithRefresh(); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL, 1); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.CACHED_DATA_CLEARED, 1); + verify(mFeedScheduler, times(1)).onArticlesCleared(false); + mAppLifecycle.onCachedDataCleared(); verify(mAppLifecycleListener, times(1)).onClearAll(); - assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL)); - verify(mFeedScheduler, times(1)).onArticlesCleared(false); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL, 2); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.CACHED_DATA_CLEARED, 2); + verify(mFeedScheduler, times(2)).onArticlesCleared(false); } @Test @SmallTest @Feature({"InterestFeedContentSuggestions"}) - public void testSignoutTriggersClearAll() throws InterruptedException { + public void testOnSignedOut() { verify(mAppLifecycleListener, times(0)).onClearAll(); + verify(mAppLifecycleListener, times(0)).onClearAllWithRefresh(); + verify(mFeedScheduler, times(0)).onArticlesCleared(anyBoolean()); + when(mFeedScheduler.onArticlesCleared(anyBoolean())).thenReturn(true).thenReturn(false); + + mAppLifecycle.onSignedOut(); + verify(mAppLifecycleListener, times(1)).onClearAllWithRefresh(); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL, 1); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.SIGN_OUT, 1); + verify(mFeedScheduler, times(1)).onArticlesCleared(false); + mAppLifecycle.onSignedOut(); verify(mAppLifecycleListener, times(1)).onClearAll(); - assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL)); - verify(mFeedScheduler, times(1)).onArticlesCleared(false); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL, 2); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.SIGN_OUT, 2); + verify(mFeedScheduler, times(2)).onArticlesCleared(false); } @Test @SmallTest @Feature({"InterestFeedContentSuggestions"}) - public void testSigninTriggersClearAll() throws InterruptedException { + public void testOnSignedIn() { verify(mAppLifecycleListener, times(0)).onClearAll(); + verify(mAppLifecycleListener, times(0)).onClearAllWithRefresh(); + verify(mFeedScheduler, times(0)).onArticlesCleared(anyBoolean()); + when(mFeedScheduler.onArticlesCleared(anyBoolean())).thenReturn(true).thenReturn(false); + + mAppLifecycle.onSignedIn(); + verify(mAppLifecycleListener, times(1)).onClearAllWithRefresh(); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL, 1); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.SIGN_IN, 1); + verify(mFeedScheduler, times(1)).onArticlesCleared(false); + mAppLifecycle.onSignedIn(); verify(mAppLifecycleListener, times(1)).onClearAll(); - assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL)); - verify(mFeedScheduler, times(1)).onArticlesCleared(false); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.CLEAR_ALL, 2); + verifyHistogram(mHistogramAppLifecycleEvents, AppLifecycleEvent.SIGN_IN, 2); + verify(mFeedScheduler, times(2)).onArticlesCleared(false); } @Test @@ -292,4 +321,8 @@ waitForStateChangeHelper.waitForCallback(0); } + + private void verifyHistogram(String name, @AppLifecycleEvent int sample, int expectedCount) { + assertEquals(expectedCount, RecordHistogram.getHistogramValueCountForTesting(name, sample)); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java index 0ed2b9f..13eeb91a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java
@@ -18,6 +18,7 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.CardType; @@ -324,10 +325,17 @@ mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, mPaymentRequestTestRule.getReadyToEdit()); - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", - "650-253-0000"}, - mPaymentRequestTestRule.getEditorTextUpdate()); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] { + "Seb Doe", "340 Main St", "Los Angeles", "CA", "90291", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyToEdit()); @@ -382,10 +390,17 @@ R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); mPaymentRequestTestRule.clickInShippingAddressAndWait( R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", - "650-253-0000"}, - mPaymentRequestTestRule.getEditorTextUpdate()); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] { + "Seb Doe", "340 Main St", "Los Angeles", "CA", "90291", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyToPay()); @@ -445,10 +460,17 @@ // recipient name brings up the address editor. mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( new int[] {DECEMBER, NEXT_YEAR, 5}, mPaymentRequestTestRule.getReadyToEdit()); - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] {"Lisa Doh", "Google", "340 Main St", "Los Angeles", "CA", "90291", - "650-253-0000"}, - mPaymentRequestTestRule.getEditorTextUpdate()); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Lisa Doh", "Google", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Lisa Doh", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyToEdit());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java index 84d6890..4818f4e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java
@@ -18,6 +18,7 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.CardType; @@ -149,10 +150,16 @@ mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( new int[] {DECEMBER, NEXT_YEAR, ADD_BILLING_ADDRESS}, mPaymentRequestTestRule.getReadyToEdit()); - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", ""}, - mPaymentRequestTestRule.getEditorTextUpdate()); - + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] { + "Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", ""}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Seb Doe", "340 Main St", "Los Angeles", "CA", "90291", ""}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } // Trying to add the address without a phone number should fail. mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getEditorValidationError());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java index b797edd..2a1dd2b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java
@@ -15,6 +15,7 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.CardType; @@ -105,10 +106,17 @@ R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); mPaymentRequestTestRule.clickInShippingAddressAndWait( R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", "Mountain View", "CA", - "94043", "650-253-0000"}, - mPaymentRequestTestRule.getEditorTextUpdate()); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", "Mountain View", "CA", + "94043", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Bob", "1600 Amphitheatre Pkwy", "Mountain View", "CA", "94043", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyForInput()); mPaymentRequestTestRule.clickAndWait(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java index 2307a02..b9b62ad1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java
@@ -17,6 +17,7 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.FlakyTest; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.CardType; @@ -108,10 +109,17 @@ R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); mPaymentRequestTestRule.clickInShippingAddressAndWait( R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", "Mountain View", "CA", - "94043", "650-253-0000"}, - mPaymentRequestTestRule.getEditorTextUpdate()); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", "Mountain View", "CA", + "94043", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Bob", "1600 Amphitheatre Pkwy", "Mountain View", "CA", "94043", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyToPay()); mPaymentRequestTestRule.clickAndWait( @@ -137,10 +145,16 @@ R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); mPaymentRequestTestRule.setSpinnerSelectionInEditorAndWait( 0 /* Afghanistan */, mPaymentRequestTestRule.getReadyToEdit()); - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] { - "Alice", "Supreme Court", "Airport Road", "Kabul", "1043", "020-253-0000"}, - mPaymentRequestTestRule.getEditorTextUpdate()); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Alice", "Supreme Court", "Airport Road", "Kabul", "1043", + "020-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Alice", "Airport Road", "Kabul", "1043", "020-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyToPay()); mPaymentRequestTestRule.clickAndWait( @@ -149,8 +163,13 @@ R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( ModalDialogProperties.ButtonType.POSITIVE, mPaymentRequestTestRule.getDismissed()); - mPaymentRequestTestRule.expectResultContains(new String[] { - "Alice", "Supreme Court", "Airport Road", "Kabul", "1043", "+93202530000"}); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.expectResultContains(new String[] { + "Alice", "Supreme Court", "Airport Road", "Kabul", "1043", "+93202530000"}); + } else { + mPaymentRequestTestRule.expectResultContains( + new String[] {"Alice", "Airport Road", "Kabul", "1043", "+93202530000"}); + } } /** Quickly pressing on "add address" and then [X] should not crash. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java index 8bfaf97..91b31b3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java
@@ -17,6 +17,7 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; @@ -69,10 +70,17 @@ "Phone number required")); mPaymentRequestTestRule.clickInShippingAddressAndWait( R.id.payments_first_radio_button, mPaymentRequestTestRule.getReadyToEdit()); - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] {"Jon Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", - "650-253-0000"}, - mPaymentRequestTestRule.getEditorTextUpdate()); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Jon Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] { + "Jon Doe", "340 Main St", "Los Angeles", "CA", "90291", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } // The contact is now complete, but not selected. mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyForInput()); @@ -107,10 +115,17 @@ // Add a new Shipping Address and see that the contact section updates. mPaymentRequestTestRule.clickInShippingAddressAndWait( R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] {"Jane Doe", "Edge Corp.", "111 Wall St.", "New York", "NY", "10110", - "650-253-0000"}, - mPaymentRequestTestRule.getEditorTextUpdate()); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Jane Doe", "Edge Corp.", "111 Wall St.", "New York", "NY", + "10110", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] { + "Jane Doe", "111 Wall St.", "New York", "NY", "10110", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyForInput()); Assert.assertEquals("Jon Doe\njon.doe@google.com\nPhone number required",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java index 36f2e5a..2b8c15e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java
@@ -24,6 +24,7 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.RetryOnFailure; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.CardType; @@ -206,10 +207,16 @@ R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); mPaymentRequestTestRule.setSpinnerSelectionInEditorAndWait( 0 /* Afghanistan */, mPaymentRequestTestRule.getReadyToEdit()); - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] { - "Alice", "Supreme Court", "Airport Road", "Kabul", "1043", "020-253-0000"}, - mPaymentRequestTestRule.getEditorTextUpdate()); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Alice", "Supreme Court", "Airport Road", "Kabul", "1043", + "020-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Alice", "Airport Road", "Kabul", "1043", "020-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyToPay());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java index 351d5df..f99534d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java
@@ -22,6 +22,7 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.CardType; @@ -246,11 +247,17 @@ mPaymentRequestTestRule.setSpinnerSelectionsInCardEditorAndWait( new int[] {DECEMBER, NEXT_YEAR, addBillingAddress}, mPaymentRequestTestRule.getReadyToEdit()); - - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", "Mountain View", "CA", - "94043", "650-253-0000"}, - mPaymentRequestTestRule.getEditorTextUpdate()); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Bob", "Google", "1600 Amphitheatre Pkwy", "Mountain View", "CA", + "94043", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Bob", "1600 Amphitheatre Pkwy", "Mountain View", "CA", "94043", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyToEdit()); @@ -262,9 +269,15 @@ R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask()); mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( ModalDialogProperties.ButtonType.POSITIVE, mPaymentRequestTestRule.getDismissed()); - mPaymentRequestTestRule.expectResultContains( - new String[] {"5454545454545454", "12", "Bob", "Google", "1600 Amphitheatre Pkwy", - "Mountain View", "CA", "94043", "+16502530000"}); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + mPaymentRequestTestRule.expectResultContains(new String[] {"5454545454545454", "12", + "Bob", "Google", "1600 Amphitheatre Pkwy", "Mountain View", "CA", "94043", + "+16502530000"}); + } else { + mPaymentRequestTestRule.expectResultContains( + new String[] {"5454545454545454", "12", "Bob", "1600 Amphitheatre Pkwy", + "Mountain View", "CA", "94043", "+16502530000"}); + } } /** Quickly pressing on "add card" and then [X] should not crash. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java index efa6c6ab8f8..7a6a74efe 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java
@@ -14,6 +14,7 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.CardType; @@ -147,19 +148,30 @@ R.id.payments_section, mPaymentRequestTestRule.getReadyForInput()); mPaymentRequestTestRule.clickInShippingAddressAndWait( R.id.payments_add_option_button, mPaymentRequestTestRule.getReadyToEdit()); - mPaymentRequestTestRule.setTextInEditorAndWait( - new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", - "650-253-0000"}, - mPaymentRequestTestRule.getEditorTextUpdate()); + Boolean is_company_name_enabled = + ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME); + if (is_company_name_enabled) { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] {"Seb Doe", "Google", "340 Main St", "Los Angeles", "CA", "90291", + "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } else { + mPaymentRequestTestRule.setTextInEditorAndWait( + new String[] { + "Seb Doe", "340 Main St", "Los Angeles", "CA", "90291", "650-253-0000"}, + mPaymentRequestTestRule.getEditorTextUpdate()); + } mPaymentRequestTestRule.clickInEditorAndWait( R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyToPay()); // Make sure that the shipping label does not include the country. - Assert.assertTrue(mPaymentRequestTestRule.getShippingAddressOptionRowAtIndex(0) - .getLabelText() - .toString() - .equals("Seb Doe\nGoogle, 340 Main St, Los Angeles, CA 90291\n" - + "+1 650-253-0000")); + Assert.assertEquals(mPaymentRequestTestRule.getShippingAddressOptionRowAtIndex(0) + .getLabelText() + .toString(), + is_company_name_enabled ? "Seb Doe\nGoogle, 340 Main St, Los Angeles, CA 90291\n" + + "+1 650-253-0000" + : "Seb Doe\n340 Main St, Los Angeles, CA 90291\n" + + "+1 650-253-0000"); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragmentTest.java index 9d822cf..5d9d98d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragmentTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragmentTest.java
@@ -20,6 +20,7 @@ import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.preferences.Preferences; @@ -35,6 +36,7 @@ /** * Unit test suite for AutofillProfilesFragment. */ + @RunWith(BaseJUnit4ClassRunner.class) public class AutofillProfilesFragmentTest { @Rule @@ -79,10 +81,19 @@ Assert.assertNotNull(addProfile); // Add a profile. - updatePreferencesAndWait(autofillProfileFragment, addProfile, - new String[] {"Alice Doe", "Google", "111 Added St", "Los Angeles", - "CA", "90291", "650-253-0000", "add@profile.com"}, - R.id.editor_dialog_done_button, false); + // TODO(jeffreycohen): Change this test into a parameterized test that exercises + // both branches of this if statement. + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + updatePreferencesAndWait(autofillProfileFragment, addProfile, + new String[] {"Alice Doe", "Google", "111 Added St", "Los Angeles", "CA", + "90291", "650-253-0000", "add@profile.com"}, + R.id.editor_dialog_done_button, false); + } else { + updatePreferencesAndWait(autofillProfileFragment, addProfile, + new String[] {"Alice Doe", "111 Added St", "Los Angeles", "CA", "90291", + "650-253-0000", "add@profile.com"}, + R.id.editor_dialog_done_button, false); + } Assert.assertEquals(7 /* One toggle + one add button + five profiles. */, autofillProfileFragment.getPreferenceScreen().getPreferenceCount()); @@ -172,11 +183,17 @@ Assert.assertEquals("John Doe", johnProfile.getTitle()); // Edit a profile. - updatePreferencesAndWait(autofillProfileFragment, johnProfile, - new String[] {"Emily Doe", "Google", "111 Edited St", "Los Angeles", - "CA", "90291", "650-253-0000", "edit@profile.com"}, - R.id.editor_dialog_done_button, false); - + if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ENABLE_COMPANY_NAME)) { + updatePreferencesAndWait(autofillProfileFragment, johnProfile, + new String[] {"Emily Doe", "Google", "111 Edited St", "Los Angeles", "CA", + "90291", "650-253-0000", "edit@profile.com"}, + R.id.editor_dialog_done_button, false); + } else { + updatePreferencesAndWait(autofillProfileFragment, johnProfile, + new String[] {"Emily Doe", "111 Edited St", "Los Angeles", "CA", "90291", + "650-253-0000", "edit@profile.com"}, + R.id.editor_dialog_done_button, false); + } // Check if the preferences are updated correctly. Assert.assertEquals(6 /* One toggle + one add button + four profiles. */, autofillProfileFragment.getPreferenceScreen().getPreferenceCount()); @@ -313,4 +330,4 @@ rule.waitForThePreferenceUpdate(); } } -} \ No newline at end of file +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/OWNERS new file mode 100644 index 0000000..c4d2e224 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/OWNERS
@@ -0,0 +1 @@ +file://components/autofill/OWNERS \ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java index 3866f426f..b280b8a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
@@ -22,18 +22,24 @@ public class TestVrShellDelegate extends VrShellDelegate { private Runnable mOnVSyncPausedCallback; private static TestVrShellDelegate sInstance; + private static Description sTestDescription; private boolean mDisableVrBrowsing; private boolean mExpectingBroadcast; private boolean mExpectingIntent; private Boolean mAllow2dIntents; - public static void createTestVrShellDelegate(final ChromeActivity activity, Description desc) { + public static void createTestVrShellDelegate(final ChromeActivity activity) { // Cannot make VrShellDelegate if we are faking that the VR module is not installed. - if (desc.getAnnotation(VrModuleNotInstalled.class) != null) return; + if (sTestDescription.getAnnotation(VrModuleNotInstalled.class) != null) return; if (sInstance != null) return; ThreadUtils.runOnUiThreadBlocking(() -> { sInstance = new TestVrShellDelegate(activity); }); } + // TODO(bsheedy): Maybe remove this and switch to setting a VrShellDelegateFactory instead. + public static void setDescription(Description desc) { + sTestDescription = desc; + } + public static TestVrShellDelegate getInstance() { return sInstance; }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/ChromeTabbedActivityVrTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/ChromeTabbedActivityVrTestRule.java index 9c647225..0b184244 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/ChromeTabbedActivityVrTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/ChromeTabbedActivityVrTestRule.java
@@ -32,7 +32,7 @@ VrTestRuleUtils.evaluateVrTestRuleImpl( base, desc, ChromeTabbedActivityVrTestRule.this, () -> { startMainActivityOnBlankPage(); - TestVrShellDelegate.createTestVrShellDelegate(getActivity(), desc); + TestVrShellDelegate.createTestVrShellDelegate(getActivity()); }); } }, desc);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/CustomTabActivityVrTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/CustomTabActivityVrTestRule.java index b341b3c..8c3e4f3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/CustomTabActivityVrTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/CustomTabActivityVrTestRule.java
@@ -35,7 +35,7 @@ CustomTabsTestUtils.createMinimalCustomTabIntent( InstrumentationRegistry.getTargetContext(), "about:blank"))); - TestVrShellDelegate.createTestVrShellDelegate(getActivity(), desc); + TestVrShellDelegate.createTestVrShellDelegate(getActivity()); }); } }, desc);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/WebappActivityVrTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/WebappActivityVrTestRule.java index e851ea9..c588891 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/WebappActivityVrTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/WebappActivityVrTestRule.java
@@ -30,7 +30,7 @@ VrTestRuleUtils.evaluateVrTestRuleImpl( base, desc, WebappActivityVrTestRule.this, () -> { startWebappActivity(); - TestVrShellDelegate.createTestVrShellDelegate(getActivity(), desc); + TestVrShellDelegate.createTestVrShellDelegate(getActivity()); }); } }, desc);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTestRuleUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTestRuleUtils.java index 2c4e40d6..3e8cc7fe 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTestRuleUtils.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTestRuleUtils.java
@@ -63,6 +63,7 @@ if (desc.getAnnotation(VrModuleNotInstalled.class) != null) { VrModuleProvider.setAlwaysUseFallbackDelegate(true); } + TestVrShellDelegate.setDescription(desc); VrTestRuleUtils.ensureNoVrActivitiesDisplayed(); HeadTrackingUtils.checkForAndApplyHeadTrackingModeAnnotation(rule, desc);
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index a1b43684..57122dad 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-73.0.3681.0_rc-r1.afdo.bz2 \ No newline at end of file +chromeos-chrome-amd64-73.0.3682.0_rc-r1.afdo.bz2 \ No newline at end of file
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index f234498..dbf299d0 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc
@@ -47,7 +47,7 @@ #include "components/crash/core/common/crash_key.h" #include "components/crash/core/common/crash_keys.h" #include "components/nacl/common/buildflags.h" -#include "components/services/heap_profiling/public/cpp/allocator_shim.h" +#include "components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h" #include "components/services/heap_profiling/public/cpp/stream.h" #include "components/tracing/common/tracing_sampler_profiler.h" #include "components/version_info/version_info.h"
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index ea3b8b2..656f3120 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -1623,7 +1623,7 @@ Skip for now </message> - <message name="IDS_AUTO_ENROLLMENT_CHECK_SCREEN_HEADER" desc="Header of message only used for accessability label in the current design, notifying about pending auto-enrollment check completion."> + <message name="IDS_AUTO_ENROLLMENT_CHECK_SCREEN_HEADER" desc="Header of message only used for accessibility label in the current design, notifying about pending auto-enrollment check completion."> Determining device configuration. </message> <message name="IDS_AUTO_ENROLLMENT_CHECK_SCREEN_MESSAGE" desc="Warning message shown on screen notifying about pending auto-enrollment check completion."> @@ -2260,6 +2260,9 @@ <message name="IDS_3G_DATASAVER_MESSAGE" desc="Text of the 3G data notification prompting user to install Data Saver."> Save data and browse faster using Google Data Saver. Click to learn more. </message> + <message name="IDS_3G_DATASAVER_MESSAGE_LITE_MODE" desc="Text of the 3G data notification prompting user to install Lite mode."> + Browse faster and use less data with Lite mode. Click to learn more. + </message> <!-- chrome://mobilesetup strings --> <message name="IDS_MOBILE_SETUP_TITLE" desc="ChromeOS mobile device activation page title">
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index 30555aa..dc34de7 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd
@@ -574,6 +574,10 @@ Customize and control Chromium. Update is available. </message> + <message name="IDS_APPMENU_TOOLTIP_ALERT" desc="The tooltip to show for the browser menu when a non-update alert is displayed"> + Customize and control Chromium. Something needs your attention - click for details. + </message> + <message name="IDS_OPEN_IN_CHROME" desc="The text label of the Open in Chrome menu item for the Hosted App app menu"> &Open in Chromium </message>
diff --git a/chrome/app/file_manager_strings.grdp b/chrome/app/file_manager_strings.grdp index d4489ce..e6b9400a 100644 --- a/chrome/app/file_manager_strings.grdp +++ b/chrome/app/file_manager_strings.grdp
@@ -1024,9 +1024,6 @@ <message name="IDS_FILE_BROWSER_DRIVE_WELCOME_TITLE" desc="In the Welcome to Google Drive banner, title of banner."> Welcome to Google Drive! </message> - <message name="IDS_FILE_BROWSER_DRIVE_WELCOME_TITLE_ALTERNATIVE" desc="In the Welcome to Google Drive banner, title of the alternative banner offering 100GB free storage."> - Get 100 GB free with Google Drive - </message> <message name="IDS_FILE_BROWSER_DRIVE_WELCOME_TEXT_SHORT" desc="In the Welcome to Google Drive banner, text of the welcome message, short version."> All files saved in this folder are backed up online automatically </message> @@ -1038,9 +1035,6 @@ <ph name="MARKUP_7"><p><strong><ex><strong></ex></ph>Share, create and collaborate<ph name="MARKUP_8"></strong><ex></strong></ex></ph> on files with others all in one place.<ph name="MARKUP_9"></p><ex></p></ex></ph> </message> - <message name="IDS_FILE_BROWSER_DRIVE_WELCOME_CHECK_ELIGIBILITY" desc="In the Welcome to Google Drive banner, a text on the button to check promo eligibility."> - Check eligibility - </message> <message name="IDS_FILE_BROWSER_DRIVE_WELCOME_DISMISS" desc="In the Welcome to Google Drive banner, a text on the button to dismiss the banner."> Dismiss </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 7e4d8d9..23b370a1 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -4486,9 +4486,9 @@ <!-- HTTPS Server Previews InfoBar --> <message name="IDS_LITE_PAGE_PREVIEWS_MESSAGE" desc="The text of the infobar notifying the user that Chrome's Lite mode will now also apply to HTTPS pages."> - Lite Mode now makes browsing faster on all pages, including HTTPS. + Lite mode now makes browsing faster on all pages, including HTTPS. </message> - <message name="IDS_LITE_PAGE_PREVIEWS_SETTINGS_LINK" desc="This link opens the Data Saver settings to explain and configure Lite mode settings."> + <message name="IDS_LITE_PAGE_PREVIEWS_SETTINGS_LINK" desc="This link opens the Data Saver settings page to explain the feature and configure the settings."> Settings </message> @@ -5420,7 +5420,7 @@ </message> </if> <message name="IDS_FEEDBACK_INCLUDE_ASSISTANT_INFORMATION_CHKBOX" desc="Checkbox for including Assistant debug information in the feedback report"> - Include info to debug Assistant + Info to debug Assistant </message> <message name="IDS_FEEDBACK_ATTACH_FILE_NOTE" desc="Text for describing the maximum size for an attached file"> File will be sent to Google for debugging
diff --git a/chrome/app/generated_resources_grd/IDS_FEEDBACK_INCLUDE_ASSISTANT_INFORMATION_CHKBOX.png.sha1 b/chrome/app/generated_resources_grd/IDS_FEEDBACK_INCLUDE_ASSISTANT_INFORMATION_CHKBOX.png.sha1 index 7fbe7b8..756f238 100644 --- a/chrome/app/generated_resources_grd/IDS_FEEDBACK_INCLUDE_ASSISTANT_INFORMATION_CHKBOX.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_FEEDBACK_INCLUDE_ASSISTANT_INFORMATION_CHKBOX.png.sha1
@@ -1 +1 @@ -f13093d7c8c783205314f71d99570a4301d0c779 \ No newline at end of file +96331c61c835f91ee744fc38e862185b4dae20af \ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd index 2317c30..6fd110c6 100644 --- a/chrome/app/google_chrome_strings.grd +++ b/chrome/app/google_chrome_strings.grd
@@ -585,6 +585,10 @@ Customize and control Google Chrome. Update is available. </message> + <message name="IDS_APPMENU_TOOLTIP_ALERT" desc="The tooltip to show for the browser menu when a non-update alert is displayed"> + Customize and control Google Chrome. Something needs your attention - click for details. + </message> + <message name="IDS_OPEN_IN_CHROME" desc="The text label of the Open in Chrome menu item for the Hosted App app menu"> &Open in Chrome </message>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 37d96929..f73abbf1 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -2527,7 +2527,7 @@ Help improve Chrome's features and performance </message> <message name="IDS_SETTINGS_ENABLE_LOGGING_DESC_UNIFIED_CONSENT" desc="The description of the checkbox to enable/disable crash and user metrics logging"> - Automatically send usage statistics and crash reports to Google + Automatically sends usage statistics and crash reports to Google </message> <message name="IDS_SETTINGS_ENABLE_URL_KEYED_ANONYMIZED_DATA_COLLECTION" desc="The label of the checkbox to enable/disable url keyed anonymized data collection."> Make searches and browsing better
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index d1b5669..5d65f80 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1711,6 +1711,7 @@ allow_circular_includes_from = [ "//chrome/browser/ui", "//chrome/browser/ui/webui/bluetooth_internals", + "//chrome/browser/safe_browsing", ] public_deps = [ @@ -1766,6 +1767,7 @@ "//components/browsing_data/content", "//components/browsing_data/core", "//components/captive_portal", + "//components/certificate_matching", "//components/certificate_transparency", "//components/cloud_devices/common", "//components/component_updater", @@ -4204,6 +4206,13 @@ "nacl_host/nacl_infobar_delegate.h", ] deps += [ "//components/nacl/browser" ] + + if (enable_nacl) { + deps += [ "//components/nacl/loader:nacl_loader_manifest" ] + if (is_win && target_cpu == "x86") { + deps += [ "//components/nacl/broker:nacl_broker_manifest" ] + } + } } if (enable_offline_pages) { @@ -4766,6 +4775,8 @@ "../android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java", "../android/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselDelegate.java", "../android/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselModel.java", + "../android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetails.java", + "../android/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsModel.java", "../android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderDelegate.java", "../android/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderModel.java", "../android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 784f76de..e4e6ebdd 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1518,10 +1518,6 @@ SINGLE_VALUE_TYPE_AND_VALUE(switches::kAllowNaClSocketAPI, "*")}, #endif // ENABLE_PLUGINS #if defined(OS_CHROMEOS) - {"ash-enable-cursor-motion-blur", - flag_descriptions::kEnableCursorMotionBlurName, - flag_descriptions::kEnableCursorMotionBlurDescription, kOsCrOS, - SINGLE_VALUE_TYPE(ash::switches::kAshEnableCursorMotionBlur)}, {"ash-enable-docked-magnifier", flag_descriptions::kEnableDockedMagnifierName, flag_descriptions::kEnableDockedMagnifierDescription, kOsCrOS, @@ -1640,13 +1636,6 @@ kOsAll, SINGLE_VALUE_TYPE(ash::switches::kAshDebugShortcuts), }, - { - "ash-enable-mirrored-screen", - flag_descriptions::kAshEnableMirroredScreenName, - flag_descriptions::kAshEnableMirroredScreenDescription, - kOsCrOS, - SINGLE_VALUE_TYPE(ash::switches::kAshEnableMirroredScreen), - }, {"ash-shelf-color", flag_descriptions::kAshShelfColorName, flag_descriptions::kAshShelfColorDescription, kOsCrOS, MULTI_VALUE_TYPE(kAshShelfColorChoices)}, @@ -3465,13 +3454,6 @@ flag_descriptions::kStopInBackgroundDescription, kOsAndroid, FEATURE_VALUE_TYPE(blink::features::kStopInBackground)}, -#if defined(OS_CHROMEOS) - {"ash-disable-login-dim-and-blur", - flag_descriptions::kAshDisableLoginDimAndBlurName, - flag_descriptions::kAshDisableLoginDimAndBlurDescription, kOsCrOS, - SINGLE_DISABLE_VALUE_TYPE(ash::switches::kAshDisableLoginDimAndBlur)}, -#endif // OS_CHROMEOS - {"clipboard-content-setting", flag_descriptions::kClipboardContentSettingName, flag_descriptions::kClipboardContentSettingDescription, kOsAll, @@ -3521,6 +3503,13 @@ kOsDesktop, FEATURE_VALUE_TYPE(features::kWebAuthBle)}, #endif // !defined(OS_ANDROID) +#if !defined(OS_ANDROID) + {"enable-web-authentication-cable-support", + flag_descriptions::kEnableWebAuthenticationCableSupportName, + flag_descriptions::kEnableWebAuthenticationCableSupportDescription, + kOsDesktop, FEATURE_VALUE_TYPE(features::kWebAuthCable)}, +#endif // !defined(OS_ANDROID) + #if defined(OS_ANDROID) {"enable-sole-integration", flag_descriptions::kSoleIntegrationName, flag_descriptions::kSoleIntegrationDescription, kOsAndroid,
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc index 4474120..215253c 100644 --- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc +++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -33,6 +33,8 @@ #include "content/public/browser/web_contents.h" #include "google_apis/google_api_keys.h" #include "jni/AssistantCarouselModel_jni.h" +#include "jni/AssistantDetailsModel_jni.h" +#include "jni/AssistantDetails_jni.h" #include "jni/AssistantHeaderModel_jni.h" #include "jni/AssistantModel_jni.h" #include "jni/AutofillAssistantUiController_jni.h" @@ -123,9 +125,13 @@ void UiControllerAndroid::OnFeedbackButtonClicked() { JNIEnv* env = AttachCurrentThread(); + auto jdetails = Java_AssistantDetailsModel_getDetails(env, GetDetailsModel()); + auto jstatus_message = + Java_AssistantHeaderModel_getStatusMessage(env, GetHeaderModel()); Java_AutofillAssistantUiController_showFeedback( env, java_autofill_assistant_ui_controller_, - base::android::ConvertUTF8ToJavaString(env, GetDebugContext())); + base::android::ConvertUTF8ToJavaString(env, GetDebugContext()), jdetails, + jstatus_message); } void UiControllerAndroid::OnCloseButtonClicked() { @@ -318,9 +324,16 @@ base::android::ToJavaArrayOfStrings(env, supported_basic_card_networks)); } +// Details related method. + +base::android::ScopedJavaLocalRef<jobject> +UiControllerAndroid::GetDetailsModel() { + return Java_AssistantModel_getDetailsModel(AttachCurrentThread(), GetModel()); +} + void UiControllerAndroid::HideDetails() { - Java_AutofillAssistantUiController_onHideDetails( - AttachCurrentThread(), java_autofill_assistant_ui_controller_); + Java_AssistantDetailsModel_clearDetails(AttachCurrentThread(), + GetDetailsModel()); } void UiControllerAndroid::ShowInitialDetails(const std::string& title, @@ -328,12 +341,12 @@ const std::string& mid, const std::string& date) { JNIEnv* env = AttachCurrentThread(); - Java_AutofillAssistantUiController_onShowInitialDetails( - env, java_autofill_assistant_ui_controller_, - base::android::ConvertUTF8ToJavaString(env, title), + auto jdetails = Java_AssistantDetails_createInitial( + env, base::android::ConvertUTF8ToJavaString(env, title), base::android::ConvertUTF8ToJavaString(env, description), base::android::ConvertUTF8ToJavaString(env, mid), base::android::ConvertUTF8ToJavaString(env, date)); + Java_AssistantDetailsModel_setDetails(env, GetDetailsModel(), jdetails); } void UiControllerAndroid::ShowDetails(const ShowDetailsProto& show_details, @@ -408,15 +421,15 @@ int second = details.datetime().time().second(); JNIEnv* env = AttachCurrentThread(); - return Java_AutofillAssistantUiController_onShowDetails( - env, java_autofill_assistant_ui_controller_, - base::android::ConvertUTF8ToJavaString(env, details.title()), + auto jdetails = Java_AssistantDetails_create( + env, base::android::ConvertUTF8ToJavaString(env, details.title()), base::android::ConvertUTF8ToJavaString(env, details.url()), base::android::ConvertUTF8ToJavaString(env, details.description()), base::android::ConvertUTF8ToJavaString(env, details.m_id()), base::android::ConvertUTF8ToJavaString(env, details.total_price()), year, month, day, hour, minute, second, user_approval_required, highlight_title, highlight_date); + Java_AssistantDetailsModel_setDetails(env, GetDetailsModel(), jdetails); } void UiControllerAndroid::Stop(
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h index eb9a259..07a196fb 100644 --- a/chrome/browser/android/autofill_assistant/ui_controller_android.h +++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -100,6 +100,7 @@ base::android::ScopedJavaLocalRef<jobject> GetModel(); base::android::ScopedJavaLocalRef<jobject> GetHeaderModel(); + base::android::ScopedJavaLocalRef<jobject> GetDetailsModel(); base::android::ScopedJavaLocalRef<jobject> GetCarouselModel(); void SetProgressPulsingEnabled(bool enabled);
diff --git a/chrome/browser/android/download/available_offline_content_provider_unittest.cc b/chrome/browser/android/download/available_offline_content_provider_unittest.cc index 88e776df..1f5e92d 100644 --- a/chrome/browser/android/download/available_offline_content_provider_unittest.cc +++ b/chrome/browser/android/download/available_offline_content_provider_unittest.cc
@@ -12,6 +12,7 @@ #include "base/test/bind_test_util.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h" +#include "chrome/common/available_offline_content.mojom-test-utils.h" #include "chrome/common/chrome_features.h" #include "chrome/test/base/testing_profile.h" #include "components/ntp_snippets/pref_names.h"
diff --git a/chrome/browser/android/feed/feed_scheduler_bridge.cc b/chrome/browser/android/feed/feed_scheduler_bridge.cc index 36709d0..e9ad48b9 100644 --- a/chrome/browser/android/feed/feed_scheduler_bridge.cc +++ b/chrome/browser/android/feed/feed_scheduler_bridge.cc
@@ -100,11 +100,11 @@ scheduler_host_->OnSuggestionConsumed(); } -void FeedSchedulerBridge::OnArticlesCleared( +bool FeedSchedulerBridge::OnArticlesCleared( JNIEnv* env, const base::android::JavaRef<jobject>& j_this, jboolean j_suppress_refreshes) { - scheduler_host_->OnArticlesCleared(j_suppress_refreshes); + return scheduler_host_->OnArticlesCleared(j_suppress_refreshes); } void FeedSchedulerBridge::TriggerRefresh() {
diff --git a/chrome/browser/android/feed/feed_scheduler_bridge.h b/chrome/browser/android/feed/feed_scheduler_bridge.h index a648b30..030175a 100644 --- a/chrome/browser/android/feed/feed_scheduler_bridge.h +++ b/chrome/browser/android/feed/feed_scheduler_bridge.h
@@ -56,7 +56,7 @@ void OnSuggestionConsumed(JNIEnv* env, const base::android::JavaRef<jobject>& j_this); - void OnArticlesCleared(JNIEnv* env, + bool OnArticlesCleared(JNIEnv* env, const base::android::JavaRef<jobject>& j_this, jboolean j_suppress_refreshes);
diff --git a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc index 9fed7827..903c402 100644 --- a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc +++ b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc
@@ -154,6 +154,8 @@ void OomInterventionTabHelper::DidStartNavigation( content::NavigationHandle* navigation_handle) { + load_finished_ = false; + // Filter out sub-frame's navigation or if the navigation happens without // changing document. if (!navigation_handle->IsInMainFrame() || @@ -192,11 +194,6 @@ } } -void OomInterventionTabHelper::DocumentAvailableInMainFrame() { - if (IsLastVisibleWebContents(web_contents())) - StartMonitoringIfNeeded(); -} - void OomInterventionTabHelper::OnVisibilityChanged( content::Visibility visibility) { if (visibility == content::Visibility::VISIBLE) { @@ -207,6 +204,12 @@ } } +void OomInterventionTabHelper::DocumentOnLoadCompletedInMainFrame() { + load_finished_ = true; + if (IsLastVisibleWebContents(web_contents())) + StartMonitoringIfNeeded(); +} + void OomInterventionTabHelper::OnCrashDumpProcessed( int rph_id, const crash_reporter::CrashMetricsReporter::ReportedCrashTypeSet& @@ -267,6 +270,9 @@ if (near_oom_detected_time_) return; + if (!load_finished_) + return; + auto* config = OomInterventionConfig::GetInstance(); if (config->should_detect_in_renderer()) { if (binding_.is_bound())
diff --git a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h index 663ac359..82d12e0 100644 --- a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h +++ b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h
@@ -56,8 +56,8 @@ void RenderProcessGone(base::TerminationStatus status) override; void DidStartNavigation( content::NavigationHandle* navigation_handle) override; - void DocumentAvailableInMainFrame() override; void OnVisibilityChanged(content::Visibility visibility) override; + void DocumentOnLoadCompletedInMainFrame() override; // CrashDumpManager::Observer: void OnCrashDumpProcessed( @@ -84,6 +84,7 @@ void ResetInterfaces(); bool navigation_started_ = false; + bool load_finished_ = false; base::Optional<base::TimeTicks> near_oom_detected_time_; std::unique_ptr<NearOomMonitor::Subscription> subscription_; base::OneShotTimer renderer_detection_timer_;
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc index 14b9bb38..4d6c0f4 100644 --- a/chrome/browser/android/tab_android.cc +++ b/chrome/browser/android/tab_android.cc
@@ -642,7 +642,6 @@ content::WebContents* contents = content::WebContents::FromRenderFrameHost(rfh); - printing::PrintViewManagerBasic::CreateForWebContents(contents); printing::PrintViewManagerBasic* print_view_manager = printing::PrintViewManagerBasic::FromWebContents(contents); return print_view_manager && print_view_manager->PrintNow(rfh);
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc index 2bc8367..671bf873 100644 --- a/chrome/browser/android/tab_web_contents_delegate_android.cc +++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -61,6 +61,10 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" +#if BUILDFLAG(ENABLE_PRINTING) +#include "components/printing/browser/print_composite_client.h" +#endif + using base::android::AttachCurrentThread; using base::android::JavaParamRef; using base::android::ScopedJavaLocalRef; @@ -185,6 +189,17 @@ return false; } +#if BUILDFLAG(ENABLE_PRINTING) +void TabWebContentsDelegateAndroid::PrintCrossProcessSubframe( + content::WebContents* web_contents, + const gfx::Rect& rect, + int document_cookie, + content::RenderFrameHost* subframe_host) const { + auto* client = printing::PrintCompositeClient::FromWebContents(web_contents); + if (client) + client->PrintCrossProcessSubframe(rect, document_cookie, subframe_host); +} +#endif void TabWebContentsDelegateAndroid::Observe( int type,
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.h b/chrome/browser/android/tab_web_contents_delegate_android.h index ac73c4e..aa890adff 100644 --- a/chrome/browser/android/tab_web_contents_delegate_android.h +++ b/chrome/browser/android/tab_web_contents_delegate_android.h
@@ -10,6 +10,7 @@ #include "content/public/browser/bluetooth_chooser.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "printing/buildflags/buildflags.h" class FindNotificationDetails; @@ -96,6 +97,14 @@ bool did_start_load, bool did_finish_load) override; +#if BUILDFLAG(ENABLE_PRINTING) + void PrintCrossProcessSubframe( + content::WebContents* web_contents, + const gfx::Rect& rect, + int document_cookie, + content::RenderFrameHost* subframe_host) const override; +#endif + private: // NotificationObserver implementation. void Observe(int type,
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc b/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc index b511d21..696787ea 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc
@@ -19,9 +19,9 @@ mojom::XRRuntimePtr)> add_device_callback, base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback, base::OnceClosure initialization_complete) { - if (vr::SupportsArCore()) + if (vr::IsArCoreSupported()) { arcore_device_ = std::make_unique<ArCoreDevice>(); - if (arcore_device_) { + add_device_callback.Run(arcore_device_->GetId(), arcore_device_->GetVRDisplayInfo(), arcore_device_->BindXRRuntimePtr());
diff --git a/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc b/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc index d40e12e..9b32de40 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc
@@ -108,8 +108,7 @@ } bool ArCoreJavaUtils::EnsureLoaded() { - if (!vr::SupportsArCore()) - return false; + DCHECK(vr::IsArCoreSupported()); JNIEnv* env = AttachCurrentThread();
diff --git a/chrome/browser/android/vr/arcore_device/arcore_shim.cc b/chrome/browser/android/vr/arcore_device/arcore_shim.cc index 9b9fabff..5ee88a84 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_shim.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_shim.cc
@@ -6,7 +6,7 @@ #include <dlfcn.h> -#include "base/android/build_info.h" +#include "base/android/android_hardware_buffer_compat.h" #include "base/logging.h" namespace { @@ -94,9 +94,8 @@ return true; } -bool SupportsArCore() { - return base::android::BuildInfo::GetInstance()->sdk_int() >= - base::android::SDK_VERSION_OREO; +bool IsArCoreSupported() { + return base::AndroidHardwareBufferCompat::IsSupportAvailable(); } } // namespace vr
diff --git a/chrome/browser/android/vr/arcore_device/arcore_shim.h b/chrome/browser/android/vr/arcore_device/arcore_shim.h index 0382747..ff0f88c 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_shim.h +++ b/chrome/browser/android/vr/arcore_device/arcore_shim.h
@@ -7,17 +7,16 @@ namespace vr { -// TODO(vollick): add support for unloading the SDK. +// TODO(https://crbug.com/917526): add support for unloading the SDK. bool LoadArCoreSdk(const std::string& libraryPath); -/** - * Determines whether AR Core features are supported. Currently, this only - * depends on the OS version, but could be more sophisticated. - * Calling this method won't load AR Core SDK and does not depend - * on AR Core SDK to be loaded. - * Returns true if the AR Core usage is supported, false otherwise. - */ -bool SupportsArCore(); +// Determines whether AR Core features are supported. +// TODO(https://crbug.com/924380): Currently, this is very simplistic. It should +// consider whether the device can support ARCore. +// Calling this method won't load AR Core SDK and does not depend on AR Core SDK +// to be loaded. +// Returns true if the AR Core usage is supported, false otherwise. +bool IsArCoreSupported(); } // namespace vr
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 26d3bd7..7b78848 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -826,10 +826,15 @@ waitTitle = l10n_util::GetNSString(IDS_ABANDON_DOWNLOAD_DIALOG_CONTINUE_BUTTON); + base::scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]); + [alert setMessageText:titleText]; + [alert setInformativeText:explanationText]; + [alert addButtonWithTitle:waitTitle]; + [alert addButtonWithTitle:exitTitle]; + // 'waitButton' is the default choice. - int choice = NSRunAlertPanel(titleText, @"%@", - waitTitle, exitTitle, nil, explanationText); - return choice == NSAlertDefaultReturn ? YES : NO; + int choice = [alert runModal]; + return choice == NSAlertFirstButtonReturn ? YES : NO; } // Check all profiles for in progress downloads, and if we find any, prompt the
diff --git a/chrome/browser/apps/app_shim/app_shim_handler_mac.h b/chrome/browser/apps/app_shim/app_shim_handler_mac.h index bdcc8c2..f08f5a8 100644 --- a/chrome/browser/apps/app_shim/app_shim_handler_mac.h +++ b/chrome/browser/apps/app_shim/app_shim_handler_mac.h
@@ -19,7 +19,8 @@ namespace apps { -using LaunchShimCallback = base::OnceCallback<void(base::Process)>; +using ShimLaunchedCallback = base::OnceCallback<void(base::Process)>; +using ShimTerminatedCallback = base::OnceClosure; // Registrar, and interface for services that can handle interactions with OSX // shim processes. @@ -54,7 +55,8 @@ virtual void OnShimLaunchRequested( AppShimHost* host, bool recreate_shims, - apps::LaunchShimCallback launch_callback) = 0; + apps::ShimLaunchedCallback launched_callback, + apps::ShimTerminatedCallback terminated_callback) = 0; // Invoked by the AppShimHostBootstrap when a shim process has connected to // the browser process. This will connect to (creating, if needed) an
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac.cc b/chrome/browser/apps/app_shim/app_shim_host_mac.cc index a1d2ffa..cf2c63a 100644 --- a/chrome/browser/apps/app_shim/app_shim_host_mac.cc +++ b/chrome/browser/apps/app_shim/app_shim_host_mac.cc
@@ -84,7 +84,20 @@ return apps::AppShimHandler::GetForAppMode(app_id_); } -void AppShimHost::OnShimLaunchCompleted(bool recreate_shims_requested, +void AppShimHost::LaunchShimInternal(bool recreate_shims) { + DCHECK(!bootstrap_); + apps::AppShimHandler* handler = GetAppShimHandler(); + if (!handler) + return; + handler->OnShimLaunchRequested( + this, recreate_shims, + base::BindOnce(&AppShimHost::OnShimProcessLaunched, + weak_factory_.GetWeakPtr(), recreate_shims), + base::BindOnce(&AppShimHost::OnShimProcessTerminated, + weak_factory_.GetWeakPtr())); +} + +void AppShimHost::OnShimProcessLaunched(bool recreate_shims_requested, base::Process shim_process) { // If the shim process was created, assume that it will successfully create // an AppShimHostBootstrap. @@ -99,12 +112,7 @@ // date. Try again, recreating the shims this time. if (!recreate_shims_requested) { DLOG(ERROR) << "Failed to launch shim, attempting to recreate."; - constexpr bool recreate_shims = true; - apps::AppShimHandler* handler = GetAppShimHandler(); - handler->OnShimLaunchRequested( - this, recreate_shims, - base::BindOnce(&AppShimHost::OnShimLaunchCompleted, - weak_factory_.GetWeakPtr(), recreate_shims)); + LaunchShimInternal(true /* recreate_shims */); return; } @@ -117,6 +125,8 @@ OnAppClosed(); } +void AppShimHost::OnShimProcessTerminated() {} + //////////////////////////////////////////////////////////////////////////////// // AppShimHost, chrome::mojom::AppShimHost @@ -146,11 +156,7 @@ std::vector<base::FilePath>()); } else { // Otherwise, attempt to launch whatever app shims we find. - constexpr bool recreate_shims = false; - handler->OnShimLaunchRequested( - this, recreate_shims, - base::BindOnce(&AppShimHost::OnShimLaunchCompleted, - weak_factory_.GetWeakPtr(), recreate_shims)); + LaunchShimInternal(false /* recreate_shims */); } }
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac.h b/chrome/browser/apps/app_shim/app_shim_host_mac.h index cf93e79..9cae828 100644 --- a/chrome/browser/apps/app_shim/app_shim_host_mac.h +++ b/chrome/browser/apps/app_shim/app_shim_host_mac.h
@@ -86,10 +86,17 @@ // Closes the channel and destroys the AppShimHost. void Close(); + // Helper function to launch the app shim process. + void LaunchShimInternal(bool recreate_shims); + // Called when LaunchShim has launched (or failed to launch) a process. - void OnShimLaunchCompleted(bool recreate_shims_requested, + void OnShimProcessLaunched(bool recreate_shims_requested, base::Process shim_process); + // Called when a shim process returned via OnShimLaunchCompleted has + // terminated. + void OnShimProcessTerminated(); + // Return the AppShimHandler for this app (virtual for tests). virtual apps::AppShimHandler* GetAppShimHandler() const;
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc b/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc index 6093b44e6..3ae2e19 100644 --- a/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc +++ b/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc
@@ -144,7 +144,8 @@ void OnShimLaunchRequested( AppShimHost* host, bool recreate_shims, - apps::LaunchShimCallback launch_callback) override {} + apps::ShimLaunchedCallback launched_callback, + apps::ShimTerminatedCallback terminated_callback) override {} void OnShimProcessConnected( std::unique_ptr<AppShimHostBootstrap> bootstrap) override { ++launch_count_;
diff --git a/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm b/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm index 4fb504b..d557866e 100644 --- a/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm +++ b/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm
@@ -120,7 +120,8 @@ void OnShimLaunchRequested( ::AppShimHost* host, bool recreate_shims, - apps::LaunchShimCallback launch_callback) override {} + apps::ShimLaunchedCallback launched_callback, + apps::ShimTerminatedCallback terminated_callback) override {} void OnShimProcessConnected( std::unique_ptr<AppShimHostBootstrap> bootstrap) override; void OnShimClose(::AppShimHost* host) override {}
diff --git a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm index e574afd..b72bbbdb 100644 --- a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm +++ b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
@@ -106,11 +106,13 @@ void OnShimLaunchRequested( AppShimHost* host, bool recreate_shims, - apps::LaunchShimCallback launch_callback) override { + apps::ShimLaunchedCallback launch_callback, + apps::ShimTerminatedCallback terminated_callback) override { apps::AppShimHandler::RemoveHandler(app_mode_id_); apps::AppShimHandler::GetForAppMode(app_mode_id_) ->OnShimLaunchRequested(host, recreate_shims, - std::move(launch_callback)); + std::move(launch_callback), + std::move(terminated_callback)); apps::AppShimHandler::RegisterHandler(app_mode_id_, this); } void OnShimProcessConnected( @@ -259,7 +261,7 @@ web_app::WebAppShortcutCreator shortcut_creator( web_app::GetWebAppDataDirectory(profile->GetPath(), app->id(), GURL()), shortcut_info.get()); - return shortcut_creator.GetInternalShortcutPath(); + return shortcut_creator.GetApplicationsShortcutPath(false); } Browser* GetFirstHostedAppWindow() { @@ -289,8 +291,8 @@ // Note that usually an install triggers shim creation, but that's disabled // (always) in tests. If it wasn't the case, the following test would fail // (but flakily since the creation happens on the FILE thread). - shim_path_ = GetAppShimPath(profile(), app); base::ScopedAllowBlockingForTesting allow_blocking; + shim_path_ = GetAppShimPath(profile(), app); EXPECT_FALSE(base::PathExists(shim_path_)); // To create a shim in a test, instead call UpdateAllShortcuts, which has been @@ -607,7 +609,7 @@ shortcut_info.get()); std::vector<base::FilePath> updated_paths; shortcut_creator.UpdateShortcuts(false, &updated_paths); - base::FilePath shim_path = shortcut_creator.GetInternalShortcutPath(); + base::FilePath shim_path = updated_paths.front(); NSMutableDictionary* plist_64 = [NSMutableDictionary dictionaryWithContentsOfFile:base::mac::FilePathToNSString( shim_path.Append("Contents").Append("Info.plist"))];
diff --git a/chrome/browser/apps/app_shim/apps_page_shim_handler.h b/chrome/browser/apps/app_shim/apps_page_shim_handler.h index 51130afc..bb8f11b8 100644 --- a/chrome/browser/apps/app_shim/apps_page_shim_handler.h +++ b/chrome/browser/apps/app_shim/apps_page_shim_handler.h
@@ -17,9 +17,11 @@ AppsPageShimHandler() {} // AppShimHandler: - void OnShimLaunchRequested(AppShimHost* host, - bool recreate_shims, - apps::LaunchShimCallback launch_callback) override; + void OnShimLaunchRequested( + AppShimHost* host, + bool recreate_shims, + apps::ShimLaunchedCallback launched_callback, + apps::ShimTerminatedCallback terminated_callback) override; void OnShimProcessConnected( std::unique_ptr<AppShimHostBootstrap> bootstrap) override; void OnShimClose(AppShimHost* host) override;
diff --git a/chrome/browser/apps/app_shim/apps_page_shim_handler.mm b/chrome/browser/apps/app_shim/apps_page_shim_handler.mm index 4511131..d404ba3 100644 --- a/chrome/browser/apps/app_shim/apps_page_shim_handler.mm +++ b/chrome/browser/apps/app_shim/apps_page_shim_handler.mm
@@ -56,7 +56,8 @@ void AppsPageShimHandler::OnShimLaunchRequested( AppShimHost* host, bool recreate_shims, - apps::LaunchShimCallback launch_callback) {} + apps::ShimLaunchedCallback launched_callback, + apps::ShimTerminatedCallback terminated_callback) {} void AppsPageShimHandler::OnShimProcessConnected( std::unique_ptr<AppShimHostBootstrap> bootstrap) {
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc index 3f6b27a..6ed1713d 100644 --- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc +++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
@@ -17,6 +17,7 @@ #include "base/mac/foundation_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/macros.h" +#include "base/sha1.h" #include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h" #include "chrome/browser/apps/app_shim/app_shim_host_mac.h" #include "chrome/browser/apps/app_shim/app_shim_host_manager_mac.h" @@ -107,23 +108,25 @@ return true; } -// Returns whether |pid|'s code signature is trusted: -// - True if |pid| is validly signed and satisfies the designated requirement -// embedded in the calling process's signature. -// - True if the caller is not signed *and* not an official Chrome build. -// - False otherwise (e.g. the shim doesn't satisfy the browser's designated -// requirement, or the browser is an official Chrome build but unsigned). -bool IsAcceptablyCodeSigned(pid_t pid) { - // Only require signatures for official Chrome builds. -#if !defined(OFFICIAL_BUILD) || !defined(GOOGLE_CHROME_BUILD) - return true; -#endif - // TODO(https://crbug.com/624228): Re-enable signature checking when shims - // can start. - return true; +// Create a SHA1 hex digest of a certificate, for use specifically in building +// a code signing requirement string in IsAcceptablyCodeSigned(), below. +std::string CertificateSHA1Digest(SecCertificateRef certificate) { + base::ScopedCFTypeRef<CFDataRef> certificate_data( + SecCertificateCopyData(certificate)); + char hash[base::kSHA1Length]; + base::SHA1HashBytes(CFDataGetBytePtr(certificate_data), + CFDataGetLength(certificate_data), + reinterpret_cast<unsigned char*>(hash)); + return base::HexEncode(hash, base::kSHA1Length); +} +// Returns whether |pid|'s code signature is trusted: +// - True if the caller is unsigned (there's nothing to verify). +// - True if |pid| satisfies the caller's designated requirement. +// - False otherwise (|pid| does not satisfy caller's designated requirement). +bool IsAcceptablyCodeSigned(pid_t pid) { base::ScopedCFTypeRef<SecCodeRef> own_code; - base::ScopedCFTypeRef<SecRequirementRef> own_designated_requirement; + base::ScopedCFTypeRef<CFDictionaryRef> own_signing_info; // Fetch the calling process's designated requirement. The shim can only be // validated if the caller has one (i.e. if the caller is code signed). @@ -133,9 +136,37 @@ // revisited after https://crbug.com/496298 is resolved. if (SecCodeCopySelf(kSecCSDefaultFlags, own_code.InitializeInto()) != errSecSuccess || - SecCodeCopyDesignatedRequirement( - own_code, kSecCSDefaultFlags, - own_designated_requirement.InitializeInto()) != errSecSuccess) { + SecCodeCopySigningInformation(own_code.get(), kSecCSSigningInformation, + own_signing_info.InitializeInto()) != + errSecSuccess) { + LOG(ERROR) << "Failed to get own code signing information."; + return false; + } + + auto* own_certificates = base::mac::GetValueFromDictionary<CFArrayRef>( + own_signing_info, kSecCodeInfoCertificates); + if (!own_certificates || CFArrayGetCount(own_certificates) < 1) { + return true; + } + + auto* own_certificate = base::mac::CFCast<SecCertificateRef>( + CFArrayGetValueAtIndex(own_certificates, 0)); + auto own_certificate_hash = CertificateSHA1Digest(own_certificate); + + base::ScopedCFTypeRef<CFStringRef> shim_requirement_string( + CFStringCreateWithFormat( + kCFAllocatorDefault, nullptr, + CFSTR( + "identifier \"app_mode_loader\" and certificate leaf = H\"%s\""), + own_certificate_hash.c_str())); + + base::ScopedCFTypeRef<SecRequirementRef> shim_requirement; + if (SecRequirementCreateWithString( + shim_requirement_string, kSecCSDefaultFlags, + shim_requirement.InitializeInto()) != errSecSuccess) { + LOG(ERROR) + << "Failed to create a SecRequirementRef from the requirement string \"" + << shim_requirement_string << "\""; return false; } @@ -152,11 +183,12 @@ if (SecCodeCopyGuestWithAttributes(nullptr, guest_attributes, kSecCSDefaultFlags, guest_code.InitializeInto())) { + LOG(ERROR) << "Failed to create a SecCodeRef from the app shim's pid."; return false; } return SecCodeCheckValidity(guest_code, kSecCSDefaultFlags, - own_designated_requirement) == errSecSuccess; + shim_requirement) == errSecSuccess; } // Attempts to launch a packaged app, prompting the user to enable it if @@ -304,19 +336,21 @@ Profile* profile, const Extension* extension, bool recreate_shims, - LaunchShimCallback launch_callback) { + apps::ShimLaunchedCallback launched_callback, + apps::ShimTerminatedCallback terminated_callback) { if (recreate_shims) { // Load the resources needed to build the app shim (icons, etc), and then // recreate the shim and launch it. web_app::GetShortcutInfoForApp( extension, profile, - base::BindOnce(&web_app::LaunchShim, - web_app::LaunchShimUpdateBehavior::RECREATE, - std::move(launch_callback))); + base::BindOnce( + &web_app::LaunchShim, + web_app::LaunchShimUpdateBehavior::RECREATE_UNCONDITIONALLY, + std::move(launched_callback), std::move(terminated_callback))); } else { web_app::LaunchShim( - web_app::LaunchShimUpdateBehavior::NO_UPDATE, - std::move(launch_callback), + web_app::LaunchShimUpdateBehavior::DO_NOT_RECREATE, + std::move(launched_callback), std::move(terminated_callback), web_app::ShortcutInfoForExtensionAndProfile(extension, profile)); } } @@ -504,13 +538,15 @@ void ExtensionAppShimHandler::OnShimLaunchRequested( AppShimHost* host, bool recreate_shims, - LaunchShimCallback launch_callback) { + apps::ShimLaunchedCallback launched_callback, + apps::ShimTerminatedCallback terminated_callback) { Profile* profile = nullptr; const Extension* extension = MaybeGetExtensionOrCloseHost(host, &profile); if (!profile || !extension) return; delegate_->LaunchShim(profile, extension, recreate_shims, - std::move(launch_callback)); + std::move(launched_callback), + std::move(terminated_callback)); } void ExtensionAppShimHandler::OnShimProcessConnected( @@ -641,7 +677,10 @@ // If the connecting shim process doesn't have an acceptable code signature, // reject the connection and recreate the shim. if (!IsAcceptablyCodeSigned(bootstrap->GetAppShimPid())) { - LOG(WARNING) << "Attaching app shim process is not signed, regenerating."; + // TODO(https://crbug.com/923612): Should only be here for a day or two. + LOG(ERROR) << "The attaching app shim's code signature is invalid. This " + "will fail in future builds of Chrome."; +#if 0 if (bootstrap->GetLaunchType() == APP_SHIM_LAUNCH_NORMAL) { constexpr bool recreate_shims = true; delegate_->LaunchShim(profile, extension, recreate_shims, @@ -649,6 +688,7 @@ } bootstrap->OnFailedToConnectToHost(APP_SHIM_LAUNCH_FAILED_VALIDATION); return; +#endif } AppShimHost* host = delegate_->AllowShimToConnect(profile, extension)
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h index 885a8db..bb5ddcc8 100644 --- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h +++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h
@@ -78,7 +78,8 @@ virtual void LaunchShim(Profile* profile, const extensions::Extension* extension, bool recreate_shims, - LaunchShimCallback launch_callback); + ShimLaunchedCallback launched_callback, + ShimTerminatedCallback terminated_callback); virtual void LaunchUserManager(); virtual void MaybeTerminate(); @@ -138,7 +139,8 @@ void OnShimLaunchRequested( AppShimHost* host, bool recreate_shims, - base::OnceCallback<void(base::Process)> launch_callback) override; + base::OnceCallback<void(base::Process)> launched_callback, + base::OnceClosure terminated_callback) override; void OnShimProcessConnected( std::unique_ptr<AppShimHostBootstrap> bootstrap) override; void OnShimClose(AppShimHost* host) override;
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc index 2306b06b8..465da676 100644 --- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc +++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc
@@ -78,12 +78,13 @@ void LaunchShim(Profile* profile, const Extension* extension, bool recreate_shim, - LaunchShimCallback launch_callback) override { + ShimLaunchedCallback launched_callback, + ShimTerminatedCallback terminated_callback) override { if (launch_shim_callback_capture_) - *launch_shim_callback_capture_ = std::move(launch_callback); + *launch_shim_callback_capture_ = std::move(launched_callback); DoLaunchShim(profile, extension, recreate_shim); } - void SetCaptureLaunchShimCallback(LaunchShimCallback* callback) { + void SetCaptureShimLaunchedCallback(ShimLaunchedCallback* callback) { launch_shim_callback_capture_ = callback; } @@ -123,7 +124,7 @@ } private: - LaunchShimCallback* launch_shim_callback_capture_ = nullptr; + ShimLaunchedCallback* launch_shim_callback_capture_ = nullptr; std::map<base::FilePath, base::OnceCallback<void(Profile*)>> callbacks_; AppShimHost* host_for_create_ = nullptr; bool allow_shim_to_connect_ = true; @@ -540,8 +541,8 @@ TEST_F(ExtensionAppShimHandlerTest, FailToLaunch) { // When the app activates, it requests a launch. - LaunchShimCallback launch_callback; - delegate_->SetCaptureLaunchShimCallback(&launch_callback); + ShimLaunchedCallback launch_callback; + delegate_->SetCaptureShimLaunchedCallback(&launch_callback); delegate_->SetHostForCreate(host_aa_.get()); EXPECT_CALL(*delegate_, DoLaunchShim(&profile_a_, extension_a_.get(), false)); handler_->OnAppActivated(&profile_a_, kTestAppIdA);
diff --git a/chrome/browser/autofill/autofill_autocomplete_browsertest.cc b/chrome/browser/autofill/autofill_autocomplete_browsertest.cc new file mode 100644 index 0000000..8727812c --- /dev/null +++ b/chrome/browser/autofill/autofill_autocomplete_browsertest.cc
@@ -0,0 +1,415 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/weak_ptr.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "base/time/time.h" +#include "chrome/browser/autofill/autocomplete_history_manager_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_navigator_params.h" +#include "chrome/browser/web_data_service_factory.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/browser/content_autofill_driver_factory.h" +#include "components/autofill/core/browser/autocomplete_history_manager.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/suggestion.h" +#include "components/autofill/core/browser/test_autofill_async_observer.h" +#include "components/autofill/core/browser/test_autofill_clock.h" +#include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_prefs.h" +#include "components/prefs/pref_service.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/test_utils.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using autofill::test::TestAutofillAsyncObserver; +using base::ASCIIToUTF16; +using testing::ElementsAre; +using testing::Field; + +using NotificationType = TestAutofillAsyncObserver::NotificationType; + +namespace autofill { + +namespace { +const char kDefaultAutocompleteInputId[] = "n300"; +const char kSimpleFormFileName[] = "autocomplete_simple_form.html"; +} // namespace + +class MockSuggestionsHandler + : public AutocompleteHistoryManager::SuggestionsHandler { + public: + MockSuggestionsHandler() : weak_ptr_factory_(this) {} + + void OnSuggestionsReturned( + int query_id, + bool autoselect_first_suggestion, + const std::vector<Suggestion>& suggestions) override { + last_suggestions_ = suggestions; + } + + base::WeakPtr<MockSuggestionsHandler> GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + + const std::vector<Suggestion>& last_suggestions() { + return last_suggestions_; + } + + private: + std::vector<Suggestion> last_suggestions_; + base::WeakPtrFactory<MockSuggestionsHandler> weak_ptr_factory_; +}; + +class BaseAutofillAutocompleteTest : public InProcessBrowserTest { + protected: + void SetUpOnMainThread() override { + active_browser_ = browser(); + + // Don't want Keychain coming up on Mac. + test::DisableSystemServices(pref_service()); + + ASSERT_TRUE(embedded_test_server()->Start()); + } + + void TearDownOnMainThread() override { + // Make sure to close any showing popups prior to tearing down the UI. + content::WebContents* web_contents = + active_browser_->tab_strip_model()->GetActiveWebContents(); + ContentAutofillDriverFactory::FromWebContents(web_contents) + ->DriverForFrame(web_contents->GetMainFrame()) + ->autofill_manager() + ->client() + ->HideAutofillPopup(); + test::ReenableSystemServices(); + } + + // Uses the browser to open the file named |filename| based on the given + // |disposition|. + void NavigateToFile(const char* filename, + const WindowOpenDisposition& disposition = + WindowOpenDisposition::NEW_FOREGROUND_TAB) { + GURL url = GetURL(filename); + NavigateParams params(active_browser_, url, ui::PAGE_TRANSITION_LINK); + params.disposition = disposition; + ui_test_utils::NavigateToURL(¶ms); + } + + // Fills in the default input with |value|, submits the form and waits + // for the value to have been saved in the DB or skipped, via observers. + void FillInputAndSubmit(const std::string& value, bool should_skip_save) { + const char js_format[] = + "document.getElementById('%s').value = '%s';" + "document.onclick = function() {" + " document.getElementById('testform').submit();" + "};"; + + const std::string js = base::StringPrintf( + js_format, kDefaultAutocompleteInputId, value.c_str()); + + ASSERT_TRUE(content::ExecuteScript(web_contents(), js)); + + // Set up observer for Autocomplete form submissions. + TestAutofillAsyncObserver observer( + should_skip_save ? NotificationType::AutocompleteFormSkipped + : NotificationType::AutocompleteFormSubmitted, + /*detach_on_notify=*/true); + autocomplete_history_manager()->Attach(&observer); + + // Simulate a mouse click to submit the form because form submissions not + // triggered by user gestures are ignored. + content::SimulateMouseClick( + active_browser_->tab_strip_model()->GetActiveWebContents(), 0, + blink::WebMouseEvent::Button::kLeft); + + // Wait for the form to be submitted. + observer.Wait(); + + if (!should_skip_save) { + // Wait for data to have been saved in the DB. + WaitForDBTasks(); + } + } + + // Validates that there is only one available autocomplete suggestion for the + // given |prefix|, and its value is equal to |expected_value|. + void ValidateSingleValue(const std::string& prefix, + const std::string& expected_value) { + MockSuggestionsHandler handler; + GetAutocompleteSuggestions(kDefaultAutocompleteInputId, prefix, handler); + + EXPECT_THAT( + handler.last_suggestions(), + ElementsAre(Field(&Suggestion::value, ASCIIToUTF16(expected_value)))); + } + + void ValidateNoValue() { + MockSuggestionsHandler handler; + GetAutocompleteSuggestions(kDefaultAutocompleteInputId, "", handler); + + EXPECT_TRUE(handler.last_suggestions().empty()); + } + + void ReinitializeAutocompleteHistoryManager() { + autocomplete_history_manager()->Init(GetWebDataService(), pref_service(), + current_profile()->IsOffTheRecord()); + } + + void set_active_browser(Browser* browser) { active_browser_ = browser; } + + AutocompleteHistoryManager* autocomplete_history_manager() { + return AutocompleteHistoryManagerFactory::GetForProfile(current_profile()); + } + + // Enqueues a RunLoop::QuitClosure using the DB task runner, which executes + // given tasks sequentially. Then block current execution until the closure + // has been called. + void WaitForDBTasks() { + base::RunLoop run_loop; + + // The quit closure will only be called after all already-queued DB tasks + // have finished running. + GetWebDataService()->GetDBTaskRunner()->PostTask(FROM_HERE, + run_loop.QuitClosure()); + run_loop.Run(); + } + + PrefService* pref_service() { return active_browser_->profile()->GetPrefs(); } + + base::test::ScopedFeatureList scoped_features_; + + private: + void GetAutocompleteSuggestions(const std::string& input_name, + const std::string& prefix, + autofill::MockSuggestionsHandler& handler) { + autocomplete_history_manager()->OnGetAutocompleteSuggestions( + 1, true, false, ASCIIToUTF16(input_name), ASCIIToUTF16(prefix), "input", + handler.GetWeakPtr()); + + // Make sure the DB task gets executed. + WaitForDBTasks(); + } + + GURL GetURL(const std::string& filename) { + return embedded_test_server()->GetURL("/autofill/" + filename); + } + + content::WebContents* web_contents() { + return active_browser_->tab_strip_model()->GetActiveWebContents(); + } + + scoped_refptr<autofill::AutofillWebDataService> GetWebDataService() { + return WebDataServiceFactory::GetAutofillWebDataForProfile( + current_profile(), ServiceAccessType::EXPLICIT_ACCESS); + } + + Profile* current_profile() { return active_browser_->profile(); } + + Browser* active_browser_; +}; + +class AutofillAutocompleteTest : public BaseAutofillAutocompleteTest, + public testing::WithParamInterface<bool> { + protected: + // InProcessBrowserTest overrides: + void SetUp() override { + scoped_features_.InitWithFeatureState( + features::kAutocompleteRetentionPolicyEnabled, GetParam()); + InProcessBrowserTest::SetUp(); + } +}; + +// Tests that a user can save a simple Autocomplete value. +IN_PROC_BROWSER_TEST_P(AutofillAutocompleteTest, SubmitSimpleValue_Saves) { + std::string prefix = "Some"; + std::string test_value = "SomeName!"; + NavigateToFile(kSimpleFormFileName); + FillInputAndSubmit(test_value, /*should_skip_save=*/false); + ValidateSingleValue(prefix, test_value); +} + +// Tests that we don't save new autocomplete entries when in Incognito. +IN_PROC_BROWSER_TEST_P(AutofillAutocompleteTest, + SubmitSimpleValue_OTR_DoesNotSave) { + set_active_browser(CreateIncognitoBrowser()); + + std::string prefix = "Some"; + std::string test_value = "SomeName!"; + NavigateToFile(kSimpleFormFileName, WindowOpenDisposition::OFF_THE_RECORD); + FillInputAndSubmit(test_value, /*should_skip_save=*/true); + ValidateNoValue(); +} + +// Tests that we don't save new autocomplete entries when Autocomplete was +// disabled by the user. +IN_PROC_BROWSER_TEST_P(AutofillAutocompleteTest, + SubmitSimpleValue_Disabled_DoesNotSave) { + pref_service()->SetBoolean(prefs::kAutofillProfileEnabled, false); + std::string prefix = "Some"; + std::string test_value = "SomeName!"; + NavigateToFile(kSimpleFormFileName); + FillInputAndSubmit(test_value, /*should_skip_save=*/true); + ValidateNoValue(); +} + +// Tests that initialization of the AutocompleteHistoryManager sets the +// retention policy last version ran preference when the flag is enabled. +IN_PROC_BROWSER_TEST_P(AutofillAutocompleteTest, + RetentionPolicy_Init_SavesVersionPref) { + // At this point, AutocompleteHistoryManager was already initialized. + bool retention_policy_enabled = GetParam(); + + int saved_version = pref_service()->GetInteger( + prefs::kAutocompleteLastVersionRetentionPolicy); + + if (retention_policy_enabled) { + EXPECT_EQ(CHROME_VERSION_MAJOR, saved_version); + } else { + EXPECT_NE(CHROME_VERSION_MAJOR, saved_version); + } +} + +// TODO(crbug.com/920214): Convert these tests as part of the flag cleanup. +class AutofillAutocompleteRetentionEnabledTest + : public BaseAutofillAutocompleteTest { + protected: + // AutofillAutocompleteTest overrides: + void SetUp() override { + scoped_features_.InitAndEnableFeature( + features::kAutocompleteRetentionPolicyEnabled); + InProcessBrowserTest::SetUp(); + } +}; + +// Tests that the retention policy cleanup removes an expired entry. +IN_PROC_BROWSER_TEST_F(AutofillAutocompleteRetentionEnabledTest, + RetentionPolicy_RemovesExpiredEntry) { + // Go back in time, far enough so that we'll expire the entry. + TestAutofillClock test_clock; + base::TimeDelta days_delta = + base::TimeDelta::FromDays(2 * kAutocompleteRetentionPolicyPeriodInDays); + test_clock.SetNow(AutofillClock::Now() - days_delta); + + // Add an entry. + std::string prefix = "Some"; + std::string test_value = "SomeName!"; + NavigateToFile(kSimpleFormFileName); + FillInputAndSubmit(test_value, /*should_skip_save=*/false); + ValidateSingleValue(prefix, test_value); + + // Come back to current time, modify the saved major version and setup our + // observer. + test_clock.Advance(days_delta); + pref_service()->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, + CHROME_VERSION_MAJOR - 1); + TestAutofillAsyncObserver observer(NotificationType::AutocompleteCleanupDone, + /*detach_on_notify=*/true); + autocomplete_history_manager()->Attach(&observer); + + // Trigger the retention policy cleanup (by reinitializing the + // AutocompleteHistoryManager), and wait for the cleanup to complete. + ReinitializeAutocompleteHistoryManager(); + observer.Wait(); + + ValidateNoValue(); +} + +// Tests that the retention policy cleanup does not remove a valid entry (e.g. +// 20 days old). +IN_PROC_BROWSER_TEST_F(AutofillAutocompleteRetentionEnabledTest, + RetentionPolicy_DoesNot_RemoveValidEntry) { + // Go back in time, but not far enough so that we'd expire the entry. + TestAutofillClock test_clock; + base::TimeDelta days_delta = + base::TimeDelta::FromDays(kAutocompleteRetentionPolicyPeriodInDays - 2); + test_clock.SetNow(AutofillClock::Now() - days_delta); + + // Add an entry. + std::string prefix = "Some"; + std::string test_value = "SomeName!"; + NavigateToFile(kSimpleFormFileName); + FillInputAndSubmit(test_value, /*should_skip_save=*/false); + ValidateSingleValue(prefix, test_value); + + // Come back to current time, modify the saved major version and setup our + // observer. + test_clock.Advance(days_delta); + pref_service()->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, + CHROME_VERSION_MAJOR - 1); + TestAutofillAsyncObserver observer(NotificationType::AutocompleteCleanupDone, + /*detach_on_notify=*/true); + autocomplete_history_manager()->Attach(&observer); + + // Trigger the retention policy cleanup (by reinitializing the + // AutocompleteHistoryManager), and wait for the cleanup to complete. + ReinitializeAutocompleteHistoryManager(); + observer.Wait(); + + // Verify that the entry is still there. + ValidateSingleValue(prefix, test_value); +} + +// TODO(crbug.com/920214): Remove these tests as part of the flag cleanup. +class AutofillAutocompleteRetentionDisabledTest + : public BaseAutofillAutocompleteTest { + protected: + // AutofillAutocompleteTest overrides: + void SetUp() override { + scoped_features_.InitAndDisableFeature( + features::kAutocompleteRetentionPolicyEnabled); + InProcessBrowserTest::SetUp(); + } +}; + +// Tests that we don't cleanup expired entries when the Autocomplete Retention +// Policy feature flag is disabled. +IN_PROC_BROWSER_TEST_F(AutofillAutocompleteRetentionDisabledTest, + RetentionPolicy_DoesNot_RemoveExpiredEntry) { + // Go back in time, far enough so that we would expire the entry when the flag + // is on. + TestAutofillClock test_clock; + base::TimeDelta days_delta = + base::TimeDelta::FromDays(2 * kAutocompleteRetentionPolicyPeriodInDays); + test_clock.SetNow(AutofillClock::Now() - days_delta); + + // Add an entry. + std::string prefix = "Some"; + std::string test_value = "SomeName!"; + NavigateToFile(kSimpleFormFileName); + FillInputAndSubmit(test_value, /*should_skip_save=*/false); + ValidateSingleValue(prefix, test_value); + + // Come back to current time, modify the saved major version and setup our + // observer. + test_clock.Advance(days_delta); + pref_service()->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, + CHROME_VERSION_MAJOR - 1); + + // Fake-trigger the retention policy cleanup (since the flag is off it won't), + // and then queue up a wait DB task before we validate the values. Worst case + // of order of DB tasks should then be: + // 1. Cleanup, + // 2. Wait DB Task, + // 3. Get Values DB task (for validation logic). + ReinitializeAutocompleteHistoryManager(); + + WaitForDBTasks(); + + // Verify that the entry is still there. + ValidateSingleValue(prefix, test_value); +} + +INSTANTIATE_TEST_CASE_P(, AutofillAutocompleteTest, testing::Bool()); + +} // namespace autofill
diff --git a/chrome/browser/background_fetch/background_fetch_browsertest.cc b/chrome/browser/background_fetch/background_fetch_browsertest.cc index 6323f47e..6fd30f0 100644 --- a/chrome/browser/background_fetch/background_fetch_browsertest.cc +++ b/chrome/browser/background_fetch/background_fetch_browsertest.cc
@@ -758,6 +758,26 @@ } } +IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest, AbortFromUI) { + std::vector<OfflineItem> items; + // Creates a registration with more than one request. + ASSERT_NO_FATAL_FAILURE( + RunScriptAndWaitForOfflineItems("StartFetchWithMultipleFiles()", &items)); + ASSERT_EQ(items.size(), 1u); + + // Simulate an abort from the UI. + delegate_->CancelDownload(items[0].id); + + // Wait for an abort event to be dispatched. This is safe because there are + // more requests to process than the scheduler will handle, and every request + // needs to contact the delegate. Since the abort originates from the + // delegate, this fetch will be aborted before the fetch completes. + // Pass in a no-op function since we only want to wait for a message at this + // point. + ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingMessage( + "(() => {})()", "backgroundfetchabort")); +} + IN_PROC_BROWSER_TEST_F(BackgroundFetchBrowserTest, FetchCanBePausedAndResumed) { offline_content_provider_observer_->PauseOnNextUpdate(); ASSERT_NO_FATAL_FAILURE(RunScriptAndCheckResultingMessage(
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc index d6cb264..6c931a6 100644 --- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc +++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -711,8 +711,15 @@ auto job_details_iter = job_details_map_.find(unique_id); DCHECK(job_details_iter != job_details_map_.end()); - job_details_iter->second.cancelled_from_ui = true; + auto& job_details = job_details_iter->second; + if (job_details.job_state == JobDetails::State::kDownloadsComplete || + job_details.job_state == JobDetails::State::kJobComplete) { + // The cancel event arrived after the fetch was complete; ignore it. + return; + } + + job_details.cancelled_from_ui = true; Abort(unique_id); if (auto client = GetClient(unique_id)) { @@ -729,6 +736,12 @@ return; JobDetails& job_details = job_details_iter->second; + if (job_details.job_state == JobDetails::State::kDownloadsComplete || + job_details.job_state == JobDetails::State::kJobComplete) { + // The pause event arrived after the fetch was complete; ignore it. + return; + } + job_details.job_state = JobDetails::State::kStartedButPaused; job_details.UpdateOfflineItem(); for (auto& download_guid_pair : job_details.current_fetch_guids)
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index 359e2fb4..2ad0c5d5 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -675,10 +675,6 @@ <include name="IDR_IME_WINDOW_CLOSE_C" file="resources\input_ime\ime_window_close_click.png" type="BINDATA" /> <include name="IDR_IME_WINDOW_CLOSE_H" file="resources\input_ime\ime_window_close_hover.png" type="BINDATA" /> </if> - <include name="IDR_NACL_LOADER_MANIFEST" file="../../components/nacl/loader/nacl_loader_manifest.json" type="BINDATA" /> - <if expr="is_win"> - <include name="IDR_NACL_BROKER_MANIFEST" file="../../components/nacl/broker/nacl_broker_manifest.json" type="BINDATA" /> - </if> <if expr="is_win"> <include name="IDR_WELCOME_WIN10_DEFAULT_WEBP" file="resources\welcome\default.webp" type="BINDATA" /> <include name="IDR_WELCOME_WIN10_PIN_WEBP" file="resources\welcome\pin.webp" type="BINDATA" />
diff --git a/chrome/browser/browsing_data/README.md b/chrome/browser/browsing_data/README.md new file mode 100644 index 0000000..b48040e --- /dev/null +++ b/chrome/browser/browsing_data/README.md
@@ -0,0 +1,36 @@ +# CookiesTreeModel + +A CookiesTreeModel is instantiated in multiple places in Chrome: + +* "All cookies and site data" (chrome://settings/siteData) +* "All sites" (chrome://settings/content/all) +* "Cookies in use" display off the origin chip in the infobar + +## BrowsingDataXYZHelper + +Instances of this type are used to fully populate a CookiesTreeModel +with full details (e.g. origin/size/modified) for different storage +types, e.g. to report storage used by all origins. + +When StartFetching is called, a call is made into the relevant storage +context to enumerate usage info - usually, a set of tuples of (origin, +size, last modified). The CookiesTreeModel assembles this into the +tree of nodes used to populate UI. + +Some UI also uses this to delete origin data, which again calls into +the storage context. + +## CannedBrowsingDataXYZHelper + +Subclass of the above. These are created to sparsely populate a +CookiesTreeModel on demand by LocalSharedObjectContainer, with only +some details (e.g. full details for cookies, but only the usage of +other storage typess). + +* TabSpecificContentSettings is notified on storage access/blocked. +* It calls into the "canned" helper instance for the storage type. +* The "canned" instance records necessary "pending" info about the access. +* On demand, the "pending" info is used to populate a CookiesTreeModel. + +This "pending" info only needs to record the origin for most storage +types.
diff --git a/chrome/browser/browsing_data/cookies_tree_model.cc b/chrome/browser/browsing_data/cookies_tree_model.cc index 02e4730..3deb7d5 100644 --- a/chrome/browser/browsing_data/cookies_tree_model.cc +++ b/chrome/browser/browsing_data/cookies_tree_model.cc
@@ -1952,14 +1952,16 @@ } // static std::unique_ptr<CookiesTreeModel> CookiesTreeModel::CreateForProfile( - Profile* profile) { + Profile* profile, + bool omit_cookies) { auto* storage_partition = content::BrowserContext::GetDefaultStoragePartition(profile); auto* file_system_context = storage_partition->GetFileSystemContext(); + auto* cookie_helper = + omit_cookies ? nullptr : new BrowsingDataCookieHelper(storage_partition); auto container = std::make_unique<LocalDataContainer>( - new BrowsingDataCookieHelper(storage_partition), - new BrowsingDataDatabaseHelper(profile), + cookie_helper, new BrowsingDataDatabaseHelper(profile), new BrowsingDataLocalStorageHelper(profile), /*session_storage_helper=*/nullptr, new BrowsingDataAppCacheHelper(profile),
diff --git a/chrome/browser/browsing_data/cookies_tree_model.h b/chrome/browser/browsing_data/cookies_tree_model.h index bc14fba0..eafdebf 100644 --- a/chrome/browser/browsing_data/cookies_tree_model.h +++ b/chrome/browser/browsing_data/cookies_tree_model.h
@@ -375,7 +375,9 @@ void SetBatchExpectation(int batches_expected, bool reset); // Create CookiesTreeModel by profile info. - static std::unique_ptr<CookiesTreeModel> CreateForProfile(Profile* profile); + static std::unique_ptr<CookiesTreeModel> CreateForProfile( + Profile* profile, + bool omit_cookies = false); private: enum CookieIconIndex { COOKIE = 0, DATABASE = 1 };
diff --git a/chrome/browser/browsing_data/local_data_container.cc b/chrome/browser/browsing_data/local_data_container.cc index 233107fa..c4cd2c3 100644 --- a/chrome/browser/browsing_data/local_data_container.cc +++ b/chrome/browser/browsing_data/local_data_container.cc
@@ -49,11 +49,13 @@ DCHECK(!model_); model_ = model; - batches_started_ = 1; - DCHECK(cookie_helper_.get()); - cookie_helper_->StartFetching( - base::BindOnce(&LocalDataContainer::OnCookiesModelInfoLoaded, - weak_ptr_factory_.GetWeakPtr())); + batches_started_ = 0; + if (cookie_helper_.get()) { + batches_started_++; + cookie_helper_->StartFetching( + base::BindOnce(&LocalDataContainer::OnCookiesModelInfoLoaded, + weak_ptr_factory_.GetWeakPtr())); + } if (database_helper_.get()) { batches_started_++;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 2451cd3..73886338 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -182,6 +182,7 @@ #include "components/autofill/core/common/autofill_switches.h" #include "components/browsing_data/core/browsing_data_utils.h" #include "components/cdm/browser/cdm_message_filter_android.h" +#include "components/certificate_matching/certificate_principal_pattern.h" #include "components/cloud_devices/common/cloud_devices_switches.h" #include "components/content_settings/core/browser/content_settings_utils.h" #include "components/content_settings/core/browser/cookie_settings.h" @@ -331,6 +332,13 @@ #include "url/gurl.h" #include "url/origin.h" +#if BUILDFLAG(ENABLE_NACL) +#include "components/nacl/loader/nacl_loader_manifest.h" +#if defined(OS_WIN) && defined(ARCH_CPU_X86) +#include "components/nacl/broker/nacl_broker_manifest.h" +#endif +#endif + #if defined(OS_WIN) #include "base/strings/string_tokenizer.h" #include "chrome/browser/chrome_browser_main_win.h" @@ -707,24 +715,6 @@ return true; } -bool CertMatchesFilter(const net::X509Certificate& cert, - const base::DictionaryValue& filter) { - // TODO(markusheintz): This is the minimal required filter implementation. - // Implement a better matcher. - - // An empty filter matches any client certificate since no requirements are - // specified at all. - if (filter.empty()) - return true; - - std::string common_name; - if (filter.GetString("ISSUER.CN", &common_name) && - (cert.issuer().common_name == common_name)) { - return true; - } - return false; -} - #if !defined(OS_ANDROID) // Check if the current url is whitelisted based on a list of whitelisted urls. bool IsURLWhitelisted(const GURL& current_url, @@ -2751,6 +2741,12 @@ namespace { +certificate_matching::CertificatePrincipalPattern +ParseCertificatePrincipalPattern(const base::Value* pattern) { + return certificate_matching::CertificatePrincipalPattern:: + ParseFromOptionalDict(pattern, "CN", "L", "O", "OU"); +} + // Attempts to auto-select a client certificate according to the value of // |CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE| content setting for // |requesting_url|. If no certificate was auto-selected, returns nullptr. @@ -2765,32 +2761,12 @@ requesting_url, requesting_url, CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, std::string(), NULL); - if (!setting) + if (!setting || !setting->is_dict()) return nullptr; - const base::DictionaryValue* setting_dict; - if (!setting->GetAsDictionary(&setting_dict)) { - NOTREACHED(); - return nullptr; - } - const base::Value* filters = - setting_dict->FindKeyOfType("filters", base::Value::Type::LIST); - if (filters) { - for (const base::Value& filter : filters->GetList()) { - const base::DictionaryValue* filter_dict; - if (!filter.GetAsDictionary(&filter_dict)) { - NOTREACHED(); - continue; - } - // Use the first certificate that is matched by the filter. - for (size_t i = 0; i < client_certs.size(); ++i) { - if (CertMatchesFilter(*client_certs[i]->certificate(), *filter_dict)) { - return std::move(client_certs[i]); - } - } - } - } else { + setting->FindKeyOfType("filters", base::Value::Type::LIST); + if (!filters) { // |setting_dict| has the wrong format (e.g. single filter instead of a // list of filters). This content setting is only provided by // the |PolicyProvider|, which should always set it to a valid format. @@ -2798,6 +2774,23 @@ host_content_settings_map->SetWebsiteSettingDefaultScope( requesting_url, requesting_url, CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, std::string(), nullptr); + return nullptr; + } + + for (const base::Value& filter : filters->GetList()) { + DCHECK(filter.is_dict()); + + auto issuer_pattern = ParseCertificatePrincipalPattern( + filter.FindKeyOfType("ISSUER", base::Value::Type::DICTIONARY)); + auto subject_pattern = ParseCertificatePrincipalPattern( + filter.FindKeyOfType("SUBJECT", base::Value::Type::DICTIONARY)); + // Use the first certificate that is matched by the filter. + for (auto& client_cert : client_certs) { + if (issuer_pattern.Matches(client_cert->certificate()->issuer()) && + subject_pattern.Matches(client_cert->certificate()->subject())) { + return std::move(client_cert); + } + } } return nullptr; @@ -3944,17 +3937,17 @@ return base::nullopt; } -std::vector<content::ContentBrowserClient::ServiceManifestInfo> +std::vector<service_manager::Manifest> ChromeContentBrowserClient::GetExtraServiceManifests() { - return std::vector<content::ContentBrowserClient::ServiceManifestInfo>({ + return std::vector<service_manager::Manifest> { + GetChromeRendererManifest(), #if BUILDFLAG(ENABLE_NACL) - {nacl::kNaClLoaderServiceName, IDR_NACL_LOADER_MANIFEST}, -#if defined(OS_WIN) - {nacl::kNaClBrokerServiceName, IDR_NACL_BROKER_MANIFEST}, + nacl_loader::GetManifest(), +#if defined(OS_WIN) && defined(ARCH_CPU_X86) + nacl_broker::GetManifest(), #endif // defined(OS_WIN) #endif // BUILDFLAG(ENABLE_NACL) - {chrome::mojom::kRendererServiceName, -1, GetChromeRendererManifest()}, - }); + }; } std::vector<std::string> ChromeContentBrowserClient::GetStartupServices() {
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index ef44018..c0a8e73f 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -409,8 +409,7 @@ const service_manager::Identity& id) override; base::Optional<service_manager::Manifest> GetServiceManifestOverlay( base::StringPiece name) override; - std::vector<content::ContentBrowserClient::ServiceManifestInfo> - GetExtraServiceManifests() override; + std::vector<service_manager::Manifest> GetExtraServiceManifests() override; std::vector<std::string> GetStartupServices() override; void OpenURL(content::SiteInstance* site_instance, const content::OpenURLParams& params,
diff --git a/chrome/browser/chrome_security_exploit_browsertest.cc b/chrome/browser/chrome_security_exploit_browsertest.cc index 93d148f..33986aeb 100644 --- a/chrome/browser/chrome_security_exploit_browsertest.cc +++ b/chrome/browser/chrome_security_exploit_browsertest.cc
@@ -31,6 +31,7 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "storage/browser/blob/blob_registry_impl.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/mojom/blob/blob_url_store.mojom-test-utils.h" #include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h" // The goal of these tests is to "simulate" exploited renderer processes, which
diff --git a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc index 8af1f85..69ae8ea 100644 --- a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc +++ b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
@@ -9,6 +9,7 @@ #include "ash/accessibility/accessibility_focus_ring_layer.h" #include "ash/public/cpp/ash_features.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/status_area_widget_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/status_area_widget_test_api.test-mojom.h" #include "ash/root_window_controller.h" #include "ash/shell.h" @@ -288,6 +289,7 @@ ash::AccessibilityFocusRingController* controller = ash::Shell::Get()->accessibility_focus_ring_controller(); + controller->SetNoFadeForTesting(); const ash::AccessibilityFocusRingGroup* focus_ring_group = controller->GetFocusRingGroupForTesting( extension_misc::kSelectToSpeakExtensionId);
diff --git a/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.cc b/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.cc index ee45c07..7e5a2a3 100644 --- a/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.cc +++ b/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.cc
@@ -8,6 +8,7 @@ #include "chrome/browser/chromeos/child_accounts/consumer_status_reporting_service.h" #include "chrome/browser/chromeos/child_accounts/consumer_status_reporting_service_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chromeos/dbus/dbus_thread_manager.h" #include "components/session_manager/core/session_manager.h" namespace chromeos { @@ -21,6 +22,7 @@ arc_app_prefs->AddObserver(this); session_manager::SessionManager::Get()->AddObserver(this); net::NetworkChangeNotifier::AddNetworkChangeObserver(this); + DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this); } EventBasedStatusReportingService::~EventBasedStatusReportingService() = default; @@ -61,6 +63,12 @@ RequestStatusReport("Request status report due to device going online."); } +void EventBasedStatusReportingService::SuspendDone( + const base::TimeDelta& duration) { + RequestStatusReport( + "Request status report after a suspend has been completed."); +} + void EventBasedStatusReportingService::RequestStatusReport( const std::string& reason) { VLOG(1) << reason; @@ -75,6 +83,7 @@ arc_app_prefs->RemoveObserver(this); session_manager::SessionManager::Get()->RemoveObserver(this); net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); + DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.h b/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.h index 7d785b2..0eaa174 100644 --- a/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.h +++ b/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.h
@@ -8,7 +8,9 @@ #include <string> #include "base/macros.h" +#include "base/time/time.h" #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" +#include "chromeos/dbus/power_manager_client.h" #include "components/keyed_service/core/keyed_service.h" #include "components/session_manager/core/session_manager_observer.h" #include "net/base/network_change_notifier.h" @@ -26,11 +28,13 @@ // * Device lock // * Device unlock // * Device connected +// * Device returns from suspend mode class EventBasedStatusReportingService : public KeyedService, public ArcAppListPrefs::Observer, public session_manager::SessionManagerObserver, - public net::NetworkChangeNotifier::NetworkChangeObserver { + public net::NetworkChangeNotifier::NetworkChangeObserver, + public PowerManagerClient::Observer { public: explicit EventBasedStatusReportingService(content::BrowserContext* context); ~EventBasedStatusReportingService() override; @@ -48,6 +52,9 @@ void OnNetworkChanged( net::NetworkChangeNotifier::ConnectionType type) override; + // PowerManagerClient::Observer: + void SuspendDone(const base::TimeDelta& duration) override; + private: void RequestStatusReport(const std::string& reason);
diff --git a/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service_unittest.cc b/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service_unittest.cc index 8e76c3e..5354770 100644 --- a/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service_unittest.cc +++ b/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service_unittest.cc
@@ -13,6 +13,8 @@ #include "chrome/browser/supervised_user/supervised_user_constants.h" #include "chrome/browser/ui/app_list/arc/arc_app_test.h" #include "chrome/test/base/testing_profile.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_power_manager_client.h" #include "components/account_id/account_id.h" #include "components/arc/common/app.mojom.h" #include "components/keyed_service/core/keyed_service.h" @@ -56,6 +58,9 @@ ~EventBasedStatusReportingServiceTest() override = default; void SetUp() override { + DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient( + std::make_unique<FakePowerManagerClient>()); + profile_.SetSupervisedUserId(supervised_users::kChildAccountSUID); arc_test_.SetUp(profile()); @@ -77,7 +82,10 @@ consumer_status_reporting_service); } - void TearDown() override { arc_test_.TearDown(); } + void TearDown() override { + arc_test_.TearDown(); + DBusThreadManager::Shutdown(); + } void SetConnectionType(net::NetworkChangeNotifier::ConnectionType type) { notifier_.SetConnectionType(type); @@ -88,6 +96,11 @@ arc::mojom::AppHost* app_host() { return arc_test_.arc_app_list_prefs(); } Profile* profile() { return &profile_; } + FakePowerManagerClient* power_manager_client() { + return static_cast<FakePowerManagerClient*>( + DBusThreadManager::Get()->GetPowerManagerClient()); + } + TestingConsumerStatusReportingService* test_consumer_status_reporting_service() { return test_consumer_status_reporting_service_; @@ -187,6 +200,16 @@ 1, test_consumer_status_reporting_service()->performed_status_reports()); } +TEST_F(EventBasedStatusReportingServiceTest, ReportWhenSuspendIsDone) { + EventBasedStatusReportingService service(profile()); + + ASSERT_EQ( + 0, test_consumer_status_reporting_service()->performed_status_reports()); + power_manager_client()->SendSuspendDone(); + EXPECT_EQ( + 1, test_consumer_status_reporting_service()->performed_status_reports()); +} + TEST_F(EventBasedStatusReportingServiceTest, ReportForMultipleEvents) { EventBasedStatusReportingService service(profile()); SetConnectionType( @@ -213,6 +236,9 @@ app_host()->OnPackageModified(arc::mojom::ArcPackageInfo::New()); EXPECT_EQ( 5, test_consumer_status_reporting_service()->performed_status_reports()); + power_manager_client()->SendSuspendDone(); + EXPECT_EQ( + 6, test_consumer_status_reporting_service()->performed_status_reports()); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc index aadc7ed..7ba87fe 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -8,7 +8,6 @@ #include <utility> #include "base/strings/stringprintf.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/file_manager/file_manager_string_util.h" #include "chrome/browser/chromeos/file_manager/open_with_browser.h" #include "chrome/browser/chromeos/login/demo_mode/demo_session.h" @@ -18,7 +17,6 @@ #include "chromeos/system/statistics_provider.h" #include "extensions/common/extension_l10n_util.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/base/webui/web_ui_util.h" namespace extensions { @@ -55,9 +53,6 @@ base::FeatureList::IsEnabled(chromeos::features::kMyFilesVolume)); dict->SetString("UI_LOCALE", extension_l10n_util::CurrentLocaleOrDefault()); - const std::string& app_locale = g_browser_process->GetApplicationLocale(); - webui::SetLoadTimeDataDefaults(app_locale, dict.get()); - return RespondNow(OneArgument(std::move(dict))); }
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc index ce77284..38d3bbe 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
@@ -292,6 +292,8 @@ std::make_unique<std::string>(volume.volume_label()); volume_metadata->disk_file_system_type = std::make_unique<std::string>(volume.file_system_type()); + volume_metadata->drive_label = + std::make_unique<std::string>(volume.drive_label()); switch (volume.type()) { case VOLUME_TYPE_GOOGLE_DRIVE:
diff --git a/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc b/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc index 5e7610e..771b96a 100644 --- a/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc
@@ -79,7 +79,12 @@ StartTest(); } -IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, NativeMediaKey) { +#if defined(OS_CHROMEOS) && defined(MEMORY_SANITIZER) +#define MAYBE_NativeMediaKey DISABLED_NativeMediaKey +#else +#define MAYBE_NativeMediaKey NativeMediaKey +#endif +IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, MAYBE_NativeMediaKey) { set_test_case_name("mediaKeyNative"); StartTest(); }
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc index 14959361..425c188 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -10,6 +10,7 @@ #include <utility> #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/shell_test_api.test-mojom.h" #include "base/containers/circular_deque.h" #include "base/files/file_path.h" @@ -594,11 +595,13 @@ RemovableTestVolume(const std::string& name, VolumeType volume_type, chromeos::DeviceType device_type, - const base::FilePath& device_path) + const base::FilePath& device_path, + const std::string& drive_label) : LocalTestVolume(name), volume_type_(volume_type), device_type_(device_type), - device_path_(device_path) {} + device_path_(device_path), + drive_label_(drive_label) {} ~RemovableTestVolume() override = default; bool PreparePartitionTestEntries(Profile* profile) { @@ -643,7 +646,8 @@ // Expose the mount point with the given volume and device type. VolumeManager::Get(profile)->AddVolumeForTesting( - root_path(), volume_type_, device_type_, read_only_, device_path_); + root_path(), volume_type_, device_type_, read_only_, device_path_, + drive_label_); base::RunLoop().RunUntilIdle(); return true; } @@ -657,6 +661,7 @@ const chromeos::DeviceType device_type_; const base::FilePath& device_path_; const bool read_only_ = false; + const std::string drive_label_; DISALLOW_COPY_AND_ASSIGN(RemovableTestVolume); }; @@ -1633,18 +1638,21 @@ "target1:0:0/1:0:0:0"; const base::FilePath usb_device_path(kSingleUsbDevicePath); - // Create partition volumes with the same device path. + // Create partition volumes with the same device path and drive label. partition_1_ = std::make_unique<RemovableTestVolume>( "partition-1", VOLUME_TYPE_REMOVABLE_DISK_PARTITION, - chromeos::DEVICE_TYPE_USB, partition_device_path); + chromeos::DEVICE_TYPE_USB, partition_device_path, + "PARTITION_DRIVE_LABEL"); partition_2_ = std::make_unique<RemovableTestVolume>( "partition-2", VOLUME_TYPE_REMOVABLE_DISK_PARTITION, - chromeos::DEVICE_TYPE_USB, partition_device_path); + chromeos::DEVICE_TYPE_USB, partition_device_path, + "PARTITION_DRIVE_LABEL"); - // Create an unpartitioned usb volume with a unique device path. + // Create an unpartitioned usb volume with a unique device path and + // unique device label. single_usb_volume_ = std::make_unique<RemovableTestVolume>( "singleUSB", VOLUME_TYPE_REMOVABLE_DISK_PARTITION, - chromeos::DEVICE_TYPE_USB, usb_device_path); + chromeos::DEVICE_TYPE_USB, usb_device_path, "SINGLE_DRIVE_LABEL"); // Create fake entries on partitions. ASSERT_TRUE(partition_1_->PreparePartitionTestEntries(profile()));
diff --git a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc index 5cba038e..24e63e6 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
@@ -7,9 +7,11 @@ #include "base/logging.h" #include "base/strings/stringprintf.h" #include "base/values.h" +#include "chrome/browser/browser_process.h" #include "chrome/grit/generated_resources.h" #include "components/strings/grit/components_strings.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/webui/web_ui_util.h" #include "ui/strings/grit/ui_strings.h" namespace { @@ -22,11 +24,6 @@ const char kGoogleDriveOverviewUrl[] = "https://support.google.com/chromebook/?p=filemanager_drive"; -// Location of Google drive redeem page. -const char kGoogleDriveRedeemUrl[] = - "http://www.google.com/intl/en/chrome/devices/goodies.html" - "?utm_source=filesapp&utm_medium=banner&utm_campaign=gsg"; - // Location of Google Drive specific help. const char kGoogleDriveHelpUrl[] = "https://support.google.com/chromebook/?p=filemanager_drivehelp"; @@ -145,16 +142,12 @@ IDS_FILE_BROWSER_DRIVE_SPACE_AVAILABLE_LONG); SET_STRING("DRIVE_VISIT_DRIVE_GOOGLE_COM", IDS_FILE_BROWSER_DRIVE_VISIT_DRIVE_GOOGLE_COM); - SET_STRING("DRIVE_WELCOME_CHECK_ELIGIBILITY", - IDS_FILE_BROWSER_DRIVE_WELCOME_CHECK_ELIGIBILITY); SET_STRING("DRIVE_WELCOME_DISMISS", IDS_FILE_BROWSER_DRIVE_WELCOME_DISMISS); SET_STRING("DRIVE_WELCOME_TEXT_LONG", IDS_FILE_BROWSER_DRIVE_WELCOME_TEXT_LONG); SET_STRING("DRIVE_WELCOME_TEXT_SHORT", IDS_FILE_BROWSER_DRIVE_WELCOME_TEXT_SHORT); SET_STRING("DRIVE_WELCOME_TITLE", IDS_FILE_BROWSER_DRIVE_WELCOME_TITLE); - SET_STRING("DRIVE_WELCOME_TITLE_ALTERNATIVE", - IDS_FILE_BROWSER_DRIVE_WELCOME_TITLE_ALTERNATIVE); SET_STRING("SYNC_DELETE_WITHOUT_PERMISSION_ERROR", IDS_FILE_BROWSER_SYNC_DELETE_WITHOUT_PERMISSION_ERROR); SET_STRING("SYNC_FILE_NAME", IDS_FILE_BROWSER_SYNC_FILE_NAME); @@ -835,11 +828,13 @@ base::StringPrintf(kHelpURLFormat, kGoogleDriveErrorHelpNumber)); dict->SetString("GOOGLE_DRIVE_HELP_URL", kGoogleDriveHelpUrl); dict->SetString("GOOGLE_DRIVE_OVERVIEW_URL", kGoogleDriveOverviewUrl); - dict->SetString("GOOGLE_DRIVE_REDEEM_URL", kGoogleDriveRedeemUrl); dict->SetString("GOOGLE_DRIVE_ROOT_URL", kGoogleDriveRootUrl); dict->SetString( "NO_TASK_FOR_FILE_URL", base::StringPrintf(kHelpURLFormat, kNoActionForFileHelpNumber)); + webui::SetLoadTimeDataDefaults(g_browser_process->GetApplicationLocale(), + dict.get()); + return dict; }
diff --git a/chrome/browser/chromeos/file_manager/path_util.cc b/chrome/browser/chromeos/file_manager/path_util.cc index 1bbf32c0..e6ec01a 100644 --- a/chrome/browser/chromeos/file_manager/path_util.cc +++ b/chrome/browser/chromeos/file_manager/path_util.cc
@@ -166,7 +166,7 @@ const base::FilePath& old_path, base::FilePath* new_path) { const base::FilePath old_base = DownloadPrefs::GetDefaultDownloadDirectory(); - const base::FilePath new_base = GetDownloadsFolderForProfile(profile); + const base::FilePath new_base = GetMyFilesFolderForProfile(profile); base::FilePath relative; if (old_path == old_base ||
diff --git a/chrome/browser/chromeos/file_manager/path_util_unittest.cc b/chrome/browser/chromeos/file_manager/path_util_unittest.cc index b99f187d..03854ae4 100644 --- a/chrome/browser/chromeos/file_manager/path_util_unittest.cc +++ b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
@@ -51,26 +51,44 @@ "CHROMEOS_RELEASE_NAME=Chrome OS\n" "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"; -TEST(FileManagerPathUtilTest, GetDownloadsFolderForProfile) { - content::TestBrowserThreadBundle thread_bundle; - TestingProfile profile(base::FilePath("/home/chronos/u-0123456789abcdef")); - std::string mount_point_name = GetDownloadsMountPointName(&profile); +class FileManagerPathUtilTest : public testing::Test { + public: + FileManagerPathUtilTest() = default; + ~FileManagerPathUtilTest() override = default; + + void SetUp() override { + // Remove mount configured to MyFiles because it can interfere with some + // tests. + storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem( + GetDownloadsMountPointName(profile_.get())); + profile_.reset( + new TestingProfile(base::FilePath("/home/chronos/u-0123456789abcdef"))); + } + void TearDown() override { profile_.reset(); } + + protected: + content::TestBrowserThreadBundle thread_bundle_; + std::unique_ptr<TestingProfile> profile_; + + private: + DISALLOW_COPY_AND_ASSIGN(FileManagerPathUtilTest); +}; + +TEST_F(FileManagerPathUtilTest, GetDownloadsFolderForProfile) { + std::string mount_point_name = GetDownloadsMountPointName(profile_.get()); EXPECT_EQ("Downloads", mount_point_name); } -TEST(FileManagerPathUtilTest, GetMyFilesFolderForProfile) { - content::TestBrowserThreadBundle thread_bundle; - +TEST_F(FileManagerPathUtilTest, GetMyFilesFolderForProfile) { base::FilePath profile_path = base::FilePath("/home/chronos/u-0123456789abcdef"); - TestingProfile profile(profile_path); // When running outside ChromeOS, it should return $HOME/Downloads for both // MyFiles and Downloads. EXPECT_EQ(DownloadPrefs::GetDefaultDownloadDirectory(), - GetMyFilesFolderForProfile(&profile)); + GetMyFilesFolderForProfile(profile_.get())); EXPECT_EQ(DownloadPrefs::GetDefaultDownloadDirectory(), - GetDownloadsFolderForProfile(&profile)); + GetDownloadsFolderForProfile(profile_.get())); // When running inside ChromeOS, it should return /home/u-{hash}/MyFiles. chromeos::ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease, @@ -80,10 +98,10 @@ feature_list.InitAndDisableFeature(chromeos::features::kMyFilesVolume); // When MyFilesVolume feature is disabled it will return the same as // Downloads. - EXPECT_EQ(GetDownloadsFolderForProfile(&profile), - GetMyFilesFolderForProfile(&profile)); + EXPECT_EQ(GetDownloadsFolderForProfile(profile_.get()), + GetMyFilesFolderForProfile(profile_.get())); EXPECT_EQ("/home/chronos/u-0123456789abcdef/Downloads", - GetDownloadsFolderForProfile(&profile).value()); + GetDownloadsFolderForProfile(profile_.get()).value()); } { // When MyFilesVolume feature is enabled Downloads path is inside MyFiles. @@ -91,33 +109,33 @@ feature_list.InitAndEnableFeature(chromeos::features::kMyFilesVolume); EXPECT_EQ("/home/chronos/u-0123456789abcdef/MyFiles", - GetMyFilesFolderForProfile(&profile).value()); + GetMyFilesFolderForProfile(profile_.get()).value()); EXPECT_EQ("/home/chronos/u-0123456789abcdef/MyFiles/Downloads", - GetDownloadsFolderForProfile(&profile).value()); + GetDownloadsFolderForProfile(profile_.get()).value()); // Mount the volume to test the return from mount_points. storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem( - GetDownloadsMountPointName(&profile), + GetDownloadsMountPointName(profile_.get()), storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(), profile_path.Append("MyFiles")); // When returning from the mount_point Downloads should still point to // MyFiles/Downloads. EXPECT_EQ("/home/chronos/u-0123456789abcdef/MyFiles/Downloads", - GetDownloadsFolderForProfile(&profile).value()); + GetDownloadsFolderForProfile(profile_.get()).value()); // Still the same: /home/u-{hash}/MyFiles. EXPECT_EQ("/home/chronos/u-0123456789abcdef/MyFiles", - GetMyFilesFolderForProfile(&profile).value()); + GetMyFilesFolderForProfile(profile_.get()).value()); } { // Remove mount configured to MyFiles in the previous test. storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem( - GetDownloadsMountPointName(&profile)); + GetDownloadsMountPointName(profile_.get())); // Add mount point for Downloads instead of MyFiles. storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem( - GetDownloadsMountPointName(&profile), + GetDownloadsMountPointName(profile_.get()), storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(), profile_path.Append("Downloads")); @@ -126,61 +144,56 @@ feature_list.InitAndDisableFeature(chromeos::features::kMyFilesVolume); // When MyFilesVolume feature is disabled it will return the same as // Downloads. - EXPECT_EQ(GetDownloadsFolderForProfile(&profile), - GetMyFilesFolderForProfile(&profile)); + EXPECT_EQ(GetDownloadsFolderForProfile(profile_.get()), + GetMyFilesFolderForProfile(profile_.get())); EXPECT_EQ("/home/chronos/u-0123456789abcdef/Downloads", - GetDownloadsFolderForProfile(&profile).value()); - // Unmount Downloads because it was interfering with other tests. - storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem( - GetDownloadsMountPointName(&profile)); + GetDownloadsFolderForProfile(profile_.get()).value()); } } -TEST(FileManagerPathUtilTest, GetPathDisplayTextForSettings) { - content::TestBrowserThreadBundle thread_bundle; +TEST_F(FileManagerPathUtilTest, GetPathDisplayTextForSettings) { content::TestServiceManagerContext service_manager_context; - TestingProfile profile(base::FilePath("/home/chronos/u-0123456789abcdef")); - EXPECT_EQ("Downloads", GetPathDisplayTextForSettings( - &profile, "/home/chronos/user/Downloads")); + profile_.get(), "/home/chronos/user/Downloads")); EXPECT_EQ("Downloads", GetPathDisplayTextForSettings( - &profile, "/home/chronos/u-0123456789abcdef/Downloads")); + profile_.get(), "/home/chronos/u-0123456789abcdef/Downloads")); - EXPECT_EQ("Downloads", GetPathDisplayTextForSettings( - &profile, "/home/chronos/user/MyFiles/Downloads")); - EXPECT_EQ( - "Downloads", - GetPathDisplayTextForSettings( - &profile, "/home/chronos/u-0123456789abcdef/MyFiles/Downloads")); + EXPECT_EQ("Downloads", + GetPathDisplayTextForSettings( + profile_.get(), "/home/chronos/user/MyFiles/Downloads")); + EXPECT_EQ("Downloads", + GetPathDisplayTextForSettings( + profile_.get(), + "/home/chronos/u-0123456789abcdef/MyFiles/Downloads")); EXPECT_EQ("Play files \u203a foo \u203a bar", GetPathDisplayTextForSettings( - &profile, "/run/arc/sdcard/write/emulated/0/foo/bar")); + profile_.get(), "/run/arc/sdcard/write/emulated/0/foo/bar")); EXPECT_EQ("Linux files \u203a foo", GetPathDisplayTextForSettings( - &profile, + profile_.get(), "/media/fuse/crostini_0123456789abcdef_termina_penguin/foo")); { base::test::ScopedFeatureList features; features.InitAndDisableFeature(chromeos::features::kDriveFs); - drive::DriveIntegrationServiceFactory::GetForProfile(&profile)->SetEnabled( - true); + drive::DriveIntegrationServiceFactory::GetForProfile(profile_.get()) + ->SetEnabled(true); EXPECT_EQ("Google Drive \u203a My Drive \u203a foo", GetPathDisplayTextForSettings( - &profile, "/special/drive-0123456789abcdef/root/foo")); + profile_.get(), "/special/drive-0123456789abcdef/root/foo")); EXPECT_EQ( "Google Drive \u203a Team Drives \u203a A Team Drive \u203a foo", GetPathDisplayTextForSettings( - &profile, + profile_.get(), "/special/drive-0123456789abcdef/team_drives/A Team Drive/foo")); EXPECT_EQ( "Google Drive \u203a Computers \u203a My Other Computer \u203a bar", GetPathDisplayTextForSettings( - &profile, + profile_.get(), "/special/drive-0123456789abcdef/Computers/My Other Computer/bar")); } { @@ -229,11 +242,9 @@ chromeos::disks::DiskMountManager::Shutdown(); } -TEST(FileManagerPathUtilTest, MigrateFromDownlaodsToMyFiles) { - content::TestBrowserThreadBundle thread_bundle; +TEST_F(FileManagerPathUtilTest, MigrateFromDownlaodsToMyFiles) { base::FilePath home("/home/chronos/u-0123456789abcdef"); base::FilePath result; - TestingProfile profile(home); base::FilePath downloads = home.Append("Downloads"); base::FilePath file = home.Append("Downloads/file.txt"); base::FilePath inhome = home.Append("NotDownloads"); @@ -249,91 +260,90 @@ { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature(chromeos::features::kMyFilesVolume); - EXPECT_FALSE(MigrateFromDownloadsToMyFiles(&profile, downloads, &result)); - EXPECT_FALSE(MigrateFromDownloadsToMyFiles(&profile, file, &result)); - EXPECT_FALSE(MigrateFromDownloadsToMyFiles(&profile, inhome, &result)); - EXPECT_FALSE(MigrateFromDownloadsToMyFiles(&profile, myfiles, &result)); - EXPECT_FALSE(MigrateFromDownloadsToMyFiles(&profile, myfilesFile, &result)); EXPECT_FALSE( - MigrateFromDownloadsToMyFiles(&profile, myfilesDownloads, &result)); + MigrateFromDownloadsToMyFiles(profile_.get(), downloads, &result)); + EXPECT_FALSE(MigrateFromDownloadsToMyFiles(profile_.get(), file, &result)); EXPECT_FALSE( - MigrateFromDownloadsToMyFiles(&profile, myfilesDownloadsFile, &result)); - EXPECT_FALSE(MigrateFromDownloadsToMyFiles(&profile, other, &result)); + MigrateFromDownloadsToMyFiles(profile_.get(), inhome, &result)); + EXPECT_FALSE( + MigrateFromDownloadsToMyFiles(profile_.get(), myfiles, &result)); + EXPECT_FALSE( + MigrateFromDownloadsToMyFiles(profile_.get(), myfilesFile, &result)); + EXPECT_FALSE(MigrateFromDownloadsToMyFiles(profile_.get(), myfilesDownloads, + &result)); + EXPECT_FALSE(MigrateFromDownloadsToMyFiles(profile_.get(), + myfilesDownloadsFile, &result)); + EXPECT_FALSE(MigrateFromDownloadsToMyFiles(profile_.get(), other, &result)); } // MyFilesVolume enabled, migrate paths under Downloads. { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(chromeos::features::kMyFilesVolume); - EXPECT_TRUE(MigrateFromDownloadsToMyFiles(&profile, downloads, &result)); + EXPECT_TRUE( + MigrateFromDownloadsToMyFiles(profile_.get(), downloads, &result)); EXPECT_EQ(result, myfilesDownloads); - EXPECT_TRUE(MigrateFromDownloadsToMyFiles(&profile, file, &result)); + EXPECT_TRUE(MigrateFromDownloadsToMyFiles(profile_.get(), file, &result)); EXPECT_EQ(result, myfilesDownloadsFile); - EXPECT_FALSE(MigrateFromDownloadsToMyFiles(&profile, inhome, &result)); - EXPECT_FALSE(MigrateFromDownloadsToMyFiles(&profile, myfiles, &result)); - EXPECT_FALSE(MigrateFromDownloadsToMyFiles(&profile, myfilesFile, &result)); EXPECT_FALSE( - MigrateFromDownloadsToMyFiles(&profile, myfilesDownloads, &result)); + MigrateFromDownloadsToMyFiles(profile_.get(), inhome, &result)); EXPECT_FALSE( - MigrateFromDownloadsToMyFiles(&profile, myfilesDownloadsFile, &result)); - EXPECT_FALSE(MigrateFromDownloadsToMyFiles(&profile, other, &result)); + MigrateFromDownloadsToMyFiles(profile_.get(), myfiles, &result)); + EXPECT_FALSE( + MigrateFromDownloadsToMyFiles(profile_.get(), myfilesFile, &result)); + EXPECT_FALSE(MigrateFromDownloadsToMyFiles(profile_.get(), myfilesDownloads, + &result)); + EXPECT_FALSE(MigrateFromDownloadsToMyFiles(profile_.get(), + myfilesDownloadsFile, &result)); + EXPECT_FALSE(MigrateFromDownloadsToMyFiles(profile_.get(), other, &result)); } } -TEST(FileManagerPathUtilTest, MultiProfileDownloadsFolderMigration) { - content::TestBrowserThreadBundle thread_bundle; - TestingProfile profile; +TEST_F(FileManagerPathUtilTest, MultiProfileDownloadsFolderMigration) { // MigratePathFromOldFormat is explicitly disabled on Linux build. // So we need to fake that this is real ChromeOS system. chromeos::ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease, base::Time()); - // This looks like "/home/chronos/u-hash/Downloads" in the production + // This looks like "/home/chronos/u-hash/MyFiles" in the production // environment. - const base::FilePath kDownloads = GetDownloadsFolderForProfile(&profile); + const base::FilePath kDownloads = GetMyFilesFolderForProfile(profile_.get()); const base::FilePath kOldDownloads = DownloadPrefs::GetDefaultDownloadDirectory(); base::FilePath path; - EXPECT_TRUE(MigratePathFromOldFormat(&profile, kOldDownloads, &path)); + EXPECT_TRUE(MigratePathFromOldFormat(profile_.get(), kOldDownloads, &path)); EXPECT_EQ(kDownloads, path); EXPECT_TRUE(MigratePathFromOldFormat( - &profile, - kOldDownloads.AppendASCII("a/b"), - &path)); + profile_.get(), kOldDownloads.AppendASCII("a/b"), &path)); EXPECT_EQ(kDownloads.AppendASCII("a/b"), path); // Path already in the new format is not converted. - EXPECT_FALSE(MigratePathFromOldFormat( - &profile, - kDownloads.AppendASCII("a/b"), - &path)); + EXPECT_FALSE(MigratePathFromOldFormat(profile_.get(), + kDownloads.AppendASCII("a/b"), &path)); // Only the "Downloads" path is converted. EXPECT_FALSE(MigratePathFromOldFormat( - &profile, - base::FilePath::FromUTF8Unsafe("/home/chronos/user/dl"), + profile_.get(), base::FilePath::FromUTF8Unsafe("/home/chronos/user/dl"), &path)); } -TEST(FileManagerPathUtilTest, ConvertFileSystemURLToPathInsideCrostini) { - content::TestBrowserThreadBundle thread_bundle; +TEST_F(FileManagerPathUtilTest, ConvertFileSystemURLToPathInsideCrostini) { content::TestServiceManagerContext service_manager_context; storage::ExternalMountPoints* mount_points = storage::ExternalMountPoints::GetSystemInstance(); // Setup for DriveFS. - TestingProfile profile(base::FilePath("/home/chronos/u-0123456789abcdef")); chromeos::FakeChromeUserManager user_manager; user_manager.AddUser( - AccountId::FromUserEmailGaiaId(profile.GetProfileUserName(), "12345")); - profile.GetPrefs()->SetString(drive::prefs::kDriveFsProfileSalt, "a"); + AccountId::FromUserEmailGaiaId(profile_->GetProfileUserName(), "12345")); + profile_->GetPrefs()->SetString(drive::prefs::kDriveFsProfileSalt, "a"); // Initialize DBUS and running container. chromeos::DBusThreadManager::Initialize(); crostini::CrostiniManager* crostini_manager = - crostini::CrostiniManager::GetForProfile(&profile); + crostini::CrostiniManager::GetForProfile(profile_.get()); crostini_manager->AddRunningVmForTesting(crostini::kCrostiniDefaultVmName); crostini_manager->AddRunningContainerForTesting( crostini::kCrostiniDefaultVmName, @@ -341,17 +351,19 @@ "testuser", "/home/testuser")); // // Register crostini, downloads, drive, android. + mount_points->RegisterFileSystem(GetCrostiniMountPointName(profile_.get()), + storage::kFileSystemTypeNativeLocal, + storage::FileSystemMountOption(), + GetCrostiniMountDirectory(profile_.get())); mount_points->RegisterFileSystem( - GetCrostiniMountPointName(&profile), storage::kFileSystemTypeNativeLocal, - storage::FileSystemMountOption(), GetCrostiniMountDirectory(&profile)); - mount_points->RegisterFileSystem( - GetDownloadsMountPointName(&profile), storage::kFileSystemTypeNativeLocal, - storage::FileSystemMountOption(), GetDownloadsFolderForProfile(&profile)); + GetDownloadsMountPointName(profile_.get()), + storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(), + GetDownloadsFolderForProfile(profile_.get())); mount_points->RegisterFileSystem( GetAndroidFilesMountPointName(), storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(), base::FilePath(kAndroidFilesPath)); drive::DriveIntegrationService* integration_service = - drive::DriveIntegrationServiceFactory::GetForProfile(&profile); + drive::DriveIntegrationServiceFactory::GetForProfile(profile_.get()); base::FilePath mount_point_drive = integration_service->GetMountPointPath(); mount_points->RegisterFileSystem( mount_point_drive.BaseName().value(), storage::kFileSystemTypeNativeLocal, @@ -368,7 +380,7 @@ base::FilePath inside; EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( - &profile, + profile_.get(), mount_points->CreateExternalFileSystemURL( GURL(), "Downloads-testing_profile-hash", base::FilePath("path/in/downloads")), @@ -377,7 +389,7 @@ inside.value()); EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( - &profile, + profile_.get(), mount_points->CreateExternalFileSystemURL( GURL(), "Downloads-testing_profile-hash", base::FilePath("path/in/downloads/")), @@ -387,7 +399,7 @@ inside.value()); EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( - &profile, + profile_.get(), mount_points->CreateExternalFileSystemURL( GURL(), "Downloads-testing_profile-hash", base::FilePath()), &inside)); @@ -399,7 +411,7 @@ base::FilePath inside; EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( - &profile, + profile_.get(), mount_points->CreateExternalFileSystemURL( GURL(), "crostini_0123456789abcdef_termina_penguin", base::FilePath("path/in/crostini")), @@ -407,20 +419,20 @@ EXPECT_EQ("/home/testuser/path/in/crostini", inside.value()); EXPECT_FALSE(ConvertFileSystemURLToPathInsideCrostini( - &profile, + profile_.get(), mount_points->CreateExternalFileSystemURL( GURL(), "unknown", base::FilePath("path/in/unknown")), &inside)); EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( - &profile, + profile_.get(), mount_points->CreateExternalFileSystemURL( GURL(), "android_files", base::FilePath("path/in/android")), &inside)); EXPECT_EQ("/mnt/chromeos/PlayFiles/path/in/android", inside.value()); EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( - &profile, + profile_.get(), mount_points->CreateExternalFileSystemURL( GURL(), "drivefs-84675c855b63e12f384d45f033826980", base::FilePath("root/path/in/mydrive")), @@ -429,7 +441,7 @@ inside.value()); EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( - &profile, + profile_.get(), mount_points->CreateExternalFileSystemURL( GURL(), "drivefs-84675c855b63e12f384d45f033826980", base::FilePath("team_drives/path/in/teamdrives")), @@ -438,7 +450,7 @@ inside.value()); EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( - &profile, + profile_.get(), mount_points->CreateExternalFileSystemURL( GURL(), "drivefs-84675c855b63e12f384d45f033826980", base::FilePath("Computers/path/in/computers")), @@ -447,7 +459,7 @@ inside.value()); EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( - &profile, + profile_.get(), mount_points->CreateExternalFileSystemURL( GURL(), "removable", base::FilePath("MyUSB/path/in/removable")), &inside)); @@ -458,13 +470,13 @@ // Test MyFiles. base::test::ScopedFeatureList features; features.InitAndEnableFeature(chromeos::features::kMyFilesVolume); - mount_points->RegisterFileSystem(GetDownloadsMountPointName(&profile), - storage::kFileSystemTypeNativeLocal, - storage::FileSystemMountOption(), - GetMyFilesFolderForProfile(&profile)); + mount_points->RegisterFileSystem( + GetDownloadsMountPointName(profile_.get()), + storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(), + GetMyFilesFolderForProfile(profile_.get())); base::FilePath inside; EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( - &profile, + profile_.get(), mount_points->CreateExternalFileSystemURL( GURL(), "Downloads-testing_profile-hash", base::FilePath("path/in/myfiles")), @@ -473,14 +485,12 @@ } } -TEST(FileManagerPathUtilTest, ExtractMountNameAndFullPath) { - content::TestBrowserThreadBundle thread_bundle; +TEST_F(FileManagerPathUtilTest, ExtractMountNameAndFullPath) { content::TestServiceManagerContext service_manager_context; - TestingProfile profile(base::FilePath("/home/chronos/u-0123456789abcdef")); storage::ExternalMountPoints* mount_points = storage::ExternalMountPoints::GetSystemInstance(); - std::string downloads_mount_name = GetDownloadsMountPointName(&profile); - base::FilePath downloads_path = GetDownloadsFolderForProfile(&profile); + std::string downloads_mount_name = GetDownloadsMountPointName(profile_.get()); + base::FilePath downloads_path = GetDownloadsFolderForProfile(profile_.get()); mount_points->RegisterFileSystem( downloads_mount_name, storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(), downloads_path);
diff --git a/chrome/browser/chromeos/file_manager/video_player_browsertest.cc b/chrome/browser/chromeos/file_manager/video_player_browsertest.cc index 9e04b2d..9dad913 100644 --- a/chrome/browser/chromeos/file_manager/video_player_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/video_player_browsertest.cc
@@ -73,7 +73,8 @@ StartTest(); } -IN_PROC_BROWSER_TEST_F(VideoPlayerBrowserTest, NativeMediaKey) { +// Flaky see https://crbug.com/921418. +IN_PROC_BROWSER_TEST_F(VideoPlayerBrowserTest, DISABLED_NativeMediaKey) { set_test_case_name("mediaKeyNative"); StartTest(); }
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc index 5fecef7e..2dbe2c29 100644 --- a/chrome/browser/chromeos/file_manager/volume_manager.cc +++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -252,6 +252,7 @@ volume->is_read_only_ = disk->is_read_only(); volume->is_read_only_removable_device_ = disk->is_read_only_hardware(); volume->has_media_ = disk->has_media(); + volume->drive_label_ = disk->drive_label(); } else { volume->volume_label_ = volume->mount_path().BaseName().AsUTF8Unsafe(); volume->device_type_ = chromeos::DEVICE_TYPE_UNKNOWN; @@ -398,7 +399,8 @@ VolumeType volume_type, chromeos::DeviceType device_type, bool read_only, - const base::FilePath& device_path) { + const base::FilePath& device_path, + const std::string& drive_label) { std::unique_ptr<Volume> volume(new Volume()); volume->type_ = volume_type; volume->device_type_ = device_type; @@ -409,6 +411,7 @@ volume->mount_condition_ = chromeos::disks::MOUNT_CONDITION_NONE; volume->is_read_only_ = read_only; volume->volume_id_ = GenerateVolumeId(*volume); + volume->drive_label_ = drive_label; return volume; } @@ -686,11 +689,12 @@ VolumeType volume_type, chromeos::DeviceType device_type, bool read_only, - const base::FilePath& device_path) { + const base::FilePath& device_path, + const std::string& drive_label) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DoMountEvent(chromeos::MOUNT_ERROR_NONE, Volume::CreateForTesting(path, volume_type, device_type, - read_only, device_path)); + read_only, device_path, drive_label)); } void VolumeManager::AddVolumeForTesting(std::unique_ptr<Volume> volume) {
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.h b/chrome/browser/chromeos/file_manager/volume_manager.h index 8f3c926..28625a1 100644 --- a/chrome/browser/chromeos/file_manager/volume_manager.h +++ b/chrome/browser/chromeos/file_manager/volume_manager.h
@@ -122,7 +122,8 @@ VolumeType volume_type, chromeos::DeviceType device_type, bool read_only, - const base::FilePath& device_path); + const base::FilePath& device_path, + const std::string& drive_label); static std::unique_ptr<Volume> CreateForTesting( const base::FilePath& device_path, const base::FilePath& mount_path); @@ -163,6 +164,7 @@ bool configurable() const { return configurable_; } bool watchable() const { return watchable_; } const std::string& file_system_type() const { return file_system_type_; } + const std::string& drive_label() const { return drive_label_; } const chromeos::file_system_provider::IconSet& icon_set() const { return icon_set_; } @@ -243,6 +245,10 @@ // Volume icon set. chromeos::file_system_provider::IconSet icon_set_; + // Device label of a physical removable device. Removable partitions + // belonging to the same device share the same device label. + std::string drive_label_; + DISALLOW_COPY_AND_ASSIGN(Volume); }; @@ -329,12 +335,12 @@ // For testing purpose, adds a volume info pointing to |path|, with TESTING // type. Assumes that the mount point is already registered. - void AddVolumeForTesting( - const base::FilePath& path, - VolumeType volume_type, - chromeos::DeviceType device_type, - bool read_only, - const base::FilePath& device_path = base::FilePath()); + void AddVolumeForTesting(const base::FilePath& path, + VolumeType volume_type, + chromeos::DeviceType device_type, + bool read_only, + const base::FilePath& device_path = base::FilePath(), + const std::string& drive_label = ""); // For testing purpose, adds the volume info to the volume manager. void AddVolumeForTesting(std::unique_ptr<Volume> volume);
diff --git a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc index 6a64d435..31e7e5ca0 100644 --- a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc +++ b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
@@ -846,11 +846,13 @@ } TEST_F(VolumeManagerTest, GetVolumeList) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(chromeos::features::kMyFilesVolume); volume_manager()->Initialize(); // Adds "Downloads" std::vector<base::WeakPtr<Volume>> volume_list = volume_manager()->GetVolumeList(); ASSERT_EQ(1u, volume_list.size()); - EXPECT_EQ("downloads:Downloads", volume_list[0]->volume_id()); + EXPECT_EQ("downloads:MyFiles", volume_list[0]->volume_id()); EXPECT_EQ(VOLUME_TYPE_DOWNLOADS_DIRECTORY, volume_list[0]->type()); } @@ -870,14 +872,16 @@ } TEST_F(VolumeManagerTest, FindVolumeById) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(chromeos::features::kMyFilesVolume); volume_manager()->Initialize(); // Adds "Downloads" base::WeakPtr<Volume> bad_volume = volume_manager()->FindVolumeById("nonexistent"); ASSERT_FALSE(bad_volume.get()); base::WeakPtr<Volume> good_volume = - volume_manager()->FindVolumeById("downloads:Downloads"); + volume_manager()->FindVolumeById("downloads:MyFiles"); ASSERT_TRUE(good_volume.get()); - EXPECT_EQ("downloads:Downloads", good_volume->volume_id()); + EXPECT_EQ("downloads:MyFiles", good_volume->volume_id()); EXPECT_EQ(VOLUME_TYPE_DOWNLOADS_DIRECTORY, good_volume->type()); }
diff --git a/chrome/browser/chromeos/first_run/chromeos_first_run_browsertest.cc b/chrome/browser/chromeos/first_run/chromeos_first_run_browsertest.cc index 4d92980a..0d02dec 100644 --- a/chrome/browser/chromeos/first_run/chromeos_first_run_browsertest.cc +++ b/chrome/browser/chromeos/first_run/chromeos_first_run_browsertest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/system_tray_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/system_tray_test_api.test-mojom.h" #include "chrome/browser/chromeos/first_run/first_run.h" #include "chrome/browser/chromeos/first_run/first_run_controller.h"
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_tester.cc b/chrome/browser/chromeos/login/lock/screen_locker_tester.cc index 727367a8..75a8d23 100644 --- a/chrome/browser/chromeos/login/lock/screen_locker_tester.cc +++ b/chrome/browser/chromeos/login/lock/screen_locker_tester.cc
@@ -8,6 +8,7 @@ #include "ash/public/cpp/ash_switches.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/login_screen_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/login_screen_test_api.test-mojom.h" #include "base/command_line.h" #include "base/macros.h"
diff --git a/chrome/browser/chromeos/login/login_shelf_test_helper.cc b/chrome/browser/chromeos/login/login_shelf_test_helper.cc index 9415fca..dc11466 100644 --- a/chrome/browser/chromeos/login/login_shelf_test_helper.cc +++ b/chrome/browser/chromeos/login/login_shelf_test_helper.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/chromeos/login/login_shelf_test_helper.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/login_screen_test_api.test-mojom-test-utils.h" #include "content/public/common/service_manager_connection.h" #include "services/service_manager/public/cpp/connector.h"
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc index 3f0446d4f..c3c31615 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -329,12 +329,6 @@ widget_->Close(); } - void OnCompositingStarted(ui::Compositor* compositor, - base::TimeTicks start_time) override {} - void OnCompositingEnded(ui::Compositor* compositor) override {} - void OnCompositingChildResizing(ui::Compositor* compositor) override {} - void OnCompositingShuttingDown(ui::Compositor* compositor) override {} - // views::WidgetObserver: void OnWidgetDestroying(views::Widget* widget) override { DCHECK_EQ(widget, widget_);
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc index dd4877b1..e9fb591 100644 --- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc +++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -77,6 +77,7 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/upstart_client.h" #include "chromeos/login/login_state/login_state.h" +#include "chromeos/network/proxy/proxy_config_service_impl.h" #include "chromeos/settings/cros_settings_names.h" #include "chromeos/timezone/timezone_resolver.h" #include "components/account_id/account_id.h" @@ -87,6 +88,7 @@ #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" +#include "components/proxy_config/proxy_prefs.h" #include "components/session_manager/core/session_manager.h" #include "components/user_manager/known_user.h" #include "components/user_manager/remove_user_delegate.h" @@ -259,6 +261,17 @@ return false; } +bool IsProxyUsed(const PrefService* local_state_prefs) { + std::unique_ptr<ProxyConfigDictionary> proxy_config = + ProxyConfigServiceImpl::GetActiveProxyConfigDictionary( + ProfileHelper::Get()->GetSigninProfile()->GetPrefs(), + local_state_prefs); + ProxyPrefs::ProxyMode mode; + if (!proxy_config || !proxy_config->GetMode(&mode)) + return false; + return mode != ProxyPrefs::MODE_DIRECT; +} + bool AreRiskyExtensionsForceInstalled( policy::DeviceLocalAccountPolicyBroker* broker) { const policy::PolicyMap& policy_map = broker->core()->store()->policy_map(); @@ -1511,7 +1524,8 @@ (IsPacHttpsUrlStrippingDisabled(broker) || AreRiskyPoliciesUsed(broker) || AreRiskyExtensionsForceInstalled(broker) || - AreForcedNetworkCertificatesInstalled()); + AreForcedNetworkCertificatesInstalled() || + IsProxyUsed(GetLocalState())); } void ChromeUserManagerImpl::AddReportingUser(const AccountId& account_id) {
diff --git a/chrome/browser/chromeos/policy/device_status_collector.cc b/chrome/browser/chromeos/policy/device_status_collector.cc index ba2d462..51fe894 100644 --- a/chrome/browser/chromeos/policy/device_status_collector.cc +++ b/chrome/browser/chromeos/policy/device_status_collector.cc
@@ -367,6 +367,12 @@ user_type == chromeos::LoginState::LOGGED_IN_USER_ARC_KIOSK_APP; } +// Utility method to turn cpu_temp_fetcher_ to OnceCallback +std::vector<em::CPUTempInfo> InvokeCpuTempFetcher( + policy::DeviceStatusCollector::CPUTempFetcher fetcher) { + return fetcher.Run(); +} + } // namespace namespace policy { @@ -477,12 +483,18 @@ void OnCPUTempInfoReceived( const std::vector<em::CPUTempInfo>& cpu_temp_info) { - if (cpu_temp_info.empty()) - DLOG(WARNING) << "Unable to read CPU temp information."; + // Only one of OnProbeDataReceived and OnCPUTempInfoReceived should be + // called. + DCHECK(device_status_->cpu_temp_info_size() == 0); - device_status_->clear_cpu_temp_info(); - for (const em::CPUTempInfo& info : cpu_temp_info) - *device_status_->add_cpu_temp_info() = info; + DLOG_IF(WARNING, cpu_temp_info.empty()) + << "Unable to read CPU temp information."; + base::Time timestamp = base::Time::Now(); + for (const em::CPUTempInfo& info : cpu_temp_info) { + auto* new_info = device_status_->add_cpu_temp_info(); + *new_info = info; + new_info->set_timestamp(timestamp.ToJavaTime()); + } } void OnAndroidInfoReceived(const std::string& status, @@ -523,6 +535,20 @@ const base::circular_deque<std::unique_ptr<SampledData>>& samples) { // Make sure we edit the state on the right thread. DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + // Only one of OnProbeDataReceived and OnCPUTempInfoReceived should be + // called. + DCHECK(device_status_->cpu_temp_info_size() == 0); + + // Store CPU measurement samples. + for (const std::unique_ptr<SampledData>& sample_data : samples) { + for (auto it = sample_data->cpu_samples.begin(); + it != sample_data->cpu_samples.end(); it++) { + auto* new_info = device_status_->add_cpu_temp_info(); + *new_info = it->second; + } + } + if (!probe_result.has_value()) return; if (probe_result.value().error() != @@ -1246,6 +1272,12 @@ session_manager::SessionState::ACTIVE; } +void DeviceStatusCollector::PowerChanged( + const power_manager::PowerSupplyProperties& prop) { + if (!power_status_callback_.is_null()) + std::move(power_status_callback_).Run(prop); +} + void DeviceStatusCollector::UpdateChildUsageTime() { if (!report_activity_times_ || !user_manager::UserManager::Get()->IsLoggedInAsChildUser()) { @@ -1380,17 +1412,29 @@ if (resource_usage_.size() > kMaxResourceUsageSamples) resource_usage_.pop_front(); + std::unique_ptr<SampledData> sample = std::make_unique<SampledData>(); + sample->timestamp = base::Time::Now(); + if (report_power_status_) { runtime_probe::ProbeRequest request; request.add_categories(runtime_probe::ProbeRequest::battery); runtime_probe_->ProbeCategories( request, base::BindOnce(&DeviceStatusCollector::SampleProbeData, - weak_factory_.GetWeakPtr(), timestamp)); + weak_factory_.GetWeakPtr(), std::move(sample), + SamplingProbeResultCallback())); + } else { + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&InvokeCpuTempFetcher, cpu_temp_fetcher_), + base::BindOnce(&DeviceStatusCollector::ReceiveCPUTemperature, + weak_factory_.GetWeakPtr(), std::move(sample), + SamplingCallback())); } } void DeviceStatusCollector::SampleProbeData( - const base::Time& timestamp, + std::unique_ptr<SampledData> sample, + SamplingProbeResultCallback callback, base::Optional<runtime_probe::ProbeResult> result) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (!result.has_value()) @@ -1401,11 +1445,9 @@ if (result.value().battery_size() == 0) return; - std::unique_ptr<SampledData> sample = std::make_unique<SampledData>(); - sample->timestamp = timestamp; for (const auto& battery : result.value().battery()) { enterprise_management::BatterySample battery_sample; - battery_sample.set_timestamp(timestamp.ToJavaTime()); + battery_sample.set_timestamp(sample->timestamp.ToJavaTime()); // Convert uV to mV battery_sample.set_voltage(battery.values().voltage_now() / 1000); // Convert uAh to mAh @@ -1415,13 +1457,67 @@ (battery.values().temperature_smart() - 2731) / 10); sample->battery_samples[battery.name()] = battery_sample; } + SamplingCallback completion_callback; + if (!callback.is_null()) + completion_callback = base::BindOnce(std::move(callback), result); + // PowerManagerClient::Observer::PowerChanged can be called as a result of + // power_manager_->RequestStatusUpdate() as well as for other reasons, + // so we store power_status_callback_ here instead of triggering + // SampleDischargeRate from PowerChanged(). + DCHECK(power_status_callback_.is_null()); // Previous sampling is completed. + + power_status_callback_ = base::BindOnce( + &DeviceStatusCollector::SampleDischargeRate, weak_factory_.GetWeakPtr(), + std::move(sample), std::move(completion_callback)); + power_manager_->RequestStatusUpdate(); +} + +void DeviceStatusCollector::SampleDischargeRate( + std::unique_ptr<SampledData> sample, + SamplingCallback callback, + const power_manager::PowerSupplyProperties& prop) { + if (prop.has_battery_discharge_rate()) { + int discharge_rate_mW = (int)(prop.has_battery_discharge_rate() * 1000); + for (auto it = sample->battery_samples.begin(); + it != sample->battery_samples.end(); it++) { + it->second.set_discharge_rate(discharge_rate_mW); + } + } + + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&InvokeCpuTempFetcher, cpu_temp_fetcher_), + base::BindOnce(&DeviceStatusCollector::ReceiveCPUTemperature, + weak_factory_.GetWeakPtr(), std::move(sample), + std::move(callback))); +} + +void DeviceStatusCollector::ReceiveCPUTemperature( + std::unique_ptr<SampledData> sample, + SamplingCallback callback, + std::vector<em::CPUTempInfo> measurements) { + auto timestamp = sample->timestamp.ToJavaTime(); + for (const auto& measurement : measurements) { + sample->cpu_samples[measurement.cpu_label()] = measurement; + sample->cpu_samples[measurement.cpu_label()].set_timestamp(timestamp); + } + AddDataSample(std::move(sample), std::move(callback)); +} + +void DeviceStatusCollector::AddDataSample(std::unique_ptr<SampledData> sample, + SamplingCallback callback) { sampled_data_.push_back(std::move(sample)); // If our cache of samples is full, throw out old samples to make room for new // sample. if (sampled_data_.size() > kMaxResourceUsageSamples) sampled_data_.pop_front(); + // We have two code paths that end here. One is regular sampling, that does + // not have final callback, and full report request, that would use callback + // to receive ProbeResponse. + if (!callback.is_null()) + std::move(callback).Run(); } void DeviceStatusCollector::FetchProbeData( @@ -1433,16 +1529,22 @@ if (report_storage_status_) request.add_categories(runtime_probe::ProbeRequest::storage); + auto sample = std::make_unique<SampledData>(); + sample->timestamp = base::Time::Now(); + auto completion_callback = + base::BindOnce(&DeviceStatusCollector::OnProbeDataFetched, + weak_factory_.GetWeakPtr(), std::move(callback)); + runtime_probe_->ProbeCategories( - request, base::BindOnce(&DeviceStatusCollector::OnProbeDataFetched, - weak_factory_.GetWeakPtr(), std::move(callback))); + request, base::BindOnce(&DeviceStatusCollector::SampleProbeData, + weak_factory_.GetWeakPtr(), std::move(sample), + std::move(completion_callback))); } void DeviceStatusCollector::OnProbeDataFetched( policy::DeviceStatusCollector::ProbeDataReceiver callback, base::Optional<runtime_probe::ProbeResult> reply) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - SampleProbeData(base::Time(), reply); std::move(callback).Run(reply, sampled_data_); } @@ -1728,9 +1830,6 @@ // Sample disk volume info in a background thread. state->SampleVolumeInfo(volume_info_fetcher_); - // Sample CPU temperature in a background thread. - state->SampleCPUTempInfo(cpu_temp_fetcher_); - // Add CPU utilization and free RAM. Note that these stats are sampled in // regular intervals. Unlike CPU temp and volume info these are not one-time // sampled values, hence the difference in logic. @@ -1749,8 +1848,14 @@ // Fetch TPM status information on a background thread. state->FetchTpmStatus(tpm_status_fetcher_); + // clear + status->clear_cpu_temp_info(); + if (report_power_status_ || report_storage_status_) { state->FetchProbeData(probe_data_fetcher_); + } else { + // Sample CPU temperature in a background thread. + state->SampleCPUTempInfo(cpu_temp_fetcher_); } return true; }
diff --git a/chrome/browser/chromeos/policy/device_status_collector.h b/chrome/browser/chromeos/policy/device_status_collector.h index fd1440d3..bde26ee 100644 --- a/chrome/browser/chromeos/policy/device_status_collector.h +++ b/chrome/browser/chromeos/policy/device_status_collector.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include <map> #include <memory> #include <string> #include <vector> @@ -45,6 +46,10 @@ struct TpmStatusInfo; } +namespace power_manager { +class PowerSupplyProperties; +} + namespace user_manager { class User; } @@ -99,6 +104,8 @@ std::map<std::string, enterprise_management::BatterySample> battery_samples; // Thermal samples for each thermal point. std::map<std::string, enterprise_management::ThermalSample> thermal_samples; + // CPU thermal samples. + std::map<std::string, enterprise_management::CPUTempInfo> cpu_samples; DISALLOW_COPY_AND_ASSIGN(SampledData); }; @@ -154,7 +161,6 @@ using StatusCallback = base::Callback<void( std::unique_ptr<enterprise_management::DeviceStatusReportRequest>, std::unique_ptr<enterprise_management::SessionStatusReportRequest>)>; - // Constructor. Callers can inject their own *Fetcher callbacks, e.g. for unit // testing. A null callback can be passed for any *Fetcher parameter, to use // the default implementation. These callbacks are always executed on Blocking @@ -208,6 +214,9 @@ base::TimeDelta GetActiveChildScreenTime(); protected: + using PowerStatusCallback = base::OnceCallback<void( + const power_manager::PowerSupplyProperties& prop)>; + // Check whether the user has been idle for a certain period of time. virtual void CheckIdleState(); @@ -241,6 +250,9 @@ // power_manager::PowerManagerClient::Observer: void SuspendDone(const base::TimeDelta& sleep_duration) override; + // power_manager::PowerManagerClient::Observer: + void PowerChanged(const power_manager::PowerSupplyProperties& prop) override; + // The timeout in the past to store device activity. // This is kept in case device status uploads fail for a number of days. base::TimeDelta max_stored_past_activity_interval_; @@ -256,6 +268,12 @@ private: class ActivityStorage; + // Callbacks used during sampling data collection, that allows to pass + // additional data using partial function application. + using SamplingProbeResultCallback = + base::OnceCallback<void(base::Optional<runtime_probe::ProbeResult>)>; + using SamplingCallback = base::OnceCallback<void()>; + // Clears the cached hardware resource usage. void ClearCachedResourceUsage(); @@ -311,10 +329,27 @@ void ReceiveCPUStatistics(const base::Time& timestamp, const std::string& statistics); - // Callback for RuntimeProbe that samples probe live data. - void SampleProbeData(const base::Time& timestamp, + // Callback for RuntimeProbe that samples probe live data. |callback| will be + // called once all sampling is finished. + void SampleProbeData(std::unique_ptr<SampledData> sample, + SamplingProbeResultCallback callback, base::Optional<runtime_probe::ProbeResult> result); + // Callback triggered from PowerManagedClient that samples battery discharge + // rate. |callback| will be called once all sampling is finished. + void SampleDischargeRate(std::unique_ptr<SampledData> sample, + SamplingCallback callback, + const power_manager::PowerSupplyProperties& prop); + + // Callback invoked to update our cpu temperature information. + void ReceiveCPUTemperature(std::unique_ptr<SampledData> sample, + SamplingCallback callback, + std::vector<enterprise_management::CPUTempInfo>); + + // Final sampling step that records data sample, invokes |callback|. + void AddDataSample(std::unique_ptr<SampledData> sample, + SamplingCallback callback); + // ProbeDataReceiver interface implementation, fetches data from // RuntimeProbe passes it to |callback| via OnProbeDataFetched(). void FetchProbeData( @@ -398,6 +433,8 @@ ProbeDataFetcher probe_data_fetcher_; + PowerStatusCallback power_status_callback_; + chromeos::system::StatisticsProvider* const statistics_provider_; chromeos::CrosSettings* const cros_settings_;
diff --git a/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc b/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc index 674c16ef..a95c8a7 100644 --- a/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/system_tray_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/system_tray_test_api.test-mojom.h" #include "base/command_line.h" #include "base/location.h"
diff --git a/chrome/browser/chromeos/shutdown_policy_browsertest.cc b/chrome/browser/chromeos/shutdown_policy_browsertest.cc index 379d7f81..dbb2f3a16 100644 --- a/chrome/browser/chromeos/shutdown_policy_browsertest.cc +++ b/chrome/browser/chromeos/shutdown_policy_browsertest.cc
@@ -9,6 +9,7 @@ #include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/ash_view_ids.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/system_tray_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/system_tray_test_api.test-mojom.h" #include "base/command_line.h" #include "base/location.h"
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc index 78d31a3..ab8105a 100644 --- a/chrome/browser/chromeos/smb_client/smb_service.cc +++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -42,6 +42,7 @@ const char kShareUrlKey[] = "share_url"; const char kModeKey[] = "mode"; const char kModeDropDownValue[] = "drop_down"; +const char kModePreMountValue[] = "pre_mount"; bool ContainsAt(const std::string& username) { return username.find('@') != std::string::npos; @@ -146,7 +147,7 @@ void SmbService::GatherSharesInNetwork(HostDiscoveryResponse discovery_callback, GatherSharesResponse shares_callback) { - shares_callback.Run(GetPreconfiguredSharePathsForDropDown()); + shares_callback.Run(GetPreconfiguredSharePathsForDropdown()); share_finder_->GatherSharesInNetwork(std::move(discovery_callback), std::move(shares_callback)); } @@ -303,20 +304,29 @@ } void SmbService::RestoreMounts() { - const std::vector<ProvidedFileSystemInfo> file_systems = + std::vector<ProvidedFileSystemInfo> file_systems = GetProviderService()->GetProvidedFileSystemInfoList(provider_id_); - if (!file_systems.empty()) { + std::vector<SmbUrl> preconfigured_shares = + GetPreconfiguredSharePathsForPremount(); + + if (!file_systems.empty() || !preconfigured_shares.empty()) { share_finder_->DiscoverHostsInNetwork(base::BindOnce( - &SmbService::OnHostsDiscovered, AsWeakPtr(), file_systems)); + &SmbService::OnHostsDiscovered, AsWeakPtr(), std::move(file_systems), + std::move(preconfigured_shares))); } } void SmbService::OnHostsDiscovered( - const std::vector<ProvidedFileSystemInfo>& file_systems) { + const std::vector<ProvidedFileSystemInfo>& file_systems, + const std::vector<SmbUrl>& preconfigured_shares) { for (const auto& file_system : file_systems) { Remount(file_system); } + for (const auto& url : preconfigured_shares) { + const base::FilePath share_path(share_finder_->GetResolvedUrl(url)); + Premount(share_path); + } } void SmbService::Remount(const ProvidedFileSystemInfo& file_system_info) { @@ -377,6 +387,45 @@ } } +void SmbService::Premount(const base::FilePath& share_path) { + GetSmbProviderClient()->Premount( + share_path, IsNTLMAuthenticationEnabled(), + base::BindOnce(&SmbService::OnPremountResponse, AsWeakPtr(), share_path)); +} + +void SmbService::OnPremountResponse(const base::FilePath& share_path, + smbprovider::ErrorType error, + int32_t mount_id) { + const bool allowed_error = (error == smbprovider::ERROR_OK) || + (error == smbprovider::ERROR_ACCESS_DENIED); + if (!allowed_error) { + LOG(ERROR) << "Error mounting preconfigured share in smbprovider."; + return; + } + + DCHECK_GE(mount_id, 0); + + file_system_provider::MountOptions mount_options; + mount_options.display_name = share_path.BaseName().value(); + mount_options.writable = true; + // |is_chromad_kerberos| is false because we do not pass user and workgroup + // at mount time. Premounts also do not get remounted and currently + // |is_chromad_kerberos| is only used at remounts to determine if the share + // was mounted with chromad kerberos. + // TODO(jimmyxgong): Support chromad kerberos for premount. + mount_options.file_system_id = + CreateFileSystemId(mount_id, share_path, false /* is_chromad_kerberos */); + // Disable remounting of preconfigured shares. + mount_options.persistent = false; + + const base::File::Error result = + GetProviderService()->MountFileSystem(provider_id_, mount_options); + + if (result != base::File::FILE_OK) { + LOG(ERROR) << "Error mounting preconfigured share with File Manager."; + } +} + void SmbService::StartSetup() { user_manager::User* user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile_); @@ -493,7 +542,8 @@ prefs::kNTLMShareAuthenticationEnabled); } -std::vector<SmbUrl> SmbService::GetPreconfiguredSharePathsForDropDown() const { +std::vector<SmbUrl> SmbService::GetPreconfiguredSharePaths( + const std::string& policy_mode) const { std::vector<SmbUrl> preconfigured_urls; const base::Value* preconfigured_shares = profile_->GetPrefs()->GetList( @@ -504,9 +554,7 @@ const base::Value* share_url = info.FindKey(kShareUrlKey); const base::Value* mode = info.FindKey(kModeKey); - DCHECK(mode->GetString() == kModeDropDownValue); - - if (mode->GetString() == kModeDropDownValue) { + if (mode->GetString() == policy_mode) { preconfigured_urls.emplace_back(share_url->GetString()); } } @@ -525,6 +573,14 @@ smb_dialog::SmbCredentialsDialog::Show(mount_id, share_path); } +std::vector<SmbUrl> SmbService::GetPreconfiguredSharePathsForDropdown() const { + return GetPreconfiguredSharePaths(kModeDropDownValue); +} + +std::vector<SmbUrl> SmbService::GetPreconfiguredSharePathsForPremount() const { + return GetPreconfiguredSharePaths(kModePreMountValue); +} + void SmbService::RecordMountCount() const { const std::vector<ProvidedFileSystemInfo> file_systems = GetProviderService()->GetProvidedFileSystemInfoList(provider_id_);
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h index 8edbd7a..e5e6e60 100644 --- a/chrome/browser/chromeos/smb_client/smb_service.h +++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -8,6 +8,7 @@ #include <map> #include <memory> #include <string> +#include <vector> #include "base/files/file.h" #include "base/macros.h" @@ -116,7 +117,8 @@ void RestoreMounts(); void OnHostsDiscovered( - const std::vector<ProvidedFileSystemInfo>& file_systems); + const std::vector<ProvidedFileSystemInfo>& file_systems, + const std::vector<SmbUrl>& preconfigured_shares); // Attempts to remount a share with the information in |file_system_info|. void Remount(const ProvidedFileSystemInfo& file_system_info); @@ -127,6 +129,16 @@ void OnRemountResponse(const std::string& file_system_id, smbprovider::ErrorType error); + // Calls SmbProviderClient::Premount(). |temp_file_manager_| must be + // initialized before this is called. + void Premount(const base::FilePath& share_path); + + // Handles the response from attempting to premount a share configured via + // policy. If premounting fails it will log and exit the operation. + void OnPremountResponse(const base::FilePath& share_path, + smbprovider::ErrorType error, + int32_t mount_id); + // Sets up SmbService, including setting up Keberos if the user is ChromAD. void StartSetup(); @@ -165,9 +177,17 @@ // Whether NTLM should be used. Controlled via policy. bool IsNTLMAuthenticationEnabled() const; + // Gets the list of all shares preconfigured via policy with mode + // |policy_mode|. + std::vector<SmbUrl> GetPreconfiguredSharePaths( + const std::string& policy_mode) const; + // Gets the shares preconfigured via policy that should be displayed in the - // discovery drop down. - std::vector<SmbUrl> GetPreconfiguredSharePathsForDropDown() const; + // discovery dropdown. + std::vector<SmbUrl> GetPreconfiguredSharePathsForDropdown() const; + + // Gets the shares preconfigured via policy that should be premounted. + std::vector<SmbUrl> GetPreconfiguredSharePathsForPremount() const; // Requests new credentials for the |share_path|. |reply| is stored. Once the // credentials have been successfully updated, |reply| is run.
diff --git a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc index 6c81f83d..2914390 100644 --- a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc +++ b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
@@ -4,6 +4,7 @@ #include "ash/public/cpp/ash_pref_names.h" #include "ash/public/cpp/ash_view_ids.h" +#include "ash/public/interfaces/system_tray_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/system_tray_test_api.test-mojom.h" #include "base/callback.h" #include "base/command_line.h"
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.cc b/chrome/browser/component_updater/cros_component_installer_chromeos.cc index ec64437..5a3940af 100644 --- a/chrome/browser/component_updater/cros_component_installer_chromeos.cc +++ b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
@@ -36,9 +36,9 @@ "1913a5e0a6cad30b6f03e176177e0d7ed62c5d6700a9c66da556d7c3f5d6a47e"}, {"cros-termina", "730.1", "e9d960f84f628e1f42d05de4046bb5b3154b6f1f65c08412c6af57a29aecaffb"}, - {"rtanalytics-light", "8.0", + {"rtanalytics-light", "9.0", "69f09d33c439c2ab55bbbe24b47ab55cb3f6c0bd1f1ef46eefea3216ec925038"}, - {"rtanalytics-full", "2.0", + {"rtanalytics-full", "9.0", "c93c3e1013c52100a20038b405ac854d69fa889f6dc4fa6f188267051e05e444"}, {"star-cups-driver", "1.1", "6d24de30f671da5aee6d463d9e446cafe9ddac672800a9defe86877dcde6c466"},
diff --git a/chrome/browser/conflicts/third_party_conflicts_manager_win.cc b/chrome/browser/conflicts/third_party_conflicts_manager_win.cc index 69b370f..6505ee1 100644 --- a/chrome/browser/conflicts/third_party_conflicts_manager_win.cc +++ b/chrome/browser/conflicts/third_party_conflicts_manager_win.cc
@@ -27,7 +27,6 @@ #include "chrome/browser/conflicts/module_blacklist_cache_updater_win.h" #include "chrome/browser/conflicts/module_blacklist_cache_util_win.h" #include "chrome/browser/conflicts/module_info_util_win.h" -#include "chrome/browser/conflicts/module_info_win.h" #include "chrome/browser/conflicts/module_list_filter_win.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" @@ -40,6 +39,16 @@ namespace { +std::unique_ptr<CertificateInfo> CreateExeCertificateInfo() { + auto certificate_info = std::make_unique<CertificateInfo>(); + + base::FilePath exe_path; + if (base::PathService::Get(base::FILE_EXE, &exe_path)) + GetCertificateInfo(exe_path, certificate_info.get()); + + return certificate_info; +} + scoped_refptr<ModuleListFilter> CreateModuleListFilter( const base::FilePath& module_list_path) { auto module_list_filter = base::MakeRefCounted<ModuleListFilter>(); @@ -135,13 +144,11 @@ LogChromeElfThirdPartyStatus(); module_database_event_source_->AddObserver(this); - - // Get the path to the current executable as it will be used to retrieve its - // associated CertificateInfo from the ModuleDatabase. This shouldn't fail, - // but it is assumed that without the path, the executable is not signed - // (hence an empty CertificateInfo). - if (!base::PathService::Get(base::FILE_EXE, &exe_path_)) - exe_certificate_info_ = std::make_unique<CertificateInfo>(); + base::PostTaskAndReplyWithResult( + background_sequence_.get(), FROM_HERE, + base::BindOnce(&CreateExeCertificateInfo), + base::BindOnce(&ThirdPartyConflictsManager::OnExeCertificateCreated, + weak_ptr_factory_.GetWeakPtr())); } ThirdPartyConflictsManager::~ThirdPartyConflictsManager() { @@ -183,26 +190,6 @@ // |instance| is intentionally destroyed at the end of the function scope. } -void ThirdPartyConflictsManager::OnNewModuleFound( - const ModuleInfoKey& module_key, - const ModuleInfoData& module_data) { - // Keep looking for the CertificateInfo of the current executable as long as - // it wasn't found yet. - if (exe_certificate_info_) - return; - - DCHECK(!exe_path_.empty()); - - // The module represent the current executable only if the paths matches. - if (exe_path_ != module_key.module_path) - return; - - exe_certificate_info_ = std::make_unique<CertificateInfo>( - module_data.inspection_result->certificate_info); - - InitializeIfReady(); -} - void ThirdPartyConflictsManager::OnModuleDatabaseIdle() { if (on_module_database_idle_called_) return; @@ -333,6 +320,13 @@ SetTerminalState(State::kNoModuleListAvailableFailure); } +void ThirdPartyConflictsManager::OnExeCertificateCreated( + std::unique_ptr<CertificateInfo> exe_certificate_info) { + exe_certificate_info_ = std::move(exe_certificate_info); + + InitializeIfReady(); +} + void ThirdPartyConflictsManager::OnModuleListFilterCreated( scoped_refptr<ModuleListFilter> module_list_filter) { module_list_filter_ = std::move(module_list_filter);
diff --git a/chrome/browser/conflicts/third_party_conflicts_manager_win.h b/chrome/browser/conflicts/third_party_conflicts_manager_win.h index 08c8d86..d6b89c9c 100644 --- a/chrome/browser/conflicts/third_party_conflicts_manager_win.h +++ b/chrome/browser/conflicts/third_party_conflicts_manager_win.h
@@ -85,8 +85,6 @@ std::unique_ptr<ThirdPartyConflictsManager> instance); // ModuleDatabaseObserver: - void OnNewModuleFound(const ModuleInfoKey& module_key, - const ModuleInfoData& module_data) override; void OnModuleDatabaseIdle() override; // Invoked when the Third Party Module List component is registered with the @@ -141,6 +139,10 @@ } private: + // Called when |exe_certificate_info_| finishes its initialization. + void OnExeCertificateCreated( + std::unique_ptr<CertificateInfo> exe_certificate_info); + // Called when |module_list_filter_| finishes its initialization. void OnModuleListFilterCreated( scoped_refptr<ModuleListFilter> module_list_filter); @@ -185,9 +187,6 @@ // instances. bool on_module_database_idle_called_; - // Path to the current executable (expected to be chrome.exe). - base::FilePath exe_path_; - // The certificate info of the current executable. std::unique_ptr<CertificateInfo> exe_certificate_info_;
diff --git a/chrome/browser/devtools/protocol/DEPS b/chrome/browser/devtools/protocol/DEPS index 143a7ea..76297a7 100644 --- a/chrome/browser/devtools/protocol/DEPS +++ b/chrome/browser/devtools/protocol/DEPS
@@ -2,6 +2,6 @@ # TODO(mash): Fix. https://crbug.com/758061 "window_manager_handler\.cc": [ "+ash/shell.h", - "+ash/wm/overview/window_selector_controller.h", + "+ash/wm/overview/overview_controller.h", ] }
diff --git a/chrome/browser/devtools/protocol/window_manager_handler.cc b/chrome/browser/devtools/protocol/window_manager_handler.cc index 2f29033c..2db2187 100644 --- a/chrome/browser/devtools/protocol/window_manager_handler.cc +++ b/chrome/browser/devtools/protocol/window_manager_handler.cc
@@ -5,7 +5,7 @@ #include "chrome/browser/devtools/protocol/window_manager_handler.h" #include "ash/shell.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "content/public/browser/browser_thread.h" WindowManagerHandler::WindowManagerHandler( @@ -17,16 +17,14 @@ protocol::Response WindowManagerHandler::EnterOverviewMode() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - bool toggled = - ash::Shell::Get()->window_selector_controller()->ToggleOverview(); + bool toggled = ash::Shell::Get()->overview_controller()->ToggleOverview(); return toggled ? protocol::Response::OK() : protocol::Response::Error("Overview failed"); } protocol::Response WindowManagerHandler::ExitOverviewMode() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - bool toggled = - ash::Shell::Get()->window_selector_controller()->ToggleOverview(); + bool toggled = ash::Shell::Get()->overview_controller()->ToggleOverview(); return toggled ? protocol::Response::OK() : protocol::Response::Error("Overview failed"); }
diff --git a/chrome/browser/dom_distiller/distillable_page_utils_browsertest.cc b/chrome/browser/dom_distiller/distillable_page_utils_browsertest.cc index aa709ad..6dab36f 100644 --- a/chrome/browser/dom_distiller/distillable_page_utils_browsertest.cc +++ b/chrome/browser/dom_distiller/distillable_page_utils_browsertest.cc
@@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <string.h> +#include <cstring> +#include <memory> #include "base/command_line.h" #include "base/message_loop/message_loop.h" @@ -15,17 +16,20 @@ #include "chrome/test/base/ui_test_utils.h" #include "components/dom_distiller/content/browser/distillable_page_utils.h" #include "components/dom_distiller/core/dom_distiller_switches.h" +#include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gmock/include/gmock/gmock.h" namespace dom_distiller { +namespace { using ::testing::_; -using namespace switches::reader_mode_heuristics; -namespace { +// This is essentially an "enum" with human-readable strings (e.g. "adaboost", +// "none") as values. +using namespace switches::reader_mode_heuristics; const char kSimpleArticlePath[] = "/dom_distiller/simple_article.html"; const char kSimpleArticleIFramePath[] = @@ -33,24 +37,30 @@ const char kArticlePath[] = "/dom_distiller/og_article.html"; const char kNonArticlePath[] = "/dom_distiller/non_og_article.html"; -const char* kAllPaths[] = { - kSimpleArticlePath, - kSimpleArticleIFramePath, - kArticlePath, - kNonArticlePath -}; +const char* kAllPaths[] = {kSimpleArticlePath, kSimpleArticleIFramePath, + kArticlePath, kNonArticlePath}; + +const bool kIsDistillable = true; +const bool kIsNotDistillable = false; + +const bool kIsLast = true; +const bool kIsNotLast = false; + +const bool kIsNotMobileFriendly = false; class Holder { public: virtual ~Holder() {} - virtual void OnResult(bool, bool, bool) = 0; + virtual void OnResult(bool is_distillable, + bool is_last, + bool is_mobile_friendly) = 0; }; class MockDelegate : public Holder { public: MOCK_METHOD3(OnResult, void(bool, bool, bool)); - base::RepeatingCallback<void(bool, bool, bool)> GetDelegate() { + DistillabilityDelegate GetDelegate() { return base::BindRepeating(&MockDelegate::OnResult, base::Unretained(this)); } }; @@ -58,33 +68,32 @@ // Wait a bit to make sure there are no extra calls after the last expected // call. All the expected calls happen within ~1ms on linux release build, // so 100ms should be pretty safe to catch extra calls. +// // If there are no extra calls, changing this doesn't change the test result. const auto kWaitAfterLastCall = base::TimeDelta::FromMilliseconds(100); -// If there are no expected calls, the test wait for a while to make sure there -// are // no calls in this period of time. When there are expected calls, they -// happen within 100ms after content::WaitForLoadStop() on linux release build, -// and 10X safety margin is used. +// Wait a bit if no calls are expected to make sure any unexpected calls are +// caught. Expected calls happen within 100ms after content::WaitForLoadStop() +// on linux release build, so 1s provides a safe margin. +// // If there are no extra calls, changing this doesn't change the test result. const auto kWaitNoExpectedCall = base::TimeDelta::FromSeconds(1); } // namespace -template<const char Option[]> +template <const char Option[]> class DistillablePageUtilsBrowserTestOption : public InProcessBrowserTest { public: void SetUpCommandLine(base::CommandLine* command_line) override { command_line->AppendSwitch(switches::kEnableDomDistiller); - command_line->AppendSwitchASCII(switches::kReaderModeHeuristics, - Option); + command_line->AppendSwitchASCII(switches::kReaderModeHeuristics, Option); command_line->AppendSwitch(switches::kEnableDistillabilityService); } void SetUpOnMainThread() override { ASSERT_TRUE(embedded_test_server()->Start()); - web_contents_ = - browser()->tab_strip_model()->GetActiveWebContents(); - setDelegate(web_contents_, holder_.GetDelegate()); + web_contents_ = browser()->tab_strip_model()->GetActiveWebContents(); + SetDelegate(web_contents_, holder_.GetDelegate()); } void NavigateAndWait(const char* url, base::TimeDelta test_timeout) { @@ -119,106 +128,116 @@ content::WebContents* web_contents_ = nullptr; }; - using DistillablePageUtilsBrowserTestAlways = DistillablePageUtilsBrowserTestOption<kAlwaysTrue>; IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestAlways, - TestDelegate) { + AllRealPathsCallDelegateOnceWithIsDistillable) { for (unsigned i = 0; i < sizeof(kAllPaths) / sizeof(kAllPaths[0]); ++i) { testing::InSequence dummy; - EXPECT_CALL(holder_, OnResult(true, true, _)) + EXPECT_CALL(holder_, + OnResult(kIsDistillable, kIsLast, /* is_mobile_friendly = */ _)) .WillOnce(testing::InvokeWithoutArgs( this, &DistillablePageUtilsBrowserTestOption::QuitSoon)); NavigateAndWait(kAllPaths[i], base::TimeDelta()); } - // Test pages that we don't care about its distillability. - { - testing::InSequence dummy; - EXPECT_CALL(holder_, OnResult(_, _, _)).Times(0); - NavigateAndWait("about:blank", kWaitNoExpectedCall); - } } +IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestAlways, + LocalUrlsDoNotCallDelegate) { + EXPECT_CALL(holder_, OnResult(_, _, _)).Times(0); + NavigateAndWait("about:blank", kWaitNoExpectedCall); +} using DistillablePageUtilsBrowserTestNone = DistillablePageUtilsBrowserTestOption<kNone>; -IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestNone, - TestDelegate) { +IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestNone, NeverCallDelegate) { EXPECT_CALL(holder_, OnResult(_, _, _)).Times(0); NavigateAndWait(kSimpleArticlePath, kWaitNoExpectedCall); } - -using DistillablePageUtilsBrowserTestOG = +using DistillablePageUtilsBrowserTestOGArticle = DistillablePageUtilsBrowserTestOption<kOGArticle>; -IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestOG, - TestDelegate) { - { - testing::InSequence dummy; - EXPECT_CALL(holder_, OnResult(true, true, _)) - .WillOnce(testing::InvokeWithoutArgs( - this, &DistillablePageUtilsBrowserTestOption::QuitSoon)); - NavigateAndWait(kArticlePath, base::TimeDelta()); - } - { - testing::InSequence dummy; - EXPECT_CALL(holder_, OnResult(false, true, _)) - .WillOnce(testing::InvokeWithoutArgs( - this, &DistillablePageUtilsBrowserTestOption::QuitSoon)); - NavigateAndWait(kNonArticlePath, base::TimeDelta()); - } +IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestOGArticle, + ArticlesCallDelegateOnceWithIsDistillable) { + EXPECT_CALL(holder_, OnResult(kIsDistillable, kIsLast, _)) + .WillOnce(testing::InvokeWithoutArgs( + this, &DistillablePageUtilsBrowserTestOption::QuitSoon)); + NavigateAndWait(kArticlePath, base::TimeDelta()); } +IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestOGArticle, + NonArticleCallsDelegateOnceWithIsNotDistillable) { + EXPECT_CALL(holder_, OnResult(kIsNotDistillable, kIsLast, _)) + .WillOnce(testing::InvokeWithoutArgs( + this, &DistillablePageUtilsBrowserTestOption::QuitSoon)); + NavigateAndWait(kNonArticlePath, base::TimeDelta()); +} using DistillablePageUtilsBrowserTestAdaboost = DistillablePageUtilsBrowserTestOption<kAdaBoost>; IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestAdaboost, - TestDelegate) { + SimpleArticlesCallDelegateTwiceWithIsDistillable) { const char* paths[] = {kSimpleArticlePath, kSimpleArticleIFramePath}; - for (unsigned i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i) { + for (unsigned i = 0; i < sizeof(paths) / sizeof(paths[0]); ++i) { testing::InSequence dummy; - EXPECT_CALL(holder_, OnResult(true, false, false)).Times(1); - EXPECT_CALL(holder_, OnResult(true, true, false)) + EXPECT_CALL(holder_, + OnResult(kIsDistillable, kIsNotLast, kIsNotMobileFriendly)) + .Times(1); + EXPECT_CALL(holder_, + OnResult(kIsDistillable, kIsLast, kIsNotMobileFriendly)) .WillOnce(testing::InvokeWithoutArgs( this, &DistillablePageUtilsBrowserTestOption::QuitSoon)); NavigateAndWait(paths[i], base::TimeDelta()); } - { - testing::InSequence dummy; - EXPECT_CALL(holder_, OnResult(false, false, false)).Times(1); - EXPECT_CALL(holder_, OnResult(false, true, false)) - .WillOnce(testing::InvokeWithoutArgs( - this, &DistillablePageUtilsBrowserTestOption::QuitSoon)); - NavigateAndWait(kNonArticlePath, base::TimeDelta()); - } +} + +IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestAdaboost, + NonArticleCallsDelegateTwiceWithIsNotDistillable) { + testing::InSequence dummy; + EXPECT_CALL(holder_, + OnResult(kIsNotDistillable, kIsNotLast, kIsNotMobileFriendly)) + .Times(1); + EXPECT_CALL(holder_, + OnResult(kIsNotDistillable, kIsLast, kIsNotMobileFriendly)) + .WillOnce(testing::InvokeWithoutArgs( + this, &DistillablePageUtilsBrowserTestOption::QuitSoon)); + NavigateAndWait(kNonArticlePath, base::TimeDelta()); } using DistillablePageUtilsBrowserTestAllArticles = DistillablePageUtilsBrowserTestOption<kAllArticles>; IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestAllArticles, - TestDelegate) { + SimpleArticlesCallDelegateTwiceWithIsDistillable) { const char* paths[] = {kSimpleArticlePath, kSimpleArticleIFramePath}; for (unsigned i = 0; i < sizeof(paths) / sizeof(paths[0]); ++i) { testing::InSequence dummy; - EXPECT_CALL(holder_, OnResult(true, false, false)).Times(1); - EXPECT_CALL(holder_, OnResult(true, true, false)) + EXPECT_CALL(holder_, + OnResult(kIsDistillable, kIsNotLast, kIsNotMobileFriendly)) + .Times(1); + EXPECT_CALL(holder_, + OnResult(kIsDistillable, kIsLast, kIsNotMobileFriendly)) .WillOnce(testing::InvokeWithoutArgs( this, &DistillablePageUtilsBrowserTestOption::QuitSoon)); NavigateAndWait(paths[i], base::TimeDelta()); } - { - testing::InSequence dummy; - EXPECT_CALL(holder_, OnResult(false, false, false)).Times(1); - EXPECT_CALL(holder_, OnResult(false, true, false)) - .WillOnce(testing::InvokeWithoutArgs( - this, &DistillablePageUtilsBrowserTestOption::QuitSoon)); - NavigateAndWait(kNonArticlePath, base::TimeDelta()); - } +} + +IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestAllArticles, + NonArticlesCallDelegateTwiceWithIsNotDistillable) { + testing::InSequence dummy; + EXPECT_CALL(holder_, + OnResult(kIsNotDistillable, kIsNotLast, kIsNotMobileFriendly)) + .Times(1); + EXPECT_CALL(holder_, + OnResult(kIsNotDistillable, kIsLast, kIsNotMobileFriendly)) + .WillOnce(testing::InvokeWithoutArgs( + this, &DistillablePageUtilsBrowserTestOption::QuitSoon)); + NavigateAndWait(kNonArticlePath, base::TimeDelta()); } } // namespace dom_distiller
diff --git a/chrome/browser/extensions/activity_log/activity_log.cc b/chrome/browser/extensions/activity_log/activity_log.cc index d0ca2748..5acc8a4f 100644 --- a/chrome/browser/extensions/activity_log/activity_log.cc +++ b/chrome/browser/extensions/activity_log/activity_log.cc
@@ -562,6 +562,7 @@ extension_registry_observer_(this), active_consumers_(0), cached_consumer_count_(0), + has_listeners_(false), is_active_(false), weak_factory_(this) { SetActivityHandlers(); @@ -653,6 +654,11 @@ CheckActive(false); // don't use cached } +void ActivityLog::SetHasListeners(bool has_listeners) { + has_listeners_ = has_listeners; + CheckActive(false); // don't use cached +} + void ActivityLog::OnExtensionLoaded(content::BrowserContext* browser_context, const Extension* extension) { if (!ActivityLogAPI::IsExtensionWhitelisted(extension->id())) @@ -733,14 +739,17 @@ } if (IsDatabaseEnabled() && database_policy_) database_policy_->ProcessAction(action); - if (IsWatchdogAppActive()) + if (has_listeners_) observers_->Notify(FROM_HERE, &Observer::OnExtensionActivity, action); if (testing_mode_) VLOG(1) << action->PrintForDebug(); } bool ActivityLog::ShouldLog(const std::string& extension_id) const { - return is_active_ && !ActivityLogAPI::IsExtensionWhitelisted(extension_id); + // Do not log for activities from the browser/WebUI, which is indicated by an + // empty extension ID. + return is_active_ && !extension_id.empty() && + !ActivityLogAPI::IsExtensionWhitelisted(extension_id); } void ActivityLog::OnScriptsExecuted(content::WebContents* web_contents, @@ -850,12 +859,16 @@ } void ActivityLog::CheckActive(bool use_cached) { - bool has_consumer = - active_consumers_ || (use_cached && cached_consumer_count_); - bool needs_db = - has_consumer || base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableExtensionActivityLogging); - bool should_be_active = needs_db || has_consumer; + const bool has_switch = base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableExtensionActivityLogging); + const bool has_consumer = + active_consumers_ || (use_cached && cached_consumer_count_) || + // Only check |has_listeners_| if the switch is also present, since + // we want to ensure the activity log is inactive unless the switch + // or the app (covered by active_consumers_) is present. + (has_listeners_ && has_switch); + const bool needs_db = has_consumer || has_switch; + const bool should_be_active = needs_db || has_consumer; if (should_be_active == is_active_) return;
diff --git a/chrome/browser/extensions/activity_log/activity_log.h b/chrome/browser/extensions/activity_log/activity_log.h index 3115923a..a25c76a6 100644 --- a/chrome/browser/extensions/activity_log/activity_log.h +++ b/chrome/browser/extensions/activity_log/activity_log.h
@@ -136,6 +136,10 @@ // active. void SetWatchdogAppActiveForTesting(bool active); + bool has_listeners() const { return has_listeners_; } + + void SetHasListeners(bool has_listeners); + private: friend class ActivityLogTest; friend class BrowserContextKeyedAPIFactory<ActivityLog>; @@ -145,6 +149,8 @@ // Specifies if the Watchdog app is active (installed & enabled). // If so, we need to log to the database and stream to the API. + // TODO(kelvinjiang): eliminate this check if possible to simplify logic and + // for the deprecation of the Chrome Apps & Extensions Developer Tool. bool IsWatchdogAppActive(); // Specifies if we need to record actions to the db. If so, we need to log to @@ -214,6 +220,8 @@ extension_registry_observer_; // The number of active consumers of the activity log. + // TODO(kelvinjiang): eliminate this flag if possible and use has_listeners_ + // instead to simplify logic. int active_consumers_; // The cached number of consumers of the activity log. Maintained by the @@ -222,6 +230,10 @@ // all extensions have finished loading. int cached_consumer_count_; + // Whether there are listeners on the browser side for the onExtensionActivity + // event. + bool has_listeners_; + // True if the activity log is currently active, meaning that the user has // either added the commandline switch or has loaded a compatible extension. // While inactive, the activity log will not store any actions for performance
diff --git a/chrome/browser/extensions/activity_log/activity_log_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_unittest.cc index 3e350b9..1a9a60e 100644 --- a/chrome/browser/extensions/activity_log/activity_log_unittest.cc +++ b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
@@ -433,8 +433,11 @@ // Loading a watchdog app means the activity log should log other extension // activities... EXPECT_TRUE(activity_log->ShouldLog(empty_extension->id())); - // ... but not those of the watchdog app. + // ... but not those of the watchdog app... EXPECT_FALSE(activity_log->ShouldLog(activity_log_extension->id())); + // ... or activities from the browser/extensions page, represented by an empty + // extension ID. + EXPECT_FALSE(activity_log->ShouldLog(std::string())); extension_service_->DisableExtension(activity_log_extension->id(), disable_reason::DISABLE_USER_ACTION); // Disabling the watchdog app means that we're back to never logging anything.
diff --git a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc index fc01719..0f30ac87 100644 --- a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc +++ b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc
@@ -85,11 +85,19 @@ } void ActivityLogAPI::OnListenerAdded(const EventListenerInfo& details) { - // TODO(felt): Only observe activity_log_ events when we have a customer. + if (activity_log_->has_listeners()) + return; + StartOrStopListeningForExtensionActivities(); } void ActivityLogAPI::OnListenerRemoved(const EventListenerInfo& details) { - // TODO(felt): Only observe activity_log_ events when we have a customer. + StartOrStopListeningForExtensionActivities(); +} + +void ActivityLogAPI::StartOrStopListeningForExtensionActivities() { + EventRouter* event_router = EventRouter::Get(browser_context_); + activity_log_->SetHasListeners(event_router->HasEventListener( + activity_log_private::OnExtensionActivity::kEventName)); } void ActivityLogAPI::OnExtensionActivity(scoped_refptr<Action> activity) {
diff --git a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h index c162da48..d900d64 100644 --- a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h +++ b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h
@@ -50,6 +50,8 @@ void OnListenerAdded(const EventListenerInfo& details) override; void OnListenerRemoved(const EventListenerInfo& details) override; + void StartOrStopListeningForExtensionActivities(); + content::BrowserContext* browser_context_; ActivityLog* activity_log_; bool initialized_;
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc index 1379f8ec..0a3e5656 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc +++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
@@ -544,6 +544,56 @@ } //////////////////////////////////////////////////////////////////////////////// +// AutofillPrivateGetLocalCreditCardListFunction + +AutofillPrivateGetLocalCreditCardListFunction:: + AutofillPrivateGetLocalCreditCardListFunction() + : chrome_details_(this) {} + +AutofillPrivateGetLocalCreditCardListFunction:: + ~AutofillPrivateGetLocalCreditCardListFunction() {} + +ExtensionFunction::ResponseAction +AutofillPrivateGetLocalCreditCardListFunction::Run() { + autofill::PersonalDataManager* personal_data = + autofill::PersonalDataManagerFactory::GetForProfile( + chrome_details_.GetProfile()); + + DCHECK(personal_data && personal_data->IsDataLoaded()); + + autofill_util::CreditCardEntryList local_credit_card_list = + autofill_util::GenerateLocalCreditCardList(*personal_data); + return RespondNow(ArgumentList( + api::autofill_private::GetLocalCreditCardList::Results::Create( + local_credit_card_list))); +} + +//////////////////////////////////////////////////////////////////////////////// +// AutofillPrivateGetServerCreditCardListFunction + +AutofillPrivateGetServerCreditCardListFunction:: + AutofillPrivateGetServerCreditCardListFunction() + : chrome_details_(this) {} + +AutofillPrivateGetServerCreditCardListFunction:: + ~AutofillPrivateGetServerCreditCardListFunction() {} + +ExtensionFunction::ResponseAction +AutofillPrivateGetServerCreditCardListFunction::Run() { + autofill::PersonalDataManager* personal_data = + autofill::PersonalDataManagerFactory::GetForProfile( + chrome_details_.GetProfile()); + + DCHECK(personal_data && personal_data->IsDataLoaded()); + + autofill_util::CreditCardEntryList server_credit_card_list = + autofill_util::GenerateServerCreditCardList(*personal_data); + return RespondNow(ArgumentList( + api::autofill_private::GetServerCreditCardList::Results::Create( + server_credit_card_list))); +} + +//////////////////////////////////////////////////////////////////////////////// // AutofillPrivateMigrateCreditCardsFunction AutofillPrivateMigrateCreditCardsFunction::
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.h b/chrome/browser/extensions/api/autofill_private/autofill_private_api.h index dde502d..89a81e7 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.h +++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.h
@@ -174,6 +174,44 @@ DISALLOW_COPY_AND_ASSIGN(AutofillPrivateGetCreditCardListFunction); }; +class AutofillPrivateGetLocalCreditCardListFunction + : public UIThreadExtensionFunction { + public: + AutofillPrivateGetLocalCreditCardListFunction(); + DECLARE_EXTENSION_FUNCTION("autofillPrivate.getLocalCreditCardList", + AUTOFILLPRIVATE_GETLOCALCREDITCARDLIST); + + protected: + ~AutofillPrivateGetLocalCreditCardListFunction() override; + + // ExtensionFunction overrides. + ResponseAction Run() override; + + private: + ChromeExtensionFunctionDetails chrome_details_; + + DISALLOW_COPY_AND_ASSIGN(AutofillPrivateGetLocalCreditCardListFunction); +}; + +class AutofillPrivateGetServerCreditCardListFunction + : public UIThreadExtensionFunction { + public: + AutofillPrivateGetServerCreditCardListFunction(); + DECLARE_EXTENSION_FUNCTION("autofillPrivate.getServerCreditCardList", + AUTOFILLPRIVATE_GETSERVERCREDITCARDLIST); + + protected: + ~AutofillPrivateGetServerCreditCardListFunction() override; + + // ExtensionFunction overrides. + ResponseAction Run() override; + + private: + ChromeExtensionFunctionDetails chrome_details_; + + DISALLOW_COPY_AND_ASSIGN(AutofillPrivateGetServerCreditCardListFunction); +}; + class AutofillPrivateMigrateCreditCardsFunction : public UIThreadExtensionFunction { public:
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc index 33fa5ed..31cee78 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc +++ b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc
@@ -50,6 +50,7 @@ personal_data_->RemoveObserver(this); } +// TODO(crbug.com/923868): Change the 4 calls to a single OnPersonalDataChanged. void AutofillPrivateEventRouter::OnPersonalDataChanged() { // Ignore any updates before data is loaded. This can happen in tests. if (!(personal_data_ && personal_data_->IsDataLoaded())) @@ -76,6 +77,28 @@ api::autofill_private::OnCreditCardListChanged::kEventName, std::move(args))); event_router_->BroadcastEvent(std::move(extension_event)); + + autofill_util::CreditCardEntryList localCreditCardList = + extensions::autofill_util::GenerateLocalCreditCardList(*personal_data_); + args.reset(api::autofill_private::OnLocalCreditCardListChanged::Create( + localCreditCardList) + .release()); + extension_event.reset( + new Event(events::AUTOFILL_PRIVATE_ON_LOCAL_CREDIT_CARD_LIST_CHANGED, + api::autofill_private::OnLocalCreditCardListChanged::kEventName, + std::move(args))); + event_router_->BroadcastEvent(std::move(extension_event)); + + autofill_util::CreditCardEntryList serverCreditCardList = + extensions::autofill_util::GenerateServerCreditCardList(*personal_data_); + args.reset(api::autofill_private::OnLocalCreditCardListChanged::Create( + serverCreditCardList) + .release()); + extension_event.reset(new Event( + events::AUTOFILL_PRIVATE_ON_SERVER_CREDIT_CARD_LIST_CHANGED, + api::autofill_private::OnServerCreditCardListChanged::kEventName, + std::move(args))); + event_router_->BroadcastEvent(std::move(extension_event)); } AutofillPrivateEventRouter* AutofillPrivateEventRouter::Create(
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h index 43e99c8..58236ef 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h +++ b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h
@@ -21,8 +21,7 @@ namespace extensions { // An event router that observes changes to autofill addresses and credit cards -// and notifies listeners to the onAddressListChanged and -// onCreditCardListChanged events of changes. +// and notifies listeners to the autofill API events. class AutofillPrivateEventRouter : public KeyedService, public EventRouter::Observer,
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chrome/browser/extensions/api/autofill_private/autofill_util.cc index 157f6c0..46c50c8 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_util.cc +++ b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
@@ -221,6 +221,35 @@ return list; } +CreditCardEntryList GenerateLocalCreditCardList( + const autofill::PersonalDataManager& personal_data) { + const std::vector<autofill::CreditCard*>& all_cards = + personal_data.GetCreditCards(); + + CreditCardEntryList list; + for (const autofill::CreditCard* card : all_cards) { + // Keep only local and full server cards. + if (card->record_type() == autofill::CreditCard::LOCAL_CARD || + card->record_type() == autofill::CreditCard::FULL_SERVER_CARD) { + list.push_back(CreditCardToCreditCardEntry(*card, personal_data)); + } + } + + return list; +} + +CreditCardEntryList GenerateServerCreditCardList( + const autofill::PersonalDataManager& personal_data) { + const std::vector<autofill::CreditCard*>& server_cards = + personal_data.GetServerCreditCards(); + + CreditCardEntryList list; + for (const autofill::CreditCard* card : server_cards) + list.push_back(CreditCardToCreditCardEntry(*card, personal_data)); + + return list; +} + } // namespace autofill_util } // namespace extensions
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.h b/chrome/browser/extensions/api/autofill_private/autofill_util.h index 7dabff6..180d888 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_util.h +++ b/chrome/browser/extensions/api/autofill_private/autofill_util.h
@@ -34,6 +34,16 @@ CreditCardEntryList GenerateCreditCardList( const autofill::PersonalDataManager& personal_data); +// Uses |personal_data| to generate a list of up-to-date local CreditCardEntry +// objects. +CreditCardEntryList GenerateLocalCreditCardList( + const autofill::PersonalDataManager& personal_data); + +// Uses |personal_data| to generate a list of up-to-date server CreditCardEntry +// objects. +CreditCardEntryList GenerateServerCreditCardList( + const autofill::PersonalDataManager& personal_data); + } // namespace autofill_util } // namespace extensions
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper_unittest.cc b/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper_unittest.cc index 80caf385c..06d3f56 100644 --- a/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper_unittest.cc +++ b/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper_unittest.cc
@@ -33,7 +33,7 @@ std::string expected_os_info; expected_os_info = base::StringPrintf( - "{\"arch\":\"%s\",\"os\":\"%s\",\"os_version\":\"%s\"}", + R"({"arch":"%s","os":"%s","os_version":"%s"})", policy::GetOSArchitecture().c_str(), policy::GetOSPlatform().c_str(), policy::GetOSVersion().c_str()); request = @@ -46,7 +46,7 @@ std::unique_ptr<em::ChromeDesktopReportRequest> request; std::string expected_machine_name; - expected_machine_name = base::StringPrintf("{\"computername\":\"%s\"}", + expected_machine_name = base::StringPrintf(R"({"computername":"%s"})", policy::GetMachineName().c_str()); request = GenerateChromeDesktopReportRequest(base::DictionaryValue(), &profile_); @@ -61,7 +61,7 @@ // The username needs to be escaped as the name can contain slashes. base::EscapeJSONString(policy::GetOSUsername(), false, &os_username_escaped); expected_os_username = - base::StringPrintf("{\"username\":\"%s\"}", os_username_escaped.c_str()); + base::StringPrintf(R"({"username":"%s"})", os_username_escaped.c_str()); request = GenerateChromeDesktopReportRequest(base::DictionaryValue(), &profile_); @@ -93,7 +93,7 @@ // Extension list will be a empty list by default. expected_extension_list = "[]"; report = base::DictionaryValue::From(base::JSONReader::Read( - "{\"browserReport\": {\"chromeUserProfileReport\":[{}]}}")); + R"({"browserReport": {"chromeUserProfileReport":[{}]}})")); ASSERT_TRUE(report); request = GenerateChromeDesktopReportRequest(*report, &profile_); ASSERT_TRUE(request); @@ -102,10 +102,15 @@ .extension_data()); // Extension list will be copied from the |report|. - expected_extension_list = "[{\"id\":\"1\"}]"; + expected_extension_list = R"([{"id":"1\\\""}])"; report = base::DictionaryValue::From(base::JSONReader::Read( - "{\"browserReport\": " - "{\"chromeUserProfileReport\":[{\"extensionData\":[{\"id\":\"1\"}]}]}}")); + R"({"browserReport": + {"chromeUserProfileReport": + [ + {"extensionData": [{"id":"1\\\""}]} + ] + } + })")); ASSERT_TRUE(report); request = GenerateChromeDesktopReportRequest(*report, &profile_); ASSERT_TRUE(request); @@ -114,6 +119,49 @@ .extension_data()); } +TEST_F(ChromeDesktopReportRequestGeneratorTest, PluginList) { + std::unique_ptr<em::ChromeDesktopReportRequest> request; + std::unique_ptr<base::DictionaryValue> report; + std::string expected_plugin_list; + + expected_plugin_list = R"([{"id":"1\\\""}])"; + report = base::DictionaryValue::From(base::JSONReader::Read( + R"({"browserReport": + {"chromeUserProfileReport": + [ + {"plugins": [{"id":"1\\\""}]} + ] + } + })")); + ASSERT_TRUE(report); + request = GenerateChromeDesktopReportRequest(*report, &profile_); + ASSERT_TRUE(request); + EXPECT_EQ(expected_plugin_list, + request->browser_report().chrome_user_profile_reports(0).plugins()); +} + +TEST_F(ChromeDesktopReportRequestGeneratorTest, SignedInUser) { + std::unique_ptr<em::ChromeDesktopReportRequest> request; + std::unique_ptr<base::DictionaryValue> report; + std::string expected_signed_in_user; + + expected_signed_in_user = R"({"email":"a\\@example.com"})"; + report = base::DictionaryValue::From(base::JSONReader::Read( + R"({"browserReport": + {"chromeUserProfileReport": + [ + {"chromeSignInUser": {"email":"a\\@example.com"}} + ] + } + })")); + ASSERT_TRUE(report); + request = GenerateChromeDesktopReportRequest(*report, &profile_); + ASSERT_TRUE(request); + EXPECT_EQ(expected_signed_in_user, request->browser_report() + .chrome_user_profile_reports(0) + .chrome_signed_in_user()); +} + TEST_F(ChromeDesktopReportRequestGeneratorTest, ProfileID) { std::unique_ptr<em::ChromeDesktopReportRequest> request; @@ -126,10 +174,12 @@ // Profile ID will be merged into the first item of // |chrome_user_profile_reports| - std::unique_ptr<base::DictionaryValue> report = base::DictionaryValue::From( - base::JSONReader::Read("{\"browserReport\": " - "{\"chromeUserProfileReport\":[{\"extensionData\":" - "[{\"id\":\"1\"}]}]}}")); + std::unique_ptr<base::DictionaryValue> report = + base::DictionaryValue::From(base::JSONReader::Read(R"({"browserReport": + {"chromeUserProfileReport":[ + {"extensionData": [{"id":"1"}]} + ]} + })")); ASSERT_TRUE(report); request = GenerateChromeDesktopReportRequest(*report, &profile_); ASSERT_TRUE(request); @@ -141,14 +191,14 @@ // |request| will not be generated if the type of input is invalid. std::unique_ptr<base::DictionaryValue> report; report = base::DictionaryValue::From(base::JSONReader::Read( - "{\"browserReport\": " - "{\"chromeUserProfileReport\":[{\"extensionData\":{}}]}}")); + R"({"browserReport": + {"chromeUserProfileReport":[{"extensionData":{}}]}})")); ASSERT_TRUE(report); EXPECT_FALSE(GenerateChromeDesktopReportRequest(*report, &profile_)); report = base::DictionaryValue::From(base::JSONReader::Read( - "{\"browserReport\": " - "{\"chromeUserProfileReport\":[{\"chromeSignInUser\":\"\"}]}}")); + R"({"browserReport": + {"chromeUserProfileReport":[{"chromeSignInUser":""}]}})")); ASSERT_TRUE(report); EXPECT_FALSE(GenerateChromeDesktopReportRequest(*report, &profile_)); } @@ -158,24 +208,33 @@ true); std::unique_ptr<base::DictionaryValue> report; - report = base::DictionaryValue::From( - base::JSONReader::Read("{\"browserReport\": " - "{\"chromeUserProfileReport\":[{" - "\"safeBrowsingWarnings\":\"invalid\"}]}}")); + report = + base::DictionaryValue::From(base::JSONReader::Read(R"({"browserReport": + {"chromeUserProfileReport":[{ + "safeBrowsingWarnings":"invalid" + }] + } + })")); ASSERT_TRUE(report); EXPECT_FALSE(GenerateChromeDesktopReportRequest(*report, &profile_)); report = base::DictionaryValue::From(base::JSONReader::Read( - "{\"browserReport\": " - "{\"chromeUserProfileReport\":[{\"safeBrowsingWarningsClickThrough\":" - "\"invalid\"}]}}")); + R"({"browserReport": + {"chromeUserProfileReport":[{ + "safeBrowsingWarningsClickThrough": "invalid"}] + } + })")); ASSERT_TRUE(report); EXPECT_FALSE(GenerateChromeDesktopReportRequest(*report, &profile_)); report = base::DictionaryValue::From(base::JSONReader::Read( - "{\"browserReport\": " - "{\"chromeUserProfileReport\":[{\"safeBrowsingWarnings\":3, " - "\"safeBrowsingWarningsClickThrough\":1}]}}")); + R"({"browserReport": + {"chromeUserProfileReport":[{ + "safeBrowsingWarnings":3, + "safeBrowsingWarningsClickThrough":1 + }] + } + })")); ASSERT_TRUE(report); std::unique_ptr<em::ChromeDesktopReportRequest> request = GenerateChromeDesktopReportRequest(*report, &profile_);
diff --git a/chrome/browser/extensions/api/identity/identity_api.cc b/chrome/browser/extensions/api/identity/identity_api.cc index 0f6accc6..c707116 100644 --- a/chrome/browser/extensions/api/identity/identity_api.cc +++ b/chrome/browser/extensions/api/identity/identity_api.cc
@@ -26,7 +26,6 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/account_consistency_mode_manager.h" -#include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/common/extensions/api/identity.h" @@ -102,7 +101,6 @@ IdentityAPI::IdentityAPI(content::BrowserContext* context) : profile_(Profile::FromBrowserContext(context)) { - AccountTrackerServiceFactory::GetForProfile(profile_)->AddObserver(this); IdentityManagerFactory::GetForProfile(profile_)->AddObserver(this); } @@ -145,7 +143,6 @@ void IdentityAPI::Shutdown() { on_shutdown_callback_list_.Notify(); - AccountTrackerServiceFactory::GetForProfile(profile_)->RemoveObserver(this); IdentityManagerFactory::GetForProfile(profile_)->RemoveObserver(this); } @@ -178,7 +175,7 @@ FireOnAccountSignInChanged(account_info.gaia, true); } -void IdentityAPI::OnAccountRemoved(const AccountInfo& account_info) { +void IdentityAPI::OnAccountRemovedWithInfo(const AccountInfo& account_info) { DCHECK(!account_info.gaia.empty()); FireOnAccountSignInChanged(account_info.gaia, false); }
diff --git a/chrome/browser/extensions/api/identity/identity_api.h b/chrome/browser/extensions/api/identity/identity_api.h index d3e63e79..28a28870 100644 --- a/chrome/browser/extensions/api/identity/identity_api.h +++ b/chrome/browser/extensions/api/identity/identity_api.h
@@ -29,7 +29,6 @@ #include "chrome/browser/extensions/api/identity/identity_remove_cached_auth_token_function.h" #include "chrome/browser/extensions/api/identity/web_auth_flow.h" #include "chrome/browser/extensions/chrome_extension_function.h" -#include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/signin_buildflags.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/browser/event_router.h" @@ -80,7 +79,6 @@ }; class IdentityAPI : public BrowserContextKeyedAPI, - public AccountTrackerService::Observer, public identity::IdentityManager::Observer { public: typedef std::map<ExtensionTokenKey, IdentityTokenCacheValue> CachedTokens; @@ -133,17 +131,13 @@ // identity::IdentityManager::Observer: void OnRefreshTokenUpdatedForAccount( const AccountInfo& account_info) override; - - // AccountTrackerService::Observer: // NOTE: This class listens for signout events via this callback (which itself // is triggered by O2TS::OnRefreshTokenRevoked()) rather than directly via // OnRefreshTokenRevoked() in order to obtain the Gaia ID of the signed-out // account, which is needed to send as input to the // chrome.identity.onSigninChanged event. That Gaia ID is not guaranteed to be // available from O2TS::OnRefreshTokenRevoked(). - // TODO(blundell): Eliminate this kludge by porting this class to interact - // with IdentityManager. - void OnAccountRemoved(const AccountInfo& info) override; + void OnAccountRemovedWithInfo(const AccountInfo& info) override; // Fires the chrome.identity.onSignInChanged event. void FireOnAccountSignInChanged(const std::string& gaia_id,
diff --git a/chrome/browser/extensions/extension_keybinding_registry.cc b/chrome/browser/extensions/extension_keybinding_registry.cc index 76ea0e6..3cfc0a8 100644 --- a/chrome/browser/extensions/extension_keybinding_registry.cc +++ b/chrome/browser/extensions/extension_keybinding_registry.cc
@@ -12,14 +12,29 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/command.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/media_keys_listener_manager.h" #include "extensions/browser/event_router.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/notification_types.h" #include "extensions/common/extension_set.h" #include "extensions/common/manifest_constants.h" +#if !defined(OS_CHROMEOS) +#include "media/base/media_switches.h" +#endif + namespace { + +bool ShouldUseMediaKeysListenerManager() { +#if defined(OS_CHROMEOS) + return false; +#else + return base::FeatureList::IsEnabled(media::kHardwareMediaKeyHandling); +#endif +} + const char kOnCommandEventName[] = "commands.onCommand"; + } // namespace namespace extensions { @@ -57,6 +72,7 @@ void ExtensionKeybindingRegistry::RemoveExtensionKeybinding( const Extension* extension, const std::string& command_name) { + bool any_media_keys_removed = false; auto it = event_targets_.begin(); while (it != event_targets_.end()) { TargetList& target_list = it->second; @@ -74,9 +90,11 @@ // Let each platform-specific implementation get a chance to clean up. RemoveExtensionKeybindingImpl(old->first, command_name); - // If the key is a media key, inform the MediaKeysListener. - if (media_keys_listener_ && Command::IsMediaKey(old->first)) - media_keys_listener_->StopWatchingMediaKey(old->first.key_code()); + if (Command::IsMediaKey(old->first)) { + any_media_keys_removed = true; + if (media_keys_listener_) + media_keys_listener_->StopWatchingMediaKey(old->first.key_code()); + } event_targets_.erase(old); @@ -86,6 +104,17 @@ break; } } + + // If we're no longer listening to any media keys, tell the browser that + // it can start handling media keys. + if (any_media_keys_removed && ShouldUseMediaKeysListenerManager() && + !IsListeningToAnyMediaKeys()) { + content::MediaKeysListenerManager* media_keys_listener_manager = + content::MediaKeysListenerManager::GetInstance(); + DCHECK(media_keys_listener_manager); + + media_keys_listener_manager->EnableInternalMediaKeyHandling(); + } } void ExtensionKeybindingRegistry::Init() { @@ -151,10 +180,22 @@ std::make_pair(extension_id, command_name)); // Shortcuts except media keys have only one target in the list. See comment // about |event_targets_|. - if (!Command::IsMediaKey(accelerator)) + if (!Command::IsMediaKey(accelerator)) { DCHECK_EQ(1u, event_targets_[accelerator].size()); - else if (media_keys_listener_) - media_keys_listener_->StartWatchingMediaKey(accelerator.key_code()); + } else { + if (media_keys_listener_) + media_keys_listener_->StartWatchingMediaKey(accelerator.key_code()); + + // Tell the browser that it should not handle media keys, since we're going + // to handle them. + if (ShouldUseMediaKeysListenerManager()) { + content::MediaKeysListenerManager* media_keys_listener_manager = + content::MediaKeysListenerManager::GetInstance(); + DCHECK(media_keys_listener_manager); + + media_keys_listener_manager->DisableInternalMediaKeyHandling(); + } + } } bool ExtensionKeybindingRegistry::GetFirstTarget( @@ -278,4 +319,12 @@ return executed; } +bool ExtensionKeybindingRegistry::IsListeningToAnyMediaKeys() const { + for (const auto& accelerator_target : event_targets_) { + if (Command::IsMediaKey(accelerator_target.first)) + return true; + } + return false; +} + } // namespace extensions
diff --git a/chrome/browser/extensions/extension_keybinding_registry.h b/chrome/browser/extensions/extension_keybinding_registry.h index 3cdbd07..8c1e570 100644 --- a/chrome/browser/extensions/extension_keybinding_registry.h +++ b/chrome/browser/extensions/extension_keybinding_registry.h
@@ -159,6 +159,9 @@ bool ExecuteCommands(const ui::Accelerator& accelerator, const std::string& extension_id); + // Returns true if any media keys are registered. + bool IsListeningToAnyMediaKeys() const; + // The content notification registrar for listening to extension events. content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/extensions/global_shortcut_listener_win.cc b/chrome/browser/extensions/global_shortcut_listener_win.cc index e5cfd70..b6519845 100644 --- a/chrome/browser/extensions/global_shortcut_listener_win.cc +++ b/chrome/browser/extensions/global_shortcut_listener_win.cc
@@ -6,8 +6,12 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/feature_list.h" #include "base/win/win_util.h" +#include "chrome/common/extensions/command.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/media_keys_listener_manager.h" +#include "media/base/media_switches.h" #include "ui/base/accelerators/accelerator.h" #include "ui/events/event_constants.h" #include "ui/events/keycodes/keyboard_code_conversion_win.h" @@ -18,6 +22,14 @@ namespace extensions { +namespace { + +bool ShouldUseMediaKeysListenerManager() { + return base::FeatureList::IsEnabled(media::kHardwareMediaKeyHandling); +} + +} // namespace + // static GlobalShortcutListener* GlobalShortcutListener::GetInstance() { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -70,6 +82,26 @@ const ui::Accelerator& accelerator) { DCHECK(hotkeys_.find(accelerator) == hotkeys_.end()); + // If we want to listen for media keys, we should do that through the + // MediaKeysListenerManager, which will tell the manager to send us media keys + // and prevent the HardwareKeyMediaController from receiving the keys. + if (ShouldUseMediaKeysListenerManager() && Command::IsMediaKey(accelerator)) { + content::MediaKeysListenerManager* media_keys_listener_manager = + content::MediaKeysListenerManager::GetInstance(); + DCHECK(media_keys_listener_manager); + + bool success = media_keys_listener_manager->StartWatchingMediaKey( + accelerator.key_code(), this); + + // Map the hot key to nullptr, since we don't need a + // SingletonHwndHotKeyObserver when the MediaKeysListenerManager is taking + // care of it. + if (success) + hotkeys_[accelerator] = nullptr; + + return success; + } + // Create an observer that registers a hot key for |accelerator|. std::unique_ptr<gfx::SingletonHwndHotKeyObserver> observer = gfx::SingletonHwndHotKeyObserver::Create( @@ -91,7 +123,25 @@ HotKeyMap::iterator it = hotkeys_.find(accelerator); DCHECK(it != hotkeys_.end()); + // If we're routing media keys through the MediaKeysListenerManager, then + // inform the manager that we're no longer listening to the given key. + if (ShouldUseMediaKeysListenerManager() && Command::IsMediaKey(accelerator)) { + content::MediaKeysListenerManager* media_keys_listener_manager = + content::MediaKeysListenerManager::GetInstance(); + DCHECK(media_keys_listener_manager); + + media_keys_listener_manager->StopWatchingMediaKey(accelerator.key_code(), + this); + } + hotkeys_.erase(it); } +void GlobalShortcutListenerWin::OnMediaKeysAccelerator( + const ui::Accelerator& accelerator) { + // We should not receive media key events that we didn't register for. + DCHECK(hotkeys_.find(accelerator) != hotkeys_.end()); + NotifyKeyPressed(accelerator); +} + } // namespace extensions
diff --git a/chrome/browser/extensions/global_shortcut_listener_win.h b/chrome/browser/extensions/global_shortcut_listener_win.h index 91f75cc..800c5c9 100644 --- a/chrome/browser/extensions/global_shortcut_listener_win.h +++ b/chrome/browser/extensions/global_shortcut_listener_win.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "chrome/browser/extensions/global_shortcut_listener.h" +#include "ui/base/accelerators/media_keys_listener.h" namespace gfx { @@ -23,7 +24,8 @@ // Windows-specific implementation of the GlobalShortcutListener class that // listens for global shortcuts. Handles setting up a keyboard hook and // forwarding its output to the base class for processing. -class GlobalShortcutListenerWin : public GlobalShortcutListener { +class GlobalShortcutListenerWin : public GlobalShortcutListener, + public ui::MediaKeysListener::Delegate { public: GlobalShortcutListenerWin(); ~GlobalShortcutListenerWin() override; @@ -38,10 +40,14 @@ bool RegisterAcceleratorImpl(const ui::Accelerator& accelerator) override; void UnregisterAcceleratorImpl(const ui::Accelerator& accelerator) override; + // ui::MediaKeysListener::Delegate implementation. + void OnMediaKeysAccelerator(const ui::Accelerator& accelerator) override; + // Whether this object is listening for global shortcuts. bool is_listening_; - // A map of registered accelerators and their registration ids. + // A map of registered accelerators and their registration ids. The value is + // null for media keys if kHardwareMediaKeyHandling is true. using HotKeyMap = std::map<ui::Accelerator, std::unique_ptr<gfx::SingletonHwndHotKeyObserver>>; HotKeyMap hotkeys_;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 2450e0c5..350256b 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -118,12 +118,12 @@ }, { "name": "arc-available-for-child", - // "owners": [ "your-team" ], + "owners": [ "//chrome/browser/chromeos/arc/enterprise/OWNERS" ], "expiry_milestone": 76 }, { "name": "arc-boot-completed-broadcast", - // "owners": [ "your-team" ], + "owners": [ "//components/arc/common/ARC_SECURITY_OWNERS" ], "expiry_milestone": 76 }, { @@ -133,22 +133,22 @@ }, { "name": "arc-file-picker-experiment", - // "owners": [ "your-team" ], - "expiry_milestone": 76 + "owners": [ "niwa" ], + "expiry_milestone": 80 }, { "name": "arc-native-bridge-experiment", - // "owners": [ "your-team" ], + "owners": [ "levarum@google.com" ], "expiry_milestone": 76 }, { "name": "arc-usb-host", - // "owners": [ "your-team" ], + "owners": [ "lgcheng" ], "expiry_milestone": 76 }, { "name": "arc-vpn", - // "owners": [ "your-team" ], + "owners": [ "cros-networking@google.com" ], "expiry_milestone": 76 }, { @@ -163,21 +163,11 @@ "expiry_milestone": 76 }, { - "name": "ash-enable-cursor-motion-blur", - // "owners": [ "your-team" ], - "expiry_milestone": 76 - }, - { "name": "ash-enable-docked-magnifier", // "owners": [ "your-team" ], "expiry_milestone": 76 }, { - "name": "ash-enable-mirrored-screen", - // "owners": [ "your-team" ], - "expiry_milestone": 76 - }, - { "name": "ash-enable-night-light", // "owners": [ "your-team" ], "expiry_milestone": 76 @@ -2084,6 +2074,11 @@ "expiry_milestone": 76 }, { + "name": "enable-web-authentication-cable-support", + "owners": [ "webauthn-team@google.com" ], + "expiry_milestone": 80 + }, + { "name": "enable-web-authentication-testing-api", "owners": [ "webauthn-team@google.com" ], "expiry_milestone": -1
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 1d87daab..effae83 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -498,10 +498,6 @@ "Enable support for specifying a target element using a css selector in " "the fragment identifier."; -const char kEnableCursorMotionBlurName[] = "Enable Cursor Motion Blur"; -const char kEnableCursorMotionBlurDescription[] = - "Enable motion blur effect for the cursor."; - const char kEnableNoScriptPreviewsName[] = "NoScript previews"; const char kEnableNoScriptPreviewsDescription[] = @@ -942,10 +938,6 @@ const char kEnableWasmDescription[] = "Enable web pages to use WebAssembly structured cloning."; -const char kEnableWebAuthenticationAPIName[] = "Web Authentication API"; -const char kEnableWebAuthenticationAPIDescription[] = - "Enable Web Authentication API support."; - const char kEnableWebAuthenticationCableSupportName[] = "Web Authentication caBLE support"; const char kEnableWebAuthenticationCableSupportDescription[] = @@ -2840,11 +2832,6 @@ "Enable support for using Web Authentication API via Bluetooth security " "keys"; -const char kEnableWebAuthenticationCtap2SupportName[] = - "Enable Web Authentication API support for CTAP2 security keys"; -const char kEnableWebAuthenticationCtap2SupportDescription[] = - "Enable CTAP2 security keys for the Web Authentication API."; - const char kEnableWebAuthenticationTestingAPIName[] = "Web Authentication Testing API"; const char kEnableWebAuthenticationTestingAPIDescription[] = @@ -3016,11 +3003,6 @@ "Fullscreen content window detaches from main browser window and goes to " "a new space without moving or changing the original browser window."; -const char kEnableWebAuthenticationTouchIdName[] = - "Web Authentication API Touch ID support"; -const char kEnableWebAuthenticationTouchIdDescription[] = - "Enables a built-in Touch ID authenticator for the Web Authentication API."; - const char kHostedAppsInWindowsName[] = "Allow hosted apps to be opened in windows"; const char kHostedAppsInWindowsDescription[] = @@ -3106,21 +3088,11 @@ const char kArcVpnDescription[] = "Allow Android VPN clients to tunnel Chrome traffic."; -const char kAshDisableLoginDimAndBlurName[] = - "Disable dimming and blur on login screen."; -const char kAshDisableLoginDimAndBlurDescription[] = - "Disable dimming and blur on login screen."; - const char kAshEnableDisplayMoveWindowAccelsName[] = "Enable shortcuts for moving window between displays."; const char kAshEnableDisplayMoveWindowAccelsDescription[] = "Enable shortcuts for moving window between displays."; -const char kAshEnableMirroredScreenName[] = "Enable mirrored screen mode."; -const char kAshEnableMirroredScreenDescription[] = - "Enable the mirrored screen mode. This mode flips the screen image " - "horizontally."; - const char kAshEnablePersistentWindowBoundsName[] = "Enable persistent window bounds in multi-displays scenario."; const char kAshEnablePersistentWindowBoundsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 21b1a5f0..98b1543 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -334,9 +334,6 @@ extern const char kEnableCSSFragmentIdentifiersName[]; extern const char kEnableCSSFragmentIdentifiersDescription[]; -extern const char kEnableCursorMotionBlurName[]; -extern const char kEnableCursorMotionBlurDescription[]; - extern const char kEnableNoScriptPreviewsName[]; extern const char kEnableNoScriptPreviewsDescription[]; @@ -567,9 +564,6 @@ extern const char kEnableWasmName[]; extern const char kEnableWasmDescription[]; -extern const char kEnableWebAuthenticationAPIName[]; -extern const char kEnableWebAuthenticationAPIDescription[]; - extern const char kEnableWebAuthenticationCableSupportName[]; extern const char kEnableWebAuthenticationCableSupportDescription[]; @@ -1689,9 +1683,6 @@ extern const char kEnableWebAuthenticationBleSupportName[]; extern const char kEnableWebAuthenticationBleSupportDescription[]; -extern const char kEnableWebAuthenticationCtap2SupportName[]; -extern const char kEnableWebAuthenticationCtap2SupportDescription[]; - extern const char kEnableWebAuthenticationTestingAPIName[]; extern const char kEnableWebAuthenticationTestingAPIDescription[]; @@ -1791,9 +1782,6 @@ extern const char kContentFullscreenName[]; extern const char kContentFullscreenDescription[]; -extern const char kEnableWebAuthenticationTouchIdName[]; -extern const char kEnableWebAuthenticationTouchIdDescription[]; - extern const char kHostedAppsInWindowsName[]; extern const char kHostedAppsInWindowsDescription[]; @@ -1861,15 +1849,9 @@ extern const char kArcVpnName[]; extern const char kArcVpnDescription[]; -extern const char kAshDisableLoginDimAndBlurName[]; -extern const char kAshDisableLoginDimAndBlurDescription[]; - extern const char kAshEnableDisplayMoveWindowAccelsName[]; extern const char kAshEnableDisplayMoveWindowAccelsDescription[]; -extern const char kAshEnableMirroredScreenName[]; -extern const char kAshEnableMirroredScreenDescription[]; - extern const char kAshEnablePersistentWindowBoundsName[]; extern const char kAshEnablePersistentWindowBoundsDescription[];
diff --git a/chrome/browser/media/router/discovery/discovery_network_list_wifi_mac.mm b/chrome/browser/media/router/discovery/discovery_network_list_wifi_mac.mm index b21b5da..40610665 100644 --- a/chrome/browser/media/router/discovery/discovery_network_list_wifi_mac.mm +++ b/chrome/browser/media/router/discovery/discovery_network_list_wifi_mac.mm
@@ -12,6 +12,12 @@ #include "base/logging.h" #include "base/strings/sys_string_conversions.h" +// TODO(crbug.com/841631): This file uses the deprecated CWInterface interface; +// it needs to be migrated to CWWiFiClient, which is unfortunately not +// compatible. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + namespace media_router { namespace { @@ -42,3 +48,5 @@ } } // namespace media_router + +#pragma clang diagnostic pop
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm index 14eae35..3cac8b3d 100644 --- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm +++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
@@ -116,8 +116,11 @@ - (id)init:(NSString*)name { if ((self = [super init])) { + base::scoped_nsobject<NSDateFormatter> iso8601day( + [[NSDateFormatter alloc] init]); + [iso8601day setDateFormat:@"yyyy-MM-dd"]; name_.reset([name retain]); - date_.reset([[NSDate dateWithNaturalLanguageString:@"12/12/12"] retain]); + date_.reset([[iso8601day dateFromString:@"2012-12-12"] retain]); } return self; }
diff --git a/chrome/browser/memory_details_mac.cc b/chrome/browser/memory_details_mac.cc index 2bebccc..b9d67ca 100644 --- a/chrome/browser/memory_details_mac.cc +++ b/chrome/browser/memory_details_mac.cc
@@ -50,6 +50,13 @@ info.product_name = base::ASCIIToUTF16(version_info::GetProductName()); info.version = base::ASCIIToUTF16(version_info::GetVersionNumber()); + // A PortProvider is not necessary to acquire information about the number + // of open file descriptors. + std::unique_ptr<base::ProcessMetrics> metrics( + base::ProcessMetrics::CreateProcessMetrics(pid, nullptr)); + info.num_open_fds = metrics->GetOpenFdCount(); + info.open_fds_soft_limit = metrics->GetOpenFdSoftLimit(); + // Check if this is one of the child processes whose data was already // collected and exists in |child_data|. for (const ProcessMemoryInformation& child : child_info) {
diff --git a/chrome/browser/metrics/browser_window_histogram_helper.h b/chrome/browser/metrics/browser_window_histogram_helper.h index 05f7aa8..c0bd5aac 100644 --- a/chrome/browser/metrics/browser_window_histogram_helper.h +++ b/chrome/browser/metrics/browser_window_histogram_helper.h
@@ -34,11 +34,7 @@ explicit BrowserWindowHistogramHelper(ui::Compositor* compositor); // ui::CompositorObserver: - void OnCompositingDidCommit(ui::Compositor* compositor) override {} - void OnCompositingStarted(ui::Compositor* compositor, - base::TimeTicks start_time) override {} void OnCompositingEnded(ui::Compositor* compositor) override; - void OnCompositingChildResizing(ui::Compositor* compositor) override {} void OnCompositingShuttingDown(ui::Compositor* compositor) override; ScopedObserver<ui::Compositor, ui::CompositorObserver> scoped_observer_;
diff --git a/chrome/browser/metrics/plugin_metrics_provider.cc b/chrome/browser/metrics/plugin_metrics_provider.cc index 6abaf49..ca779cca 100644 --- a/chrome/browser/metrics/plugin_metrics_provider.cc +++ b/chrome/browser/metrics/plugin_metrics_provider.cc
@@ -30,7 +30,7 @@ namespace { // Delay for RecordCurrentState execution. -const int kRecordStateDelayMs = 15 * base::Time::kMillisecondsPerSecond; +constexpr base::TimeDelta kRecordStateDelay = base::TimeDelta::FromSeconds(15); // Returns the plugin preferences corresponding for this user, if available. // If multiple user profiles are loaded, returns the preferences corresponding @@ -303,7 +303,7 @@ DCHECK(IsPluginProcess(stats.process_type)); } stats.loading_errors++; - RecordCurrentStateWithDelay(kRecordStateDelayMs); + RecordCurrentStateWithDelay(); } void PluginMetricsProvider::SetPluginsForTesting( @@ -343,14 +343,14 @@ void PluginMetricsProvider::BrowserChildProcessHostConnected( const content::ChildProcessData& data) { GetChildProcessStats(data).process_launches++; - RecordCurrentStateWithDelay(kRecordStateDelayMs); + RecordCurrentStateWithDelay(); } void PluginMetricsProvider::BrowserChildProcessCrashed( const content::ChildProcessData& data, const content::ChildProcessTerminationInfo& info) { GetChildProcessStats(data).process_crashes++; - RecordCurrentStateWithDelay(kRecordStateDelayMs); + RecordCurrentStateWithDelay(); } void PluginMetricsProvider::BrowserChildProcessKilled( @@ -360,10 +360,10 @@ // actual crashes, which is treated as a kill rather than a crash by // base::GetTerminationStatus GetChildProcessStats(data).process_crashes++; - RecordCurrentStateWithDelay(kRecordStateDelayMs); + RecordCurrentStateWithDelay(); } -bool PluginMetricsProvider::RecordCurrentStateWithDelay(int delay_sec) { +bool PluginMetricsProvider::RecordCurrentStateWithDelay() { if (weak_ptr_factory_.HasWeakPtrs()) return false; @@ -371,7 +371,7 @@ FROM_HERE, base::BindOnce(&PluginMetricsProvider::RecordCurrentState, weak_ptr_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(delay_sec)); + kRecordStateDelay); return true; } @@ -383,3 +383,8 @@ RecordCurrentState(); return true; } + +// static +base::TimeDelta PluginMetricsProvider::GetRecordStateDelay() { + return kRecordStateDelay; +}
diff --git a/chrome/browser/metrics/plugin_metrics_provider.h b/chrome/browser/metrics/plugin_metrics_provider.h index 7f8986c..a8359c81 100644 --- a/chrome/browser/metrics/plugin_metrics_provider.h +++ b/chrome/browser/metrics/plugin_metrics_provider.h
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" +#include "base/time/time.h" #include "components/metrics/metrics_provider.h" #include "content/public/browser/browser_child_process_observer.h" @@ -76,15 +77,6 @@ // Saves plugin information to local state. void RecordCurrentState(); - // Posts a delayed task for RecordCurrentState. Returns true if new task is - // posted and false if there was one already waiting for execution. - // The param delay_sec is for unit tests. - bool RecordCurrentStateWithDelay(int delay_ms); - - // If a delayed RecordCurrnetState task exists then cancels it, calls - // RecordCurrentState immediately and returns true. Otherwise returns false. - bool RecordCurrentStateIfPending(); - // content::BrowserChildProcessObserver: void BrowserChildProcessHostConnected( const content::ChildProcessData& data) override; @@ -95,6 +87,17 @@ const content::ChildProcessData& data, const content::ChildProcessTerminationInfo& info) override; + // Posts a delayed task for RecordCurrentState. Returns true if new task is + // posted and false if there was one already waiting for execution. + bool RecordCurrentStateWithDelay(); + + // If a delayed RecordCurrnetState task exists then cancels it, calls + // RecordCurrentState immediately and returns true. Otherwise returns false. + bool RecordCurrentStateIfPending(); + + // Records the delay used internally by RecordCurrentStateWithDelay(). + static base::TimeDelta GetRecordStateDelay(); + PrefService* local_state_; // The list of plugins which was retrieved on the file thread.
diff --git a/chrome/browser/metrics/plugin_metrics_provider_unittest.cc b/chrome/browser/metrics/plugin_metrics_provider_unittest.cc index 259fa4b..6475cbf 100644 --- a/chrome/browser/metrics/plugin_metrics_provider_unittest.cc +++ b/chrome/browser/metrics/plugin_metrics_provider_unittest.cc
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_task_environment.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" @@ -117,22 +118,23 @@ } TEST_F(PluginMetricsProviderTest, RecordCurrentStateWithDelay) { - content::TestBrowserThreadBundle thread_bundle; + content::TestBrowserThreadBundle thread_bundle( + base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME); PluginMetricsProvider provider(prefs()); - int delay_ms = 10; - EXPECT_TRUE(provider.RecordCurrentStateWithDelay(delay_ms)); - EXPECT_FALSE(provider.RecordCurrentStateWithDelay(delay_ms)); + EXPECT_TRUE(provider.RecordCurrentStateWithDelay()); + EXPECT_FALSE(provider.RecordCurrentStateWithDelay()); - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(delay_ms)); + thread_bundle.FastForwardBy(PluginMetricsProvider::GetRecordStateDelay()); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(provider.RecordCurrentStateWithDelay(delay_ms)); + EXPECT_TRUE(provider.RecordCurrentStateWithDelay()); } TEST_F(PluginMetricsProviderTest, RecordCurrentStateIfPending) { - content::TestBrowserThreadBundle thread_bundle; + content::TestBrowserThreadBundle thread_bundle( + base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME); PluginMetricsProvider provider(prefs()); @@ -141,13 +143,12 @@ // After delayed task is posted RecordCurrentStateIfPending should return // true. - int delay_ms = 100000; - EXPECT_TRUE(provider.RecordCurrentStateWithDelay(delay_ms)); + EXPECT_TRUE(provider.RecordCurrentStateWithDelay()); EXPECT_TRUE(provider.RecordCurrentStateIfPending()); // If RecordCurrentStateIfPending was successful then we should be able to // post a new delayed task. - EXPECT_TRUE(provider.RecordCurrentStateWithDelay(delay_ms)); + EXPECT_TRUE(provider.RecordCurrentStateWithDelay()); } TEST_F(PluginMetricsProviderTest, ProvideStabilityMetricsWhenPendingTask) {
diff --git a/chrome/browser/navigation_predictor/navigation_predictor.cc b/chrome/browser/navigation_predictor/navigation_predictor.cc index 186c55a..d7dbad5 100644 --- a/chrome/browser/navigation_predictor/navigation_predictor.cc +++ b/chrome/browser/navigation_predictor/navigation_predictor.cc
@@ -86,35 +86,35 @@ : browser_context_( render_frame_host->GetSiteInstance()->GetBrowserContext()), ratio_area_scale_(base::GetFieldTrialParamByFeatureAsInt( - blink::features::kRecordAnchorMetricsVisible, + blink::features::kNavigationPredictor, "ratio_area_scale", 100)), is_in_iframe_scale_(base::GetFieldTrialParamByFeatureAsInt( - blink::features::kRecordAnchorMetricsVisible, + blink::features::kNavigationPredictor, "is_in_iframe_scale", 0)), is_same_host_scale_(base::GetFieldTrialParamByFeatureAsInt( - blink::features::kRecordAnchorMetricsVisible, + blink::features::kNavigationPredictor, "is_same_host_scale", 100)), contains_image_scale_(base::GetFieldTrialParamByFeatureAsInt( - blink::features::kRecordAnchorMetricsVisible, + blink::features::kNavigationPredictor, "contains_image_scale", 50)), is_url_incremented_scale_(base::GetFieldTrialParamByFeatureAsInt( - blink::features::kRecordAnchorMetricsVisible, + blink::features::kNavigationPredictor, "is_url_incremented_scale", 100)), source_engagement_score_scale_(base::GetFieldTrialParamByFeatureAsInt( - blink::features::kRecordAnchorMetricsVisible, + blink::features::kNavigationPredictor, "source_engagement_score_scale", 100)), target_engagement_score_scale_(base::GetFieldTrialParamByFeatureAsInt( - blink::features::kRecordAnchorMetricsVisible, + blink::features::kNavigationPredictor, "target_engagement_score_scale", 100)), area_rank_scale_(base::GetFieldTrialParamByFeatureAsInt( - blink::features::kRecordAnchorMetricsVisible, + blink::features::kNavigationPredictor, "area_rank_scale", 100)), sum_scales_(ratio_area_scale_ + is_in_iframe_scale_ + @@ -123,16 +123,16 @@ target_engagement_score_scale_ + area_rank_scale_), is_low_end_device_(base::SysInfo::IsLowEndDevice()), prefetch_url_score_threshold_(base::GetFieldTrialParamByFeatureAsInt( - blink::features::kRecordAnchorMetricsVisible, + blink::features::kNavigationPredictor, "prefetch_url_score_threshold", 0)), preconnect_origin_score_threshold_(base::GetFieldTrialParamByFeatureAsInt( - blink::features::kRecordAnchorMetricsVisible, + blink::features::kNavigationPredictor, "preconnect_origin_score_threshold", 0)), same_origin_preconnecting_allowed_( base::GetFieldTrialParamByFeatureAsBool( - blink::features::kRecordAnchorMetricsVisible, + blink::features::kNavigationPredictor, "same_origin_preconnecting_allowed", false)) #ifdef OS_ANDROID @@ -169,10 +169,7 @@ void NavigationPredictor::Create( blink::mojom::AnchorElementMetricsHostRequest request, content::RenderFrameHost* render_frame_host) { - DCHECK(base::FeatureList::IsEnabled( - blink::features::kRecordAnchorMetricsClicked)); - DCHECK(base::FeatureList::IsEnabled( - blink::features::kRecordAnchorMetricsVisible)); + DCHECK(base::FeatureList::IsEnabled(blink::features::kNavigationPredictor)); // Only valid for the main frame. if (render_frame_host->GetParent()) @@ -346,8 +343,7 @@ void NavigationPredictor::ReportAnchorElementMetricsOnClick( blink::mojom::AnchorElementMetricsPtr metrics) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(base::FeatureList::IsEnabled( - blink::features::kRecordAnchorMetricsClicked)); + DCHECK(base::FeatureList::IsEnabled(blink::features::kNavigationPredictor)); if (browser_context_->IsOffTheRecord()) return; @@ -556,8 +552,7 @@ void NavigationPredictor::ReportAnchorElementMetricsOnLoad( std::vector<blink::mojom::AnchorElementMetricsPtr> metrics) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(base::FeatureList::IsEnabled( - blink::features::kRecordAnchorMetricsVisible)); + DCHECK(base::FeatureList::IsEnabled(blink::features::kNavigationPredictor)); // Each document should only report metrics once when page is loaded. DCHECK(navigation_scores_map_.empty());
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc index aa3c4753..9aae846 100644 --- a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc +++ b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
@@ -54,8 +54,7 @@ NavigationPredictorBrowserTest() : subresource_filter::SubresourceFilterBrowserTest() { const std::vector<base::Feature> features = { - blink::features::kRecordAnchorMetricsVisible, - blink::features::kRecordAnchorMetricsClicked}; + blink::features::kNavigationPredictor}; feature_list_.InitWithFeatures(features, {}); } @@ -348,7 +347,7 @@ base::test::ScopedFeatureList feature_list; parameters["same_origin_preconnecting_allowed"] = "true"; feature_list.InitAndEnableFeatureWithParameters( - blink::features::kRecordAnchorMetricsVisible, parameters); + blink::features::kNavigationPredictor, parameters); base::HistogramTester histogram_tester;
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc b/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc index 8ca5256..55e591fb 100644 --- a/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc +++ b/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc
@@ -29,8 +29,7 @@ : NavigationPredictor(render_frame_host), binding_(this) { binding_.Bind(std::move(request)); const std::vector<base::Feature> features = { - blink::features::kRecordAnchorMetricsVisible, - blink::features::kRecordAnchorMetricsClicked}; + blink::features::kNavigationPredictor}; feature_list_.InitWithFeatures(features, {}); } @@ -123,7 +122,7 @@ base::IntToString(prefetch_url_score_threshold.value()); } scoped_feature_list.InitAndEnableFeatureWithParameters( - blink::features::kRecordAnchorMetricsVisible, params); + blink::features::kNavigationPredictor, params); } blink::mojom::AnchorElementMetricsHostPtr predictor_service_;
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc index c425614..543a638 100644 --- a/chrome/browser/net/profile_network_context_service.cc +++ b/chrome/browser/net/profile_network_context_service.cc
@@ -11,6 +11,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" +#include "base/metrics/histogram_macros.h" #include "base/task/post_task.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" @@ -77,6 +78,15 @@ return net::HttpUtil::GenerateAcceptLanguageHeader(accept_languages_str); } +void DeleteChannelIDFiles(base::FilePath channel_id_path) { + UMA_HISTOGRAM_BOOLEAN("DomainBoundCerts.DBExists", + base::PathExists(channel_id_path)); + base::DeleteFile(channel_id_path, false); + base::DeleteFile( + base::FilePath(channel_id_path.value() + FILE_PATH_LITERAL("-journal")), + false); +} + } // namespace ProfileNetworkContextService::ProfileNetworkContextService(Profile* profile) @@ -413,9 +423,14 @@ cookie_path = cookie_path.Append(chrome::kCookieFilename); network_context_params->cookie_path = cookie_path; - base::FilePath channel_id_path = path; - channel_id_path = channel_id_path.Append(chrome::kChannelIDFilename); - network_context_params->channel_id_path = channel_id_path; + // TODO(nharper): Remove the following when no longer needed - see + // crbug.com/903642. + base::PostTaskWithTraits( + FROM_HERE, + {base::TaskPriority::BEST_EFFORT, base::MayBlock(), + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce(DeleteChannelIDFiles, + path.Append(chrome::kChannelIDFilename))); if (relative_partition_path.empty()) { // This is the main partition. network_context_params->restore_old_session_cookies =
diff --git a/chrome/browser/notifications/notification_channels_provider_android.cc b/chrome/browser/notifications/notification_channels_provider_android.cc index 8ef20f7e..09414a6b 100644 --- a/chrome/browser/notifications/notification_channels_provider_android.cc +++ b/chrome/browser/notifications/notification_channels_provider_android.cc
@@ -223,9 +223,8 @@ while (it && it->HasNext()) { content_settings::Rule rule = it->Next(); - rules.push_back(std::move(rule)); - CreateChannelForRule(rule); + rules.push_back(std::move(rule)); } }
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc index 9ad39d1..2b8ca307 100644 --- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc
@@ -718,6 +718,54 @@ 0); } +class RemoteFrameNavigationBrowserTest + : public AdsPageLoadMetricsObserverResourceBrowserTest { + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitchASCII("enable-blink-features", + "BlockingDownloadsInSandbox"); + } +}; + +IN_PROC_BROWSER_TEST_F(RemoteFrameNavigationBrowserTest, + DownloadsBlockedInSandbox) { + embedded_test_server()->ServeFilesFromSourceDirectory( + "chrome/test/data/ad_tagging"); + content::SetupCrossSiteRedirector(embedded_test_server()); + ASSERT_TRUE(embedded_test_server()->Start()); + + base::HistogramTester histogram_tester; + std::string origin1 = "foo.com"; + std::string origin2 = "bar.com"; + GURL tab1_url = + embedded_test_server()->GetURL(origin1, "/frame_factory.html"); + + auto subframe_navigation_waiter = + std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>( + web_contents()); + subframe_navigation_waiter->AddSubframeNavigationExpectation(2); + + ui_test_utils::NavigateToURL(browser(), tab1_url); + + std::string subframe_url = + embedded_test_server()->GetURL(origin2, "/frame_factory.html").spec(); + content::TestNavigationObserver new_subframe_waiter(web_contents()); + std::string script = + base::StringPrintf("createFrame('%s','test','');", subframe_url.c_str()); + web_contents()->GetMainFrame()->ExecuteJavaScriptForTests( + base::ASCIIToUTF16(script)); + new_subframe_waiter.Wait(); + + GURL dld_url = embedded_test_server()->GetURL(origin1, "/allow.zip"); + EXPECT_TRUE(ExecuteScriptWithoutUserGesture( + web_contents(), + "document.getElementById('test').src = \"" + dld_url.spec() + "\";")); + + subframe_navigation_waiter->Wait(); + SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); + histogram_tester.ExpectTotalCount("Download.Subframe.SandboxOriginAdGesture", + 0 /* expected_count */); +} + class MainFrameDownloadFlagsBrowserTest : public AdsPageLoadMetricsObserverResourceBrowserTest, public ::testing::WithParamInterface< @@ -941,6 +989,10 @@ browser()->tab_strip_model()->GetActiveWebContents(); std::unique_ptr<AdsPageLoadMetricsTestWaiter> waiter; + if (origin == Origin::kNavigation) { + waiter = std::make_unique<AdsPageLoadMetricsTestWaiter>(contents); + waiter->AddSubframeNavigationExpectation(2); + } if (expected_download && is_ad_frame) { if (!waiter) waiter = std::make_unique<AdsPageLoadMetricsTestWaiter>(contents);
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc index e4be30206..32e1739 100644 --- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -99,13 +99,13 @@ const char kHistogramInteractiveToInteractiveDetection[] = "PageLoad.Internal.InteractiveToInteractiveDetection"; const char kHistogramFirstInputDelay[] = - "PageLoad.InteractiveTiming.FirstInputDelay"; + "PageLoad.InteractiveTiming.FirstInputDelay2"; const char kHistogramFirstInputTimestamp[] = - "PageLoad.InteractiveTiming.FirstInputTimestamp"; + "PageLoad.InteractiveTiming.FirstInputTimestamp2"; const char kHistogramLongestInputDelay[] = - "PageLoad.InteractiveTiming.LongestInputDelay"; + "PageLoad.InteractiveTiming.LongestInputDelay2"; const char kHistogramLongestInputTimestamp[] = - "PageLoad.InteractiveTiming.LongestInputTimestamp"; + "PageLoad.InteractiveTiming.LongestInputTimestamp2"; const char kHistogramParseStartToFirstMeaningfulPaint[] = "PageLoad.Experimental.PaintTiming.ParseStartToFirstMeaningfulPaint"; const char kHistogramParseStartToFirstContentfulPaint[] =
diff --git a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc index 7d12f8c7..66ae720 100644 --- a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc
@@ -38,7 +38,7 @@ const char kHistogramFromGWSParseStart[] = "PageLoad.Clients.FromGoogleSearch.ParseTiming.NavigationToParseStart"; const char kHistogramFromGWSFirstInputDelay[] = - "PageLoad.Clients.FromGoogleSearch.InteractiveTiming.FirstInputDelay"; + "PageLoad.Clients.FromGoogleSearch.InteractiveTiming.FirstInputDelay2"; const char kHistogramFromGWSAbortNewNavigationBeforeCommit[] = "PageLoad.Clients.FromGoogleSearch.Experimental.AbortTiming.NewNavigation."
diff --git a/chrome/browser/page_load_metrics/observers/histogram_suffixes.cc b/chrome/browser/page_load_metrics/observers/histogram_suffixes.cc index 3daeb84..6cd0a21 100644 --- a/chrome/browser/page_load_metrics/observers/histogram_suffixes.cc +++ b/chrome/browser/page_load_metrics/observers/histogram_suffixes.cc
@@ -15,7 +15,7 @@ const char kHistogramFirstImagePaintSuffix[] = "PaintTiming.NavigationToFirstImagePaint"; const char kHistogramFirstInputDelaySuffix[] = - "InteractiveTiming.FirstInputDelay"; + "InteractiveTiming.FirstInputDelay2"; const char kHistogramFirstLayoutSuffix[] = "DocumentTiming.NavigationToFirstLayout"; const char kHistogramFirstMeaningfulPaintSuffix[] =
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc index f3f0c9f..76f67e5c 100644 --- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
@@ -29,7 +29,7 @@ "PageLoad.Clients.ServiceWorker2.ParseTiming.NavigationToParseStart." "Background"; const char kHistogramServiceWorkerFirstInputDelay[] = - "PageLoad.Clients.ServiceWorker2.InteractiveTiming.FirstInputDelay"; + "PageLoad.Clients.ServiceWorker2.InteractiveTiming.FirstInputDelay2"; const char kHistogramServiceWorkerFirstPaint[] = "PageLoad.Clients.ServiceWorker2.PaintTiming.NavigationToFirstPaint"; const char kHistogramServiceWorkerFirstContentfulPaint[] =
diff --git a/chrome/browser/page_load_metrics/observers/signed_exchange_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/signed_exchange_page_load_metrics_observer.cc index 76efa5a62..b9afac3 100644 --- a/chrome/browser/page_load_metrics/observers/signed_exchange_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/signed_exchange_page_load_metrics_observer.cc
@@ -15,7 +15,7 @@ constexpr char kHistogramSignedExchangeParseStart[] = HISTOGRAM_PREFIX "ParseTiming.NavigationToParseStart"; constexpr char kHistogramSignedExchangeFirstInputDelay[] = - HISTOGRAM_PREFIX "InteractiveTiming.FirstInputDelay"; + HISTOGRAM_PREFIX "InteractiveTiming.FirstInputDelay2"; constexpr char kHistogramSignedExchangeFirstPaint[] = HISTOGRAM_PREFIX "PaintTiming.NavigationToFirstPaint"; constexpr char kHistogramSignedExchangeFirstContentfulPaint[] =
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc index 88e3eb3..74d5ee8 100644 --- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -248,26 +248,26 @@ if (timing.interactive_timing->first_input_delay) { base::TimeDelta first_input_delay = timing.interactive_timing->first_input_delay.value(); - builder.SetInteractiveTiming_FirstInputDelay( + builder.SetInteractiveTiming_FirstInputDelay2( first_input_delay.InMilliseconds()); } if (timing.interactive_timing->first_input_timestamp) { base::TimeDelta first_input_timestamp = timing.interactive_timing->first_input_timestamp.value(); - builder.SetInteractiveTiming_FirstInputTimestamp( + builder.SetInteractiveTiming_FirstInputTimestamp2( first_input_timestamp.InMilliseconds()); } if (timing.interactive_timing->longest_input_delay) { base::TimeDelta longest_input_delay = timing.interactive_timing->longest_input_delay.value(); - builder.SetInteractiveTiming_LongestInputDelay( + builder.SetInteractiveTiming_LongestInputDelay2( longest_input_delay.InMilliseconds()); } if (timing.interactive_timing->longest_input_timestamp) { base::TimeDelta longest_input_timestamp = timing.interactive_timing->longest_input_timestamp.value(); - builder.SetInteractiveTiming_LongestInputTimestamp( + builder.SetInteractiveTiming_LongestInputTimestamp2( longest_input_timestamp.InMilliseconds()); }
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc index 79f7d04..730676e 100644 --- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -638,9 +638,9 @@ test_ukm_recorder().ExpectEntrySourceHasUrl(kv.second.get(), GURL(kTestUrl1)); test_ukm_recorder().ExpectEntryMetric( - kv.second.get(), PageLoad::kInteractiveTiming_FirstInputDelayName, 50); + kv.second.get(), PageLoad::kInteractiveTiming_FirstInputDelay2Name, 50); test_ukm_recorder().ExpectEntryMetric( - kv.second.get(), PageLoad::kInteractiveTiming_FirstInputTimestampName, + kv.second.get(), PageLoad::kInteractiveTiming_FirstInputTimestamp2Name, 712); } } @@ -669,11 +669,11 @@ test_ukm_recorder().ExpectEntrySourceHasUrl(kv.second.get(), GURL(kTestUrl1)); test_ukm_recorder().ExpectEntryMetric( - kv.second.get(), PageLoad::kInteractiveTiming_LongestInputDelayName, + kv.second.get(), PageLoad::kInteractiveTiming_LongestInputDelay2Name, 50); test_ukm_recorder().ExpectEntryMetric( - kv.second.get(), PageLoad::kInteractiveTiming_LongestInputTimestampName, - 712); + kv.second.get(), + PageLoad::kInteractiveTiming_LongestInputTimestamp2Name, 712); } }
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc b/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc index ee0ebc2..9943ed9 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.cc
@@ -46,6 +46,11 @@ } } +void PageLoadMetricsTestWaiter::AddSubframeNavigationExpectation( + size_t expected_subframe_navigations) { + expected_subframe_navigations_ = expected_subframe_navigations; +} + void PageLoadMetricsTestWaiter::AddMinimumCompleteResourcesExpectation( int expected_minimum_complete_resources) { expected_minimum_complete_resources_ = expected_minimum_complete_resources; @@ -155,6 +160,17 @@ run_loop_->Quit(); } +void PageLoadMetricsTestWaiter::OnDidFinishSubFrameNavigation( + content::NavigationHandle* navigation_handle) { + if (SubframeNavigationExpectationsSatisfied()) + return; + + ++observed_subframe_navigations_; + + if (ExpectationsSatisfied() && run_loop_) + run_loop_->Quit(); +} + bool PageLoadMetricsTestWaiter::IsPageLevelField(TimingField field) { switch (field) { case TimingField::kFirstPaint: @@ -229,10 +245,16 @@ .none(); } +bool PageLoadMetricsTestWaiter::SubframeNavigationExpectationsSatisfied() + const { + return observed_subframe_navigations_ >= expected_subframe_navigations_; +} + bool PageLoadMetricsTestWaiter::ExpectationsSatisfied() const { return subframe_expected_fields_.Empty() && page_expected_fields_.Empty() && ResourceUseExpectationsSatisfied() && - WebFeaturesExpectationsSatisfied(); + WebFeaturesExpectationsSatisfied() && + SubframeNavigationExpectationsSatisfied(); } PageLoadMetricsTestWaiter::WaiterMetricsObserver::~WaiterMetricsObserver() {} @@ -273,4 +295,11 @@ waiter_->OnFeaturesUsageObserved(nullptr, features, extra_info); } +void PageLoadMetricsTestWaiter::WaiterMetricsObserver:: + OnDidFinishSubFrameNavigation( + content::NavigationHandle* navigation_handle) { + if (waiter_) + waiter_->OnDidFinishSubFrameNavigation(navigation_handle); +} + } // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.h b/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.h index a41de23..6de54ef 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.h +++ b/chrome/browser/page_load_metrics/page_load_metrics_test_waiter.h
@@ -45,6 +45,9 @@ // Add a single WebFeature expectation. void AddWebFeatureExpectation(blink::mojom::WebFeature web_feature); + // Add number of subframe navigations expectation. + void AddSubframeNavigationExpectation(size_t expected_subframe_navigations); + // Add a minimum completed resource expectation. void AddMinimumCompleteResourcesExpectation( int expected_minimum_complete_resources); @@ -105,6 +108,9 @@ const page_load_metrics::mojom::PageLoadFeatures&, const page_load_metrics::PageLoadExtraInfo& extra_info) override; + void OnDidFinishSubFrameNavigation( + content::NavigationHandle* navigation_handle) override; + private: const base::WeakPtr<PageLoadMetricsTestWaiter> waiter_; }; @@ -173,6 +179,9 @@ const mojom::PageLoadFeatures& features, const PageLoadExtraInfo& extra_info); + void OnDidFinishSubFrameNavigation( + content::NavigationHandle* navigation_handle); + void OnTrackerCreated(page_load_metrics::PageLoadTracker* tracker) override; void OnCommit(page_load_metrics::PageLoadTracker* tracker) override; @@ -181,16 +190,20 @@ bool WebFeaturesExpectationsSatisfied() const; + bool SubframeNavigationExpectationsSatisfied() const; + std::unique_ptr<base::RunLoop> run_loop_; TimingFieldBitSet page_expected_fields_; TimingFieldBitSet subframe_expected_fields_; std::bitset<static_cast<size_t>(blink::mojom::WebFeature::kNumberOfFeatures)> expected_web_features_; + size_t expected_subframe_navigations_ = 0; TimingFieldBitSet observed_page_fields_; std::bitset<static_cast<size_t>(blink::mojom::WebFeature::kNumberOfFeatures)> observed_web_features_; + size_t observed_subframe_navigations_ = 0; int current_complete_resources_ = 0; int64_t current_network_bytes_ = 0;
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index 6072e93..ff3b34a 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -169,7 +169,7 @@ #endif driver_factory_(nullptr), content_credential_manager_(this), - password_manager_client_bindings_(web_contents, this), + password_generation_driver_bindings_(web_contents, this), password_manager_driver_bindings_(web_contents, this), observer_(nullptr), credentials_filter_( @@ -366,7 +366,11 @@ void ChromePasswordManagerClient::GeneratePassword() { password_manager::ContentPasswordManagerDriver* driver = driver_factory_->GetDriverForFrame(web_contents()->GetFocusedFrame()); - driver->GeneratePassword(); + // Using unretained pointer is safe because |this| outlives + // ContentPasswordManagerDriver that holds the connection. + driver->GeneratePassword(base::BindOnce( + &ChromePasswordManagerClient::ShowManualPasswordGenerationPopup, + base::Unretained(this), base::AsWeakPtr(driver))); } void ChromePasswordManagerClient::NotifyUserAutoSignin( @@ -646,7 +650,7 @@ autofill::password_generation::PasswordGenerationUIData>& ui_data) { if (ui_data && !password_manager::bad_message::CheckChildProcessSecurityPolicy( - password_manager_client_bindings_.GetCurrentTargetFrame(), + password_generation_driver_bindings_.GetCurrentTargetFrame(), ui_data->password_form, BadMessageReason:: CPMD_BAD_ORIGIN_AUTOMATIC_GENERATION_STATUS_CHANGED)) @@ -657,7 +661,7 @@ if (available) { password_manager::PasswordManagerDriver* driver = driver_factory_->GetDriverForFrame( - password_manager_client_bindings_.GetCurrentTargetFrame()); + password_generation_driver_bindings_.GetCurrentTargetFrame()); DCHECK(driver); password_manager_.SetGenerationElementAndReasonForForm( driver, ui_data.value().password_form, @@ -667,7 +671,7 @@ ->OnAutomaticGenerationStatusChanged(true, ui_data, driver->AsWeakPtr()); gfx::RectF element_bounds_in_screen_space = TransformToRootCoordinates( - password_manager_client_bindings_.GetCurrentTargetFrame(), + password_generation_driver_bindings_.GetCurrentTargetFrame(), ui_data.value().bounds); driver->GetPasswordAutofillManager()->MaybeShowPasswordSuggestions( element_bounds_in_screen_space, ui_data.value().text_direction); @@ -682,32 +686,24 @@ } #else if (available) { - ShowPasswordGenerationPopup(ui_data.value(), + password_manager::ContentPasswordManagerDriver* driver = + driver_factory_->GetDriverForFrame( + password_generation_driver_bindings_.GetCurrentTargetFrame()); + ShowPasswordGenerationPopup(driver, ui_data.value(), false /* is_manually_triggered */); } #endif // defined(OS_ANDROID) } -void ChromePasswordManagerClient::ShowManualPasswordGenerationPopup( - const autofill::password_generation::PasswordGenerationUIData& ui_data) { - if (!password_manager::bad_message::CheckChildProcessSecurityPolicy( - password_manager_client_bindings_.GetCurrentTargetFrame(), - ui_data.password_form, - BadMessageReason:: - CPMD_BAD_ORIGIN_SHOW_MANUAL_PASSWORD_GENERATION_POPUP)) - return; - ShowPasswordGenerationPopup(ui_data, true /* is_manually_triggered */); -} - void ChromePasswordManagerClient::ShowPasswordEditingPopup( const gfx::RectF& bounds, const autofill::PasswordForm& form) { if (!password_manager::bad_message::CheckChildProcessSecurityPolicy( - password_manager_client_bindings_.GetCurrentTargetFrame(), form, + password_generation_driver_bindings_.GetCurrentTargetFrame(), form, BadMessageReason::CPMD_BAD_ORIGIN_SHOW_PASSWORD_EDITING_POPUP)) return; auto* driver = driver_factory_->GetDriverForFrame( - password_manager_client_bindings_.GetCurrentTargetFrame()); + password_generation_driver_bindings_.GetCurrentTargetFrame()); DCHECK(driver); gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(TransformToRootCoordinates( @@ -727,7 +723,7 @@ void ChromePasswordManagerClient::GenerationAvailableForForm( const autofill::PasswordForm& form) { if (!password_manager::bad_message::CheckChildProcessSecurityPolicy( - password_manager_client_bindings_.GetCurrentTargetFrame(), form, + password_generation_driver_bindings_.GetCurrentTargetFrame(), form, BadMessageReason::CPMD_BAD_ORIGIN_GENERATION_AVAILABLE_FOR_FORM)) return; password_manager_.GenerationAvailableForForm(form); @@ -742,7 +738,7 @@ void ChromePasswordManagerClient::PresaveGeneratedPassword( const autofill::PasswordForm& password_form) { if (!password_manager::bad_message::CheckChildProcessSecurityPolicy( - password_manager_client_bindings_.GetCurrentTargetFrame(), + password_generation_driver_bindings_.GetCurrentTargetFrame(), password_form, BadMessageReason::CPMD_BAD_ORIGIN_PRESAVE_GENERATED_PASSWORD)) return; @@ -758,7 +754,7 @@ void ChromePasswordManagerClient::PasswordNoLongerGenerated( const autofill::PasswordForm& password_form) { if (!password_manager::bad_message::CheckChildProcessSecurityPolicy( - password_manager_client_bindings_.GetCurrentTargetFrame(), + password_generation_driver_bindings_.GetCurrentTargetFrame(), password_form, BadMessageReason::CPMD_BAD_ORIGIN_PASSWORD_NO_LONGER_GENERATED)) return; @@ -1030,15 +1026,29 @@ #endif } +void ChromePasswordManagerClient::ShowManualPasswordGenerationPopup( + base::WeakPtr<password_manager::ContentPasswordManagerDriver> driver, + const base::Optional< + autofill::password_generation::PasswordGenerationUIData>& ui_data) { + if (!ui_data || !driver) + return; + // Check the data because it's a Mojo callback and the input isn't trusted. + if (!password_manager::bad_message::CheckChildProcessSecurityPolicy( + driver->render_frame_host(), ui_data->password_form, + BadMessageReason:: + CPMD_BAD_ORIGIN_SHOW_MANUAL_PASSWORD_GENERATION_POPUP)) + return; + ShowPasswordGenerationPopup(driver.get(), *ui_data, + true /* is_manually_triggered */); +} + void ChromePasswordManagerClient::ShowPasswordGenerationPopup( + password_manager::ContentPasswordManagerDriver* driver, const autofill::password_generation::PasswordGenerationUIData& ui_data, bool is_manually_triggered) { - auto* driver = driver_factory_->GetDriverForFrame( - password_manager_client_bindings_.GetCurrentTargetFrame()); DCHECK(driver); - gfx::RectF element_bounds_in_top_frame_space = TransformToRootCoordinates( - password_manager_client_bindings_.GetCurrentTargetFrame(), - ui_data.bounds); + gfx::RectF element_bounds_in_top_frame_space = + TransformToRootCoordinates(driver->render_frame_host(), ui_data.bounds); if (!is_manually_triggered && driver->GetPasswordAutofillManager() ->MaybeShowPasswordSuggestionsWithGeneration(
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h index ab42759..ee5598a 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.h +++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -51,7 +51,7 @@ public content::WebContentsObserver, public content::WebContentsUserData<ChromePasswordManagerClient>, public autofill::mojom::PasswordManagerDriver, - public autofill::mojom::PasswordManagerClient, + public autofill::mojom::PasswordGenerationDriver, public content::RenderWidgetHost::InputEventObserver { public: ~ChromePasswordManagerClient() override; @@ -117,15 +117,12 @@ void NavigateToManagePasswordsPage( password_manager::ManagePasswordsReferrer referrer) override; - // autofill::mojom::PasswordManagerClient overrides. + // autofill::mojom::PasswordGenerationDriver overrides. void AutomaticGenerationStatusChanged( bool available, const base::Optional< autofill::password_generation::PasswordGenerationUIData>& ui_data) override; - void ShowManualPasswordGenerationPopup( - const autofill::password_generation::PasswordGenerationUIData& ui_data) - override; void ShowPasswordEditingPopup(const gfx::RectF& bounds, const autofill::PasswordForm& form) override; void GenerationAvailableForForm(const autofill::PasswordForm& form) override; @@ -239,7 +236,15 @@ void PromptUserToEnableAutosignin() override; password_manager::PasswordManager* GetPasswordManager() override; + // |ui_data| is empty in case the renderer failed to start manual generation. + // In this case nothing should happen. + void ShowManualPasswordGenerationPopup( + base::WeakPtr<password_manager::ContentPasswordManagerDriver> driver, + const base::Optional< + autofill::password_generation::PasswordGenerationUIData>& ui_data); + void ShowPasswordGenerationPopup( + password_manager::ContentPasswordManagerDriver* driver, const autofill::password_generation::PasswordGenerationUIData& ui_data, bool is_manually_triggered); @@ -264,8 +269,8 @@ // once main frame host was created. password_manager::ContentCredentialManager content_credential_manager_; - content::WebContentsFrameBindingSet<autofill::mojom::PasswordManagerClient> - password_manager_client_bindings_; + content::WebContentsFrameBindingSet<autofill::mojom::PasswordGenerationDriver> + password_generation_driver_bindings_; content::WebContentsFrameBindingSet<autofill::mojom::PasswordManagerDriver> password_manager_driver_bindings_;
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc index 6df51c1..92a2243 100644 --- a/chrome/browser/pdf/pdf_extension_test.cc +++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -633,13 +633,7 @@ RunTestsInFile("touch_handling_test.js", "test.pdf"); } -// Flaky on ASan/LSan bots: https://crbug.com/915555. -#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) -#define MAYBE_Elements DISABLED_Elements -#else -#define MAYBE_Elements Elements -#endif -IN_PROC_BROWSER_TEST_F(PDFExtensionTest, MAYBE_Elements) { +IN_PROC_BROWSER_TEST_F(PDFExtensionTest, Elements) { // Although this test file does not require a PDF to be loaded, loading the // elements without loading a PDF is difficult. RunTestsInFile("material_elements_test.js", "test.pdf");
diff --git a/chrome/browser/previews/previews_browsertest.cc b/chrome/browser/previews/previews_browsertest.cc index e9b4106..08848ae13 100644 --- a/chrome/browser/previews/previews_browsertest.cc +++ b/chrome/browser/previews/previews_browsertest.cc
@@ -120,6 +120,25 @@ const GURL& https_no_transform_url() const { return https_no_transform_url_; } const GURL& http_url() const { return http_url_; } const GURL& redirect_url() const { return redirect_url_; } + + // Triggers a navigation to |url| to prime the OptimizationGuide hints for the + // url's host and ensure that they have been loaded from the store (via + // histogram) prior to the navigation that tests functionality. + void LoadUrlHints(const GURL& url) { + base::HistogramTester histogram_tester; + + ui_test_utils::NavigateToURL(browser(), url); + + RetryForHistogramUntilCountReached( + &histogram_tester, + previews::kPreviewsOptimizationGuideOnLoadedHintResultHistogramString, + 1); + + // Reset state for any subsequent test. + noscript_css_requested_ = false; + noscript_js_requested_ = false; + } + bool noscript_css_requested() const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); return noscript_css_requested_; @@ -259,26 +278,35 @@ // script resource is not loaded. IN_PROC_BROWSER_TEST_F(PreviewsNoScriptBrowserTest, MAYBE_NoScriptPreviewsEnabled) { + GURL url = https_url(); + // Whitelist test URL for NoScript. - SetUpNoScriptWhitelist({https_url().host()}); + SetUpNoScriptWhitelist({url.host()}); + + LoadUrlHints(url); base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), https_url()); + ui_test_utils::NavigateToURL(browser(), url); // Verify loaded noscript tag triggered css resource but not js one. EXPECT_TRUE(noscript_css_requested()); EXPECT_FALSE(noscript_js_requested()); // Verify info bar presented via histogram check. - histogram_tester.ExpectUniqueSample("Previews.InfoBarAction.NoScript", 0, 1); + EXPECT_FALSE(histogram_tester.GetAllSamples("Previews.InfoBarAction.NoScript") + .empty()); } IN_PROC_BROWSER_TEST_F(PreviewsNoScriptBrowserTest, NoScriptPreviewsEnabledButHttpRequest) { - // Whitelist test URL for NoScript. - SetUpNoScriptWhitelist({http_url().host()}); + GURL url = http_url(); - ui_test_utils::NavigateToURL(browser(), http_url()); + // Whitelist test URL for NoScript. + SetUpNoScriptWhitelist({url.host()}); + + LoadUrlHints(url); + + ui_test_utils::NavigateToURL(browser(), url); // Verify loaded js resource but not css triggered by noscript tag. EXPECT_TRUE(noscript_js_requested()); @@ -296,11 +324,15 @@ #endif IN_PROC_BROWSER_TEST_F(PreviewsNoScriptBrowserTest, MAYBE_NoScriptPreviewsEnabledButNoTransformDirective) { + GURL url = https_no_transform_url(); + // Whitelist test URL for NoScript. - SetUpNoScriptWhitelist({https_no_transform_url().host()}); + SetUpNoScriptWhitelist({url.host()}); + + LoadUrlHints(url); base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), https_no_transform_url()); + ui_test_utils::NavigateToURL(browser(), url); // Verify loaded js resource but not css triggered by noscript tag. EXPECT_TRUE(noscript_js_requested()); @@ -312,18 +344,23 @@ IN_PROC_BROWSER_TEST_F(PreviewsNoScriptBrowserTest, MAYBE_NoScriptPreviewsEnabledHttpRedirectToHttps) { + GURL url = redirect_url(); + // Whitelist test URL for NoScript. - SetUpNoScriptWhitelist({redirect_url().host()}); + SetUpNoScriptWhitelist({url.host()}); + + LoadUrlHints(url); base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), redirect_url()); + ui_test_utils::NavigateToURL(browser(), url); // Verify loaded noscript tag triggered css resource but not js one. EXPECT_TRUE(noscript_css_requested()); EXPECT_FALSE(noscript_js_requested()); // Verify info bar presented via histogram check. - histogram_tester.ExpectUniqueSample("Previews.InfoBarAction.NoScript", 0, 1); + EXPECT_FALSE(histogram_tester.GetAllSamples("Previews.InfoBarAction.NoScript") + .empty()); } // Flaky in all platforms except Android. See https://crbug.com/803626 for @@ -336,20 +373,24 @@ #endif IN_PROC_BROWSER_TEST_F(PreviewsNoScriptBrowserTest, MAYBE_NoScriptPreviewsRecordsOptOut) { + GURL url = redirect_url(); + // Whitelist test URL for NoScript. - SetUpNoScriptWhitelist({redirect_url().host()}); + SetUpNoScriptWhitelist({url.host()}); + + LoadUrlHints(url); base::HistogramTester histogram_tester; - // Navigate to a No Script Preview page. - ui_test_utils::NavigateToURL(browser(), redirect_url()); + // Navigate to a NoScript Preview page. + ui_test_utils::NavigateToURL(browser(), url); - // Terminate the previous page (non-opt out) and pull up a new No Script page. - ui_test_utils::NavigateToURL(browser(), redirect_url()); + // Terminate the previous page (non-opt out) and pull up a new NoScript page. + ui_test_utils::NavigateToURL(browser(), url); histogram_tester.ExpectUniqueSample("Previews.OptOut.UserOptedOut.NoScript", - 0, 1); + 0, 2); - // Opt out of the No Script Preview page. + // Opt out of the NoScript Preview page. PreviewsUITabHelper::FromWebContents( browser()->tab_strip_model()->GetActiveWebContents()) ->ReloadWithoutPreviews(); @@ -372,10 +413,14 @@ IN_PROC_BROWSER_TEST_F(PreviewsNoScriptBrowserTest, MAYBE_NoScriptPreviewsEnabledByWhitelist) { - // Whitelist test URL for NoScript. - SetUpNoScriptWhitelist({https_url().host()}); + GURL url = https_url(); - ui_test_utils::NavigateToURL(browser(), https_url()); + // Whitelist test URL for NoScript. + SetUpNoScriptWhitelist({url.host()}); + + LoadUrlHints(url); + + ui_test_utils::NavigateToURL(browser(), url); // Verify loaded noscript tag triggered css resource but not js one. EXPECT_TRUE(noscript_css_requested()); @@ -384,10 +429,14 @@ IN_PROC_BROWSER_TEST_F(PreviewsNoScriptBrowserTest, NoScriptPreviewsNotEnabledByWhitelist) { + GURL url = https_url(); + // Whitelist random site for NoScript. SetUpNoScriptWhitelist({"foo.com"}); - ui_test_utils::NavigateToURL(browser(), https_url()); + LoadUrlHints(url); + + ui_test_utils::NavigateToURL(browser(), url); // Verify loaded js resource but not css triggered by noscript tag. EXPECT_TRUE(noscript_js_requested());
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc index a217f65..01050cb 100644 --- a/chrome/browser/previews/previews_lite_page_browsertest.cc +++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -853,19 +853,6 @@ GetWebContents()->GetController().Reload(content::ReloadType::NORMAL, false); VerifyPreviewLoaded(); VerifyInfoStatus(previews::ServerLitePageStatus::kSuccess); - - // Set the ECT so that a preview won't be triggered on the reload. - g_browser_process->network_quality_tracker() - ->ReportEffectiveConnectionTypeForTesting( - net::EFFECTIVE_CONNECTION_TYPE_4G); - - GetWebContents()->GetController().Reload(content::ReloadType::NORMAL, false); - VerifyPreviewNotLoaded(); - - // Reset ECT for future tests. - g_browser_process->network_quality_tracker() - ->ReportEffectiveConnectionTypeForTesting( - net::EFFECTIVE_CONNECTION_TYPE_2G); } IN_PROC_BROWSER_TEST_F(PreviewsLitePageServerBrowserTest, @@ -874,20 +861,8 @@ scoped_feature_list.InitWithFeatures( {previews::features::kPreviewsDisallowedOnReloads}, {}); - // Set the ECT so that a preview won't be triggered. - // TODO(robertogden): Remove this and serve a preview when reloads work - // correctly. https://crbug.com/914547 - g_browser_process->network_quality_tracker() - ->ReportEffectiveConnectionTypeForTesting( - net::EFFECTIVE_CONNECTION_TYPE_4G); - ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess)); - VerifyPreviewNotLoaded(); - - // Set the ECT so that a preview should be triggered for non-reloads. - g_browser_process->network_quality_tracker() - ->ReportEffectiveConnectionTypeForTesting( - net::EFFECTIVE_CONNECTION_TYPE_2G); + VerifyPreviewLoaded(); GetWebContents()->GetController().Reload(content::ReloadType::NORMAL, false); VerifyPreviewNotLoaded();
diff --git a/chrome/browser/previews/previews_lite_page_decider.cc b/chrome/browser/previews/previews_lite_page_decider.cc index 1a34f32..15e7ddd 100644 --- a/chrome/browser/previews/previews_lite_page_decider.cc +++ b/chrome/browser/previews/previews_lite_page_decider.cc
@@ -212,8 +212,19 @@ if (!previews_data) return nullptr; + // If this navigation is reloading on a lite page, always create a navigation + // throttle. In this event, the navigation throttle will always cancel and + // restart the navigation to a non-preview page. This is important for the + // experiment that disables previews on reloads since it won't enable the + // previews state. + bool reload_load_original = + previews::ExtractOriginalURLFromLitePageRedirectURL(handle->GetURL(), + nullptr) && + handle->GetReloadType() != content::ReloadType::NONE; + if (previews_data->allowed_previews_state() & - content::LITE_PAGE_REDIRECT_ON) { + content::LITE_PAGE_REDIRECT_ON || + reload_load_original) { return std::make_unique<PreviewsLitePageNavigationThrottle>( handle, previews_service->previews_lite_page_decider()); }
diff --git a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc index 6a657df7..98e3f9b 100644 --- a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc +++ b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc
@@ -101,6 +101,7 @@ url_params.frame_tree_node_id = handle->GetFrameTreeNodeId(); url_params.user_gesture = handle->HasUserGesture(); url_params.started_from_context_menu = handle->WasStartedFromContextMenu(); + url_params.reload_type = handle->GetReloadType(); return url_params; } @@ -517,7 +518,8 @@ std::string original_url; if (previews::ExtractOriginalURLFromLitePageRedirectURL( navigation_handle()->GetURL(), &original_url) && - navigation_handle()->GetReloadType() == content::ReloadType::NORMAL) { + navigation_handle()->GetReloadType() != content::ReloadType::NONE && + !GetServerLitePageInfo()) { // Don't use |LoadAndBypass| because we might not want to bypass. WebContentsLifetimeHelper::CreateForWebContents( navigation_handle()->GetWebContents());
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc index a87693a..de5dc0c 100644 --- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc +++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
@@ -119,6 +119,20 @@ cmd->AppendSwitch(previews::switches::kIgnorePreviewsBlacklist); } + // Triggers a navigation to |url| to prime the OptimizationGuide hints for the + // url's host and ensure that they have been loaded from the store (via + // histogram) prior to the navigation that tests functionality. + void LoadUrlHints(const GURL& url) { + base::HistogramTester histogram_tester; + + ui_test_utils::NavigateToURL(browser(), url); + + RetryForHistogramUntilCountReached( + &histogram_tester, + previews::kPreviewsOptimizationGuideOnLoadedHintResultHistogramString, + 1); + } + void ProcessHintsComponent( const optimization_guide::HintsComponentInfo& component_info) { base::HistogramTester histogram_tester; @@ -314,15 +328,19 @@ IN_PROC_BROWSER_TEST_F( ResourceLoadingHintsBrowserTest, DISABLE_ON_WIN_MAC(ResourceLoadingHintsHttpsWhitelisted)) { - SetExpectedFooJpgRequest(false); - SetExpectedBarJpgRequest(true); + GURL url = https_url(); // Whitelist test URL for resource loading hints. - SetDefaultOnlyResourceLoadingHints({https_url().host()}); + SetDefaultOnlyResourceLoadingHints({url.host()}); + LoadUrlHints(url); + + SetExpectedFooJpgRequest(false); + SetExpectedBarJpgRequest(true); + ResetResourceLoadingHintInterventionHeaderSeen(); base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), https_url()); + ui_test_utils::NavigateToURL(browser(), url); RetryForHistogramUntilCountReached( &histogram_tester, "ResourceLoadingHints.CountBlockedSubresourcePatterns", @@ -347,7 +365,7 @@ SetExpectedBarJpgRequest(true); ResetResourceLoadingHintInterventionHeaderSeen(); - ui_test_utils::NavigateToURL(browser(), https_url()); + ui_test_utils::NavigateToURL(browser(), url); RetryForHistogramUntilCountReached( &histogram_tester, "ResourceLoadingHints.CountBlockedSubresourcePatterns", @@ -373,15 +391,19 @@ IN_PROC_BROWSER_TEST_F( ResourceLoadingHintsBrowserTest, DISABLE_ON_WIN_MAC(ExperimentalHints_ExperimentIsNotEnabled)) { - SetExpectedFooJpgRequest(true); - SetExpectedBarJpgRequest(true); + GURL url = https_url(); // Whitelist test URL for resource loading hints. - SetExperimentOnlyResourceLoadingHints({https_url().host()}); + SetExperimentOnlyResourceLoadingHints({url.host()}); + LoadUrlHints(url); + + SetExpectedFooJpgRequest(true); + SetExpectedBarJpgRequest(true); + ResetResourceLoadingHintInterventionHeaderSeen(); base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), https_url()); + ui_test_utils::NavigateToURL(browser(), url); histogram_tester.ExpectBucketCount( "Previews.EligibilityReason.ResourceLoadingHints", @@ -403,15 +425,20 @@ previews::features::kOptimizationHintsExperiments, {{previews::features::kOptimizationHintsExperimentNameParam, optimization_guide::testing::kFooExperimentName}}); - SetExpectedFooJpgRequest(false); - SetExpectedBarJpgRequest(true); + + GURL url = https_url(); // Whitelist test URL for resource loading hints. - SetExperimentOnlyResourceLoadingHints({https_url().host()}); + SetExperimentOnlyResourceLoadingHints({url.host()}); + LoadUrlHints(url); + + SetExpectedFooJpgRequest(false); + SetExpectedBarJpgRequest(true); + ResetResourceLoadingHintInterventionHeaderSeen(); base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), https_url()); + ui_test_utils::NavigateToURL(browser(), url); RetryForHistogramUntilCountReached( &histogram_tester, "ResourceLoadingHints.CountBlockedSubresourcePatterns", @@ -442,16 +469,21 @@ previews::features::kOptimizationHintsExperiments, {{previews::features::kOptimizationHintsExperimentNameParam, optimization_guide::testing::kFooExperimentName}}); - SetExpectedFooJpgRequest(false); - SetExpectedBarJpgRequest(true); + + GURL url = https_url(); // Whitelist test URL for resource loading hints. Set both experimental and // non-experimental hints. - SetMixResourceLoadingHints({https_url().host()}); + SetMixResourceLoadingHints({url.host()}); + LoadUrlHints(url); + + SetExpectedFooJpgRequest(false); + SetExpectedBarJpgRequest(true); + ResetResourceLoadingHintInterventionHeaderSeen(); base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), https_url()); + ui_test_utils::NavigateToURL(browser(), url); RetryForHistogramUntilCountReached( &histogram_tester, "ResourceLoadingHints.CountBlockedSubresourcePatterns", @@ -482,15 +514,20 @@ previews::features::kOptimizationHintsExperiments, {{previews::features::kOptimizationHintsExperimentNameParam, "some_other_experiment"}}); - SetExpectedFooJpgRequest(true); - SetExpectedBarJpgRequest(false); + + GURL url = https_url(); // Whitelist test URL for resource loading hints. - SetMixResourceLoadingHints({https_url().host()}); + SetMixResourceLoadingHints({url.host()}); + LoadUrlHints(url); + + SetExpectedFooJpgRequest(true); + SetExpectedBarJpgRequest(false); + ResetResourceLoadingHintInterventionHeaderSeen(); base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), https_url()); + ui_test_utils::NavigateToURL(browser(), url); RetryForHistogramUntilCountReached( &histogram_tester, "ResourceLoadingHints.CountBlockedSubresourcePatterns", @@ -500,22 +537,27 @@ static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1); // Infobar would still be shown since there were at least one resource // loading hints available, even though none of them matched. - histogram_tester.ExpectTotalCount( - "Previews.InfoBarAction.ResourceLoadingHints", 1); + EXPECT_FALSE(histogram_tester + .GetAllSamples("Previews.InfoBarAction.ResourceLoadingHints") + .empty()); EXPECT_TRUE(resource_loading_hint_intervention_header_seen()); } IN_PROC_BROWSER_TEST_F( ResourceLoadingHintsBrowserTest, DISABLE_ON_WIN_MAC(ResourceLoadingHintsHttpsWhitelistedRedirectToHttps)) { - SetExpectedFooJpgRequest(false); - SetExpectedBarJpgRequest(true); + GURL url = redirect_url(); SetDefaultOnlyResourceLoadingHints({https_url().host()}); + LoadUrlHints(url); + + SetExpectedFooJpgRequest(false); + SetExpectedBarJpgRequest(true); + ResetResourceLoadingHintInterventionHeaderSeen(); base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), redirect_url()); + ui_test_utils::NavigateToURL(browser(), url); RetryForHistogramUntilCountReached( &histogram_tester, "ResourceLoadingHints.CountBlockedSubresourcePatterns", @@ -528,8 +570,9 @@ histogram_tester.ExpectBucketCount( "Previews.EligibilityReason.ResourceLoadingHints", static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 2); - histogram_tester.ExpectTotalCount( - "Previews.InfoBarAction.ResourceLoadingHints", 1); + EXPECT_FALSE(histogram_tester + .GetAllSamples("Previews.InfoBarAction.ResourceLoadingHints") + .empty()); // SetDefaultOnlyResourceLoadingHints sets 3 resource loading hints patterns. histogram_tester.ExpectBucketCount( "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 1); @@ -539,15 +582,19 @@ IN_PROC_BROWSER_TEST_F( ResourceLoadingHintsBrowserTest, DISABLE_ON_WIN_MAC(ResourceLoadingHintsHttpsNoWhitelisted)) { - SetExpectedFooJpgRequest(true); - SetExpectedBarJpgRequest(true); + GURL url = https_url(); SetDefaultOnlyResourceLoadingHints({}); + LoadUrlHints(url); + + SetExpectedFooJpgRequest(true); + SetExpectedBarJpgRequest(true); + ResetResourceLoadingHintInterventionHeaderSeen(); base::HistogramTester histogram_tester; // The URL is not whitelisted. - ui_test_utils::NavigateToURL(browser(), https_url()); + ui_test_utils::NavigateToURL(browser(), url); base::RunLoop().RunUntilIdle(); histogram_tester.ExpectBucketCount( @@ -564,15 +611,19 @@ IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest, DISABLE_ON_WIN_MAC(ResourceLoadingHintsHttp)) { - SetExpectedFooJpgRequest(true); - SetExpectedBarJpgRequest(true); + GURL url = http_url(); // Whitelist test HTTP URL for resource loading hints. SetDefaultOnlyResourceLoadingHints({https_url().host()}); + LoadUrlHints(url); + + SetExpectedFooJpgRequest(true); + SetExpectedBarJpgRequest(true); + ResetResourceLoadingHintInterventionHeaderSeen(); base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), http_url()); + ui_test_utils::NavigateToURL(browser(), url); base::RunLoop().RunUntilIdle(); histogram_tester.ExpectBucketCount( @@ -588,15 +639,19 @@ IN_PROC_BROWSER_TEST_F( ResourceLoadingHintsBrowserTest, DISABLE_ON_WIN_MAC(ResourceLoadingHintsHttpsWhitelistedNoTransform)) { - SetExpectedFooJpgRequest(true); - SetExpectedBarJpgRequest(true); + GURL url = https_no_transform_url(); // Whitelist test URL for resource loading hints. SetDefaultOnlyResourceLoadingHints({https_url().host()}); + LoadUrlHints(url); + + SetExpectedFooJpgRequest(true); + SetExpectedBarJpgRequest(true); + ResetResourceLoadingHintInterventionHeaderSeen(); base::HistogramTester histogram_tester; - ui_test_utils::NavigateToURL(browser(), https_no_transform_url()); + ui_test_utils::NavigateToURL(browser(), url); base::RunLoop().RunUntilIdle(); histogram_tester.ExpectBucketCount(
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc index cfd13b0..007b003 100644 --- a/chrome/browser/printing/print_view_manager_base.cc +++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -56,9 +56,6 @@ #include "chrome/browser/printing/print_error_dialog.h" #endif -using base::TimeDelta; -using content::BrowserThread; - namespace printing { namespace { @@ -78,19 +75,6 @@ } #if BUILDFLAG(ENABLE_PRINT_PREVIEW) -void CreateQueryWithSettings(base::Value job_settings, - int render_process_id, - int render_frame_id, - scoped_refptr<PrintQueriesQueue> queue, - PrintSettingsCallback callback) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - scoped_refptr<printing::PrinterQuery> printer_query = - queue->CreatePrinterQuery(render_process_id, render_frame_id); - printer_query->SetSettings( - std::move(job_settings), - base::BindOnce(std::move(callback), printer_query)); -} - void OnPrintSettingsDoneWrapper(PrintSettingsCallback settings_callback, scoped_refptr<PrinterQuery> query) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); @@ -98,6 +82,22 @@ base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, base::BindOnce(std::move(settings_callback), query)); } + +void CreateQueryWithSettings(base::Value job_settings, + int render_process_id, + int render_frame_id, + scoped_refptr<PrintQueriesQueue> queue, + PrintSettingsCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + PrintSettingsCallback callback_wrapper = + base::BindOnce(OnPrintSettingsDoneWrapper, std::move(callback)); + scoped_refptr<printing::PrinterQuery> printer_query = + queue->CreatePrinterQuery(render_process_id, render_frame_id); + printer_query->SetSettings( + std::move(job_settings), + base::BindOnce(std::move(callback_wrapper), printer_query)); +} #endif // BUILDFLAG(ENABLE_PRINT_PREVIEW) } // namespace @@ -146,8 +146,7 @@ FROM_HERE, {content::BrowserThread::IO}, base::BindOnce(CreateQueryWithSettings, std::move(job_settings), rfh->GetProcess()->GetID(), rfh->GetRoutingID(), queue_, - base::BindOnce(OnPrintSettingsDoneWrapper, - std::move(settings_callback)))); + std::move(settings_callback))); } #endif // BUILDFLAG(ENABLE_PRINT_PREVIEW) @@ -177,10 +176,11 @@ PrinterHandler::PrintCallback callback, scoped_refptr<printing::PrinterQuery> printer_query) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(printer_query); + // Check if the job was cancelled. This should only happen on Windows when // the system dialog is cancelled. - if (printer_query && - printer_query->last_status() == PrintingContext::CANCEL) { + if (printer_query->last_status() == PrintingContext::CANCEL) { queue_->QueuePrinterQuery(printer_query.get()); #if defined(OS_WIN) base::PostTaskWithTraits( @@ -192,16 +192,16 @@ return; } - if (!printer_query || !printer_query->cookie() || - !printer_query->settings().dpi()) { - if (printer_query) - printer_query->StopWorker(); + if (!printer_query->cookie() || !printer_query->settings().dpi()) { + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&PrinterQuery::StopWorker, printer_query)); std::move(callback).Run(base::Value("Update settings failed")); return; } // Post task so that the query has time to reset the callback before calling - // OnDidGetPrintedPagesCount. + // OnDidGetPrintedPagesCount(). queue_->QueuePrinterQuery(printer_query.get()); base::PostTaskWithTraits( FROM_HERE, {content::BrowserThread::UI}, @@ -446,14 +446,20 @@ ShouldQuitFromInnerMessageLoop(); break; } - case JobEventDetails::NEW_DOC: #if defined(OS_WIN) case JobEventDetails::PAGE_DONE: #endif - case JobEventDetails::DOC_DONE: { + case JobEventDetails::NEW_DOC: { // Don't care about the actual printing process. break; } + case JobEventDetails::DOC_DONE: { + // Don't care about the actual printing process, except on Android. +#if defined(OS_ANDROID) + PdfWritingDone(number_pages_); +#endif + break; + } case JobEventDetails::JOB_DONE: { // Printing is done, we don't need it anymore. // print_job_->is_job_pending() may still be true, depending on the order @@ -569,6 +575,9 @@ // We don't need the metafile data anymore because the printing is canceled. print_job_->Cancel(); quit_inner_loop_.Reset(); +#if defined(OS_ANDROID) + PdfWritingDone(0); +#endif } else { DCHECK(!quit_inner_loop_); DCHECK(!print_job_->document() || print_job_->document()->IsComplete()); @@ -612,11 +621,11 @@ // - If we're looping because of renderer page generation, the renderer could // be CPU bound, the page overly complex/large or the system just // memory-bound. - static const int kPrinterSettingsTimeout = 60000; + static constexpr base::TimeDelta kPrinterSettingsTimeout = + base::TimeDelta::FromSeconds(60); base::OneShotTimer quit_timer; base::RunLoop run_loop; - quit_timer.Start(FROM_HERE, - TimeDelta::FromMilliseconds(kPrinterSettingsTimeout), + quit_timer.Start(FROM_HERE, kPrinterSettingsTimeout, run_loop.QuitWhenIdleClosure()); quit_inner_loop_ = run_loop.QuitClosure(); @@ -694,7 +703,7 @@ if (!printer_query) return; base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, + FROM_HERE, {content::BrowserThread::IO}, base::BindOnce(&PrinterQuery::StopWorker, printer_query)); }
diff --git a/chrome/browser/printing/print_view_manager_basic.cc b/chrome/browser/printing/print_view_manager_basic.cc index 0e90ce99..326396c 100644 --- a/chrome/browser/printing/print_view_manager_basic.cc +++ b/chrome/browser/printing/print_view_manager_basic.cc
@@ -27,8 +27,6 @@ void PrintViewManagerBasic::PdfWritingDone(int page_count) { if (pdf_writing_done_callback_) pdf_writing_done_callback_.Run(page_count); - // Invalidate the file descriptor so it doesn't get reused. - file_descriptor_ = base::FileDescriptor(); } #endif
diff --git a/chrome/browser/printing/print_view_manager_basic.h b/chrome/browser/printing/print_view_manager_basic.h index 0e132d9b..8bffa6f 100644 --- a/chrome/browser/printing/print_view_manager_basic.h +++ b/chrome/browser/printing/print_view_manager_basic.h
@@ -10,10 +10,6 @@ #include "chrome/browser/printing/print_view_manager_base.h" #include "content/public/browser/web_contents_user_data.h" -#if defined(OS_ANDROID) -#include "base/file_descriptor_posix.h" -#endif - namespace printing { // Manages the print commands for a WebContents - basic version. @@ -26,14 +22,6 @@ #if defined(OS_ANDROID) // printing::PrintManager: void PdfWritingDone(int page_count) override; - - // Sets the file descriptor into which the PDF will be written. - void set_file_descriptor(const base::FileDescriptor& file_descriptor) { - file_descriptor_ = file_descriptor; - } - - // Gets the file descriptor into which the PDF will be written. - base::FileDescriptor file_descriptor() const { return file_descriptor_; } #endif private: @@ -42,11 +30,6 @@ WEB_CONTENTS_USER_DATA_KEY_DECL(); -#if defined(OS_ANDROID) - // The file descriptor into which the PDF of the document will be written. - base::FileDescriptor file_descriptor_; -#endif - DISALLOW_COPY_AND_ASSIGN(PrintViewManagerBasic); };
diff --git a/chrome/browser/printing/printer_query.cc b/chrome/browser/printing/printer_query.cc index 5786a45..2abaa6e 100644 --- a/chrome/browser/printing/printer_query.cc +++ b/chrome/browser/printing/printer_query.cc
@@ -12,6 +12,7 @@ #include "base/location.h" #include "base/task/post_task.h" #include "base/threading/thread_restrictions.h" +#include "base/threading/thread_task_runner_handle.h" #include "base/values.h" #include "chrome/browser/printing/print_job_worker.h" #include "content/public/browser/browser_task_traits.h" @@ -22,7 +23,9 @@ namespace printing { PrinterQuery::PrinterQuery(int render_process_id, int render_frame_id) - : cookie_(PrintSettings::NewCookie()), + : base::RefCountedDeleteOnSequence<PrinterQuery>( + base::ThreadTaskRunnerHandle::Get()), + cookie_(PrintSettings::NewCookie()), worker_(std::make_unique<PrintJobWorker>(render_process_id, render_frame_id, this)) { @@ -57,7 +60,7 @@ } std::unique_ptr<PrintJobWorker> PrinterQuery::DetachWorker() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(!callback_); DCHECK(worker_);
diff --git a/chrome/browser/printing/printer_query.h b/chrome/browser/printing/printer_query.h index 6d9b0e7..b6d8e222 100644 --- a/chrome/browser/printing/printer_query.h +++ b/chrome/browser/printing/printer_query.h
@@ -9,7 +9,7 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/memory/ref_counted.h" +#include "base/memory/ref_counted_delete_on_sequence.h" #include "base/values.h" #include "printing/print_job_constants.h" #include "printing/print_settings.h" @@ -24,7 +24,7 @@ class PrintJobWorker; // Query the printer for settings. -class PrinterQuery : public base::RefCountedThreadSafe<PrinterQuery> { +class PrinterQuery : public base::RefCountedDeleteOnSequence<PrinterQuery> { public: // GetSettings() UI parameter. enum class GetSettingsAskParam { @@ -41,6 +41,8 @@ // Detach the PrintJobWorker associated to this object. Virtual so that tests // can override. + // Called on the UI thread. + // TODO(thestig): Do |worker_| and |callback_| need locks? virtual std::unique_ptr<PrintJobWorker> DetachWorker(); // Virtual so that tests can override. @@ -84,8 +86,9 @@ bool PostTask(const base::Location& from_here, base::OnceClosure task); protected: - // Refcounted class. - friend class base::RefCountedThreadSafe<PrinterQuery>; + // RefCountedDeleteOnSequence class. + friend class base::RefCountedDeleteOnSequence<PrinterQuery>; + friend class base::DeleteHelper<PrinterQuery>; virtual ~PrinterQuery();
diff --git a/chrome/browser/printing/printing_message_filter.cc b/chrome/browser/printing/printing_message_filter.cc index 8cf82aaf..df6cdee8 100644 --- a/chrome/browser/printing/printing_message_filter.cc +++ b/chrome/browser/printing/printing_message_filter.cc
@@ -31,12 +31,6 @@ #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" #endif -#if defined(OS_ANDROID) -#include "base/file_descriptor_posix.h" -#include "base/strings/string_number_conversions.h" -#include "chrome/browser/printing/print_view_manager_basic.h" -#endif - #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) #include "chrome/browser/conflicts/module_database_win.h" #endif @@ -67,7 +61,7 @@ DISALLOW_COPY_AND_ASSIGN(PrintingMessageFilterShutdownNotifierFactory); }; -#if defined(OS_ANDROID) || (defined(OS_WIN) && BUILDFLAG(ENABLE_PRINT_PREVIEW)) +#if defined(OS_WIN) && BUILDFLAG(ENABLE_PRINT_PREVIEW) content::WebContents* GetWebContentsForRenderFrame(int render_process_id, int render_frame_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -76,16 +70,6 @@ return frame ? content::WebContents::FromRenderFrameHost(frame) : nullptr; } -#if defined(OS_ANDROID) -PrintViewManagerBasic* GetPrintManager(int render_process_id, - int render_frame_id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::WebContents* web_contents = - GetWebContentsForRenderFrame(render_process_id, render_frame_id); - return web_contents ? PrintViewManagerBasic::FromWebContents(web_contents) - : nullptr; -} -#else // defined(OS_WIN) && BUILDFLAG(ENABLE_PRINT_PREVIEW) PrintViewManager* GetPrintViewManager(int render_process_id, int render_frame_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -94,9 +78,7 @@ return web_contents ? PrintViewManager::FromWebContents(web_contents) : nullptr; } -#endif -#endif // defined(OS_ANDROID) || (defined(OS_WIN) && - // BUILDFLAG(ENABLE_PRINT_PREVIEW)) +#endif // defined(OS_WIN) && BUILDFLAG(ENABLE_PRINT_PREVIEW) } // namespace @@ -126,16 +108,6 @@ printing_shutdown_notifier_.reset(); } -void PrintingMessageFilter::OverrideThreadForMessage( - const IPC::Message& message, BrowserThread::ID* thread) { -#if defined(OS_ANDROID) - if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID || - message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) { - *thread = BrowserThread::UI; - } -#endif -} - void PrintingMessageFilter::OnDestruct() const { BrowserThread::DeleteOnUIThread::Destruct(this); } @@ -143,12 +115,6 @@ bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PrintingMessageFilter, message) -#if defined(OS_ANDROID) - IPC_MESSAGE_HANDLER(PrintHostMsg_AllocateTempFileForPrinting, - OnAllocateTempFileForPrinting) - IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten, - OnTempFileForPrintingWritten) -#endif IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings, OnGetDefaultPrintSettings) IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint) @@ -162,35 +128,6 @@ return handled; } -#if defined(OS_ANDROID) -void PrintingMessageFilter::OnAllocateTempFileForPrinting( - int render_frame_id, - base::FileDescriptor* temp_file_fd, - int* sequence_number) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - PrintViewManagerBasic* print_view_manager = - GetPrintManager(render_process_id_, render_frame_id); - if (!print_view_manager) - return; - - // The file descriptor is originally created in & passed from the Android - // side, and it will handle the closing. - temp_file_fd->fd = print_view_manager->file_descriptor().fd; - temp_file_fd->auto_close = false; -} - -void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_frame_id, - int sequence_number, - int page_count) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK_GT(page_count, 0); - PrintViewManagerBasic* print_view_manager = - GetPrintManager(render_process_id_, render_frame_id); - if (print_view_manager) - print_view_manager->PdfWritingDone(page_count); -} -#endif // defined(OS_ANDROID) - void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) { DCHECK_CURRENTLY_ON(BrowserThread::IO); scoped_refptr<PrinterQuery> printer_query; @@ -263,11 +200,6 @@ scoped_refptr<PrinterQuery> printer_query, IPC::Message* reply_msg) { PrintMsg_PrintPages_Params params; -#if defined(OS_ANDROID) - // We need to save the routing ID here because Send method below deletes the - // |reply_msg| before we can get the routing ID for the Android code. - int routing_id = reply_msg->routing_id(); -#endif if (printer_query->last_status() != PrintingContext::OK || !printer_query->settings().dpi()) { params.Reset(); @@ -279,32 +211,12 @@ PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params); Send(reply_msg); if (!params.params.dpi.IsEmpty() && params.params.document_cookie) { -#if defined(OS_ANDROID) - int file_descriptor; - const base::string16& device_name = printer_query->settings().device_name(); - if (base::StringToInt(device_name, &file_descriptor)) { - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - base::Bind(&PrintingMessageFilter::UpdateFileDescriptor, this, - routing_id, file_descriptor)); - } -#endif queue_->QueuePrinterQuery(printer_query.get()); } else { printer_query->StopWorker(); } } -#if defined(OS_ANDROID) -void PrintingMessageFilter::UpdateFileDescriptor(int render_frame_id, int fd) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - PrintViewManagerBasic* print_view_manager = - GetPrintManager(render_process_id_, render_frame_id); - if (print_view_manager) - print_view_manager->set_file_descriptor(base::FileDescriptor(fd, false)); -} -#endif - void PrintingMessageFilter::OnUpdatePrintSettings(int document_cookie, base::Value job_settings, IPC::Message* reply_msg) {
diff --git a/chrome/browser/printing/printing_message_filter.h b/chrome/browser/printing/printing_message_filter.h index 63b71257..c4d586e6 100644 --- a/chrome/browser/printing/printing_message_filter.h +++ b/chrome/browser/printing/printing_message_filter.h
@@ -23,12 +23,6 @@ struct PrintHostMsg_ScriptedPrint_Params; class Profile; -#if defined(OS_ANDROID) -namespace base { -struct FileDescriptor; -} -#endif - namespace printing { class PrintQueriesQueue; @@ -40,10 +34,7 @@ public: PrintingMessageFilter(int render_process_id, Profile* profile); - // content::BrowserMessageFilter methods. - void OverrideThreadForMessage(const IPC::Message& message, - content::BrowserThread::ID* thread) override; - + // content::BrowserMessageFilter: bool OnMessageReceived(const IPC::Message& message) override; private: @@ -56,21 +47,6 @@ void ShutdownOnUIThread(); -#if defined(OS_ANDROID) - // Used to ask the browser allocate a temporary file for the renderer - // to fill in resulting PDF in renderer. - void OnAllocateTempFileForPrinting(int render_frame_id, - base::FileDescriptor* temp_file_fd, - int* sequence_number); - void OnTempFileForPrintingWritten(int render_frame_id, - int sequence_number, - int page_count); - - // Updates the file descriptor for the PrintViewManagerBasic of a given - // |render_frame_id|. - void UpdateFileDescriptor(int render_frame_id, int fd); -#endif - // Get the default print setting. void OnGetDefaultPrintSettings(IPC::Message* reply_msg); void OnGetDefaultPrintSettingsReply(scoped_refptr<PrinterQuery> printer_query,
diff --git a/chrome/browser/resources/bookmarks/toolbar.js b/chrome/browser/resources/bookmarks/toolbar.js index d8c584c..3dd19e3f 100644 --- a/chrome/browser/resources/bookmarks/toolbar.js +++ b/chrome/browser/resources/bookmarks/toolbar.js
@@ -84,13 +84,12 @@ }, /** - * @param {Event} e + * @param {!CustomEvent<string>} e * @private */ onSearchChanged_: function(e) { - const searchTerm = /** @type {string} */ (e.detail); - if (searchTerm != this.searchTerm_) { - this.dispatch(bookmarks.actions.setSearchTerm(searchTerm)); + if (e.detail != this.searchTerm_) { + this.dispatch(bookmarks.actions.setSearchTerm(e.detail)); } },
diff --git a/chrome/browser/resources/chromeos/camera/OWNERS b/chrome/browser/resources/chromeos/camera/OWNERS new file mode 100644 index 0000000..b98e4c7 --- /dev/null +++ b/chrome/browser/resources/chromeos/camera/OWNERS
@@ -0,0 +1,9 @@ +set noparent + +henryhsu@chromium.org +inker@chromium.org +jcliang@chromium.org +shenghao@chromium.org +shik@chromium.org +wtlee@chromium.org +yuli@chromium.org
diff --git a/chrome/browser/resources/chromeos/camera/src/js/main.js b/chrome/browser/resources/chromeos/camera/src/js/main.js index d01ac16..2534eb6 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/main.js +++ b/chrome/browser/resources/chromeos/camera/src/js/main.js
@@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Chromium OS Authors. All rights reserved. +// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,10 +11,9 @@ /** * Creates the Camera App main object. - * @param {number} aspectRatio Aspect ratio of app window when launched. * @constructor */ -cca.App = function(aspectRatio) { +cca.App = function() { /** * @type {cca.models.Gallery} * @private @@ -25,8 +24,7 @@ * @type {cca.views.Camera} * @private */ - this.cameraView_ = new cca.views.Camera( - this.model_, this.onWindowResize_.bind(this)); + this.cameraView_ = new cca.views.Camera(this.model_); /** * @type {cca.views.MasterSettings} @@ -64,23 +62,10 @@ */ this.dialogView_ = new cca.views.Dialog(); - /** - * @type {?number} - * @private - */ - this.resizeWindowTimeout_ = null; - - /** - * @type {number} - * @private - */ - this.aspectRatio_ = aspectRatio; - // End of properties. Seal the object. Object.seal(this); document.body.addEventListener('keydown', this.onKeyPressed_.bind(this)); - window.addEventListener('resize', this.onWindowResize_.bind(this, null)); document.title = chrome.i18n.getMessage('name'); this.setupI18nElements_(); @@ -202,54 +187,6 @@ }; /** - * Resizes the window to match the last known aspect ratio if applicable. - * @private - */ -cca.App.prototype.resizeByAspectRatio_ = function() { - // Don't update window size if it's maximized or fullscreen. - if (cca.util.isWindowFullSize()) { - return; - } - - // Keep the width fixed and calculate the height by the aspect ratio. - // TODO(yuli): Update min-width for resizing at portrait orientation. - var inner = chrome.app.window.current().innerBounds; - var innerW = inner.minWidth; - var innerH = Math.round(innerW / this.aspectRatio_); - - // Limit window resizing capability by setting min-height. Don't limit - // max-height here as it may disable maximize/fullscreen capabilities. - inner.minHeight = innerH; - - inner.width = innerW; - inner.height = innerH; -}; - -/** - * Handles resizing window/views for size or aspect ratio changes. - * @param {number=} aspectRatio Aspect ratio changed. - * @private - */ -cca.App.prototype.onWindowResize_ = function(aspectRatio) { - if (this.resizeWindowTimeout_) { - clearTimeout(this.resizeWindowTimeout_); - this.resizeWindowTimeout_ = null; - } - if (aspectRatio) { - // Update window size immediately for changed aspect ratio. - this.aspectRatio_ = aspectRatio; - this.resizeByAspectRatio_(); - } else { - // Don't further resize window during resizing for smooth UX. - this.resizeWindowTimeout_ = setTimeout(() => { - this.resizeWindowTimeout_ = null; - this.resizeByAspectRatio_(); - }, 500); - } - cca.nav.onWindowResized(); -}; - -/** * Handles pressed keys. * @param {Event} event Key press event. * @private @@ -269,11 +206,9 @@ * Creates the Camera object and starts screen capturing. */ document.addEventListener('DOMContentLoaded', () => { - var appWindow = chrome.app.window.current(); if (!cca.App.instance_) { - var inner = appWindow.innerBounds; - cca.App.instance_ = new cca.App(inner.width / inner.height); + cca.App.instance_ = new cca.App(); } cca.App.instance_.start(); - appWindow.show(); + chrome.app.window.current().show(); });
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js index d085510..ea127e5 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js
@@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Chromium OS Authors. All rights reserved. +// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -17,10 +17,9 @@ /** * Creates the camera-view controller. * @param {cca.models.Gallery} model Model object. - * @param {function(number)} onAspectRatio Callback to report aspect ratio. * @constructor */ -cca.views.Camera = function(model, onAspectRatio) { +cca.views.Camera = function(model) { cca.views.View.call(this, '#camera'); /** @@ -63,8 +62,7 @@ * @type {cca.views.camera.Preview} * @private */ - this.preview_ = new cca.views.camera.Preview( - this.stop_.bind(this), onAspectRatio); + this.preview_ = new cca.views.camera.Preview(this.stop_.bind(this)); /** * Options for the camera.
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/preview.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/preview.js index 9ce2d1d9..63853460 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera/preview.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera/preview.js
@@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -22,10 +22,9 @@ /** * Creates a controller for the video preview of Camera view. * @param {function()} onNewStreamNeeded Callback to request new stream. - * @param {function(number)} onAspectRatio Callback to report aspect ratio. * @constructor */ -cca.views.camera.Preview = function(onNewStreamNeeded, onAspectRatio) { +cca.views.camera.Preview = function(onNewStreamNeeded) { /** * @type {function()} * @private @@ -33,12 +32,6 @@ this.onNewStreamNeeded_ = onNewStreamNeeded; /** - * @type {function(number)} - * @private - */ - this.onAspectRatio_ = onAspectRatio; - - /** * Video element to capture the stream. * @type {Video} * @private @@ -66,9 +59,27 @@ */ this.focus_ = null; + /** + * Timeout for resizing the window. + * @type {?number} + * @private + */ + this.resizeWindowTimeout_ = null; + + /** + * Aspect ratio for the window. + * @type {number} + * @private + */ + this.aspectRatio_ = 1; + // End of properties, seal the object. Object.seal(this); + var inner = chrome.app.window.current().innerBounds; + this.aspectRatio_ = inner.width / inner.height; + window.addEventListener('resize', this.onWindowResize_.bind(this, null)); + this.video_.cleanup = () => {}; }; @@ -176,12 +187,54 @@ }; /** + * Handles resizing the window for preview's aspect ratio changes. + * @param {number=} aspectRatio Aspect ratio changed. + * @private + */ +cca.views.camera.Preview.prototype.onWindowResize_ = function(aspectRatio) { + if (this.resizeWindowTimeout_) { + clearTimeout(this.resizeWindowTimeout_); + this.resizeWindowTimeout_ = null; + } + // Resize window for changed preview's aspect ratio or restore window size by + // the last known window's aspect ratio. + new Promise((resolve) => { + if (aspectRatio) { + this.aspectRatio_ = aspectRatio; + resolve(); + } else { + this.resizeWindowTimeout_ = setTimeout(() => { + this.resizeWindowTimeout_ = null; + resolve(); + }, 500); // Delay further resizing for smooth UX. + } + }).then(() => { + // Resize window by aspect ratio only if it's not maximized or fullscreen. + if (cca.util.isWindowFullSize()) { + return; + } + // Keep the width fixed and calculate the height by the aspect ratio. + // TODO(yuli): Update min-width for resizing at portrait orientation. + var inner = chrome.app.window.current().innerBounds; + var innerW = inner.minWidth; + var innerH = Math.round(innerW / this.aspectRatio_); + + // Limit window resizing capability by setting min-height. Don't limit + // max-height here as it may disable maximize/fullscreen capabilities. + inner.minHeight = innerH; + inner.width = innerW; + inner.height = innerH; + }); + cca.nav.onWindowResized(); +}; + +/** * Handles changed intrinsic size (first loaded or orientation changes). * @private */ cca.views.camera.Preview.prototype.onIntrinsicSizeChanged_ = function() { if (this.video_.videoWidth && this.video_.videoHeight) { - this.onAspectRatio_(this.video_.videoWidth / this.video_.videoHeight); + this.onWindowResize_(this.video_.videoWidth / this.video_.videoHeight); } this.cancelFocus_(); };
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs index 4e70c32..0612623 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -1936,3 +1936,28 @@ .replay(); }); }); + +TEST_F('ChromeVoxBackgroundTest', 'ValidationTest', function() { + var mockFeedback = this.createMockFeedback(); + this.runWithLoadedTree(function() {/* + <label for="in1">Name:</label> + <input id="in1" required autofocus> + <script> + const in1 = document.querySelector('input'); + in1.addEventListener('focus', () => { + setTimeout(() => { + in1.setCustomValidity('Please enter name'); + in1.reportValidity(); + }, 500); + }); + </script> + */}, function(root) { + mockFeedback + .expectSpeech('Name:') + .expectSpeech('Edit text') + .expectSpeech('Required') + .expectSpeech('Alert') + .expectSpeech('Please enter name') + .replay(); + }); +});
diff --git a/chrome/browser/resources/chromeos/login/md_login_shared.js b/chrome/browser/resources/chromeos/login/md_login_shared.js index bcef8f8..7e721b79 100644 --- a/chrome/browser/resources/chromeos/login/md_login_shared.js +++ b/chrome/browser/resources/chromeos/login/md_login_shared.js
@@ -21,6 +21,7 @@ // <include src="../../../../../ui/login/display_manager.js"> // <include src="md_header_bar.js"> // <include src="md_top_header_bar.js"> +// <include src="demo_mode_test_helper.js"> // <include // src="../../../../../ui/login/account_picker/md_screen_account_picker.js"> @@ -414,6 +415,13 @@ }; /** + * Starts online demo mode setup for telemetry. + */ + Oobe.setUpOnlineDemoModeForTesting = function() { + DemoModeTestHelper.setUp('online'); + }; + + /** * Shows/hides login UI control bar with buttons like [Shut down]. */ Oobe.showControlBar = function(show) {
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js index e72a9fd5..b84d189c 100644 --- a/chrome/browser/resources/chromeos/login/oobe.js +++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -20,7 +20,6 @@ // <include src="oobe_screen_welcome.js"> // <include src="multi_tap_detector.js"> // <include src="web_view_helper.js"> -// <include src="demo_mode_test_helper.js"> cr.define('cr.ui.Oobe', function() {
diff --git a/chrome/browser/resources/chromeos/switch_access/menu_panel.js b/chrome/browser/resources/chromeos/switch_access/menu_panel.js index da66412..471eaca 100644 --- a/chrome/browser/resources/chromeos/switch_access/menu_panel.js +++ b/chrome/browser/resources/chromeos/switch_access/menu_panel.js
@@ -3,113 +3,123 @@ // found in the LICENSE file. /** - * Class to handle the Switch Access menu panel. - * @constructor + * Handles the Switch Access menu panel. */ -function Panel() {} +const Panel = { + /** + * This must be kept in sync with the div ID in menu_panel.html. + * @type {string} + */ + MENU_ID: 'switchaccess_menu_actions', + /** + * This must be kept in sync with the class name in menu_panel.css. + * @type {string} + */ + FOCUS_CLASS: 'focus', -// This must be kept in sync with the div ID in menu_panel.html -Panel.MENU_ID = 'switchaccess_menu_actions'; -// This must be kept in sync with the class name in menu_panel.css -Panel.FOCUS_CLASS = 'focus'; + /** + * Keeps track of whether we have received a 'ready' from the background page. + * @type {boolean} + */ + readyReceived: false, + /** + * Keeps track of whether the context menu is loaded. + * @type {boolean} + */ + loaded: false, -Panel.readyReceived = false; -Panel.loaded = false; + /** + * Captures messages before the Panel is initialized. + */ + preMessageHandler: () => { + Panel.readyReceived = true; + if (Panel.loaded) + Panel.sendReady(); + window.removeEventListener('message', Panel.preMessageHandler); + }, + + /** + * Initialize the panel and buttons. + */ + init: () => { + Panel.loaded = true; + if (Panel.readyReceived) + Panel.sendReady(); + + const div = document.getElementById(Panel.MENU_ID); + for (const button of div.children) + Panel.setupButton(button); + window.addEventListener('message', Panel.matchMessage); + }, + + /** + * Sends a message to the background when both pages are loaded. + */ + sendReady: () => { + MessageHandler.sendMessage( + MessageHandler.Destination.BACKGROUND, MessageHandler.READY); + }, + + /** + * Adds an event listener to the given button to send a message when clicked. + * @param {!HTMLElement} button + */ + setupButton: (button) => { + let id = button.id; + button.addEventListener('click', function() { + MessageHandler.sendMessage(MessageHandler.Destination.BACKGROUND, id); + }.bind(id)); + }, + + /** + * Takes the given message and sees if it matches any expected pattern. If + * it does, extract the parameters and pass them to the appropriate handler. + * If not, log as an unrecognized action. + * + * @param {Object} message + */ + matchMessage: (message) => { + let matches = message.data.match(MessageHandler.SET_ACTIONS_REGEX); + if (matches && matches.length === 2) { + const actions = matches[1].split(','); + Panel.setActions(actions); + return; + } + matches = message.data.match(MessageHandler.SET_FOCUS_RING_REGEX); + if (matches && matches.length === 3) { + const id = matches[1]; + const shouldAdd = matches[2] === 'on'; + Panel.updateClass(id, Panel.FOCUS_CLASS, shouldAdd); + return; + } + console.log('Action not recognized: ' + message.data); + }, + + /** + * Sets which buttons are enabled/disabled, based on |actions|. + * @param {!Array<string>} actions + */ + setActions: (actions) => { + const div = document.getElementById(Panel.MENU_ID); + for (const button of div.children) + button.hidden = !actions.includes(button.id); + }, + + /** + * Either adds or removes the class |className| for the element with the given + * |id|. + * @param {string} id + * @param {string} className + * @param {bool} shouldAdd + */ + updateClass: (id, className, shouldAdd) => { + const htmlNode = document.getElementById(id); + if (shouldAdd) + htmlNode.classList.add(className); + else + htmlNode.classList.remove(className); + } +}; + window.addEventListener('message', Panel.preMessageHandler); - -/** - * Captures messages before the Panel is initialized. - */ -Panel.preMessageHandler = function() { - Panel.readyReceived = true; - if (Panel.loaded) - Panel.sendReady(); - window.removeEventListener('message', Panel.preMessageHandler); -}; - -/** - * Initialize the panel and buttons. - */ -Panel.init = function() { - Panel.loaded = true; - if (Panel.readyReceived) - Panel.sendReady(); - - let div = document.getElementById(Panel.MENU_ID); - for (let button of div.children) - Panel.setupButton(button); - window.addEventListener('message', Panel.matchMessage); -}; - -/** - * Sends a message to the background when both pages are loaded. - */ -Panel.sendReady = function() { - MessageHandler.sendMessage(MessageHandler.Destination.BACKGROUND, 'ready'); -}; - -/** - * Adds an event listener to the given button to send a message when clicked. - * @param {!HTMLElement} button - */ -Panel.setupButton = function(button) { - let id = button.id; - button.addEventListener('click', function() { - MessageHandler.sendMessage(MessageHandler.Destination.BACKGROUND, id); - }.bind(id)); -}; - -/** - * Takes the given message and sees if it matches any expected pattern. If - * it does, extract the parameters and pass them to the appropriate handler. - * If not, log as an unrecognized action. - * - * @param {Object} message - */ -Panel.matchMessage = function(message) { - if (message.data === 'ready') { - clearInterval(Panel.handshakeInterval); - return; - } - let matches = message.data.match(MessageHandler.SET_ACTIONS_REGEX); - if (matches && matches.length === 2) { - let actions = matches[1].split(','); - Panel.setActions(actions); - return; - } - matches = message.data.match(MessageHandler.SET_FOCUS_RING_REGEX); - if (matches && matches.length === 3) { - let id = matches[1]; - let shouldAdd = matches[2] === 'on'; - Panel.updateStyle(id, Panel.FOCUS_CLASS, shouldAdd); - return; - } - console.log('Action not recognized: ' + message.data); -}; - -/** - * Sets which buttons are enabled/disabled, based on |actions|. - * @param {!Array<string>} actions - */ -Panel.setActions = function(actions) { - let div = document.getElementById(Panel.MENU_ID); - for (let button of div.children) - button.hidden = !actions.includes(button.id); -}; - -/** - * Sets the style for the element with the given |id| by toggling - * |className|. - * @param {string} id - * @param {string} className - * @param {bool} shouldAdd - */ -Panel.updateStyle = function(id, className, shouldAdd) { - let htmlNode = document.getElementById(id); - if (shouldAdd) - htmlNode.classList.add(className); - else - htmlNode.classList.remove(className); -}; - window.addEventListener('load', Panel.init);
diff --git a/chrome/browser/resources/chromeos/switch_access/message_handler.js b/chrome/browser/resources/chromeos/switch_access/message_handler.js index a36df5e25..fd702d44 100644 --- a/chrome/browser/resources/chromeos/switch_access/message_handler.js +++ b/chrome/browser/resources/chromeos/switch_access/message_handler.js
@@ -27,6 +27,12 @@ Destination: {BACKGROUND: 'background', MENU_PANEL: 'menu_panel.html'}, /** + * Constant that signals readiness. + * @type {string} + */ + READY: 'ready', + + /** * Sends a message to the Switch Access menu panel with the given name and * parameters. *
diff --git a/chrome/browser/resources/local_ntp/custom_backgrounds.css b/chrome/browser/resources/local_ntp/custom_backgrounds.css index 4f0a4e9..07dc7084 100644 --- a/chrome/browser/resources/local_ntp/custom_backgrounds.css +++ b/chrome/browser/resources/local_ntp/custom_backgrounds.css
@@ -82,6 +82,12 @@ right: 16px; } +html[darkmode=true] #edit-bg-dialog { + background-color: rgb(41, 42, 45); + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), + 0 4px 8px 3px rgba(0, 0, 0, 0.15); +} + #edit-bg-menu { padding: 0 0 16px 0; width: 325px; @@ -104,6 +110,10 @@ padding: 16px 16px 0 0; } +html[darkmode=true] #edit-bg-title { + color: rgb(var(--GG200-rgb)); +} + .bg-option { color: rgb(var(--GG800-rgb)); font-family: 'Roboto', arial, sans-serif; @@ -112,10 +122,18 @@ line-height: 40px; } +html[darkmode=true] .bg-option { + color: rgb(var(--GG200-rgb)); +} + .bg-option:hover { background-color: rgb(var(--GG100-rgb)); } +html[darkmode=true] .bg-option:hover { + background-color: rgb(var(--GG800-rgb)); +} + .bg-option-img { background-size: 24px 24px; display: inline-block; @@ -135,6 +153,10 @@ opacity: 0.28; } +html[darkmode=true] .bg-option.bg-option-disabled { + opacity: 0.38; +} + .bg-option.bg-option-disabled:focus { outline: none; } @@ -162,6 +184,10 @@ width: 100%; } +html[darkmode=true] #edit-bg-divider { + border-color: rgba(255, 255, 255, 0.1); +} + #custom-links-restore-default .bg-option-img { background: rgb(var(--GG100-rgb)) url(icons/link_gray.svg) no-repeat center; border-radius: 50%; @@ -184,10 +210,6 @@ white-space: nowrap; } -#bg-sel-menu::backdrop { - background-color: rgba(255, 255, 255, .75); -} - /* The width here should match that used in customBackgrounds.getNextTile. */ #bg-sel-menu { background-color: #fff; @@ -210,6 +232,12 @@ z-index: 10000; } +html[darkmode=true] #bg-sel-menu { + background-color: rgb(41, 42, 45); + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), + 0 4px 8px 3px rgba(0, 0, 0, 0.15); +} + /* The width is decided by the longest text length plus 16px margin on the right, so that every text can stay on its row even on the smallest window */ @media (max-width: 356px) { @@ -241,12 +269,36 @@ user-select: none; } +html[darkmode=true] #bg-sel-title-bar { + border-color: rgba(255, 255, 255, 0.1); +} + #bg-sel-back { background: url(../../../../ui/webui/resources/images/icon_arrow_back.svg) no-repeat center; background-size: 20px 20px; display: none; height: 20px; outline: none; + position: relative; + width: 20px; +} + +html[darkmode=true] #bg-sel-back { + background: transparent; +} + +/* We use ::after without content to provide the masked arrow element. */ +html[darkmode=true] #bg-sel-back::after { + -webkit-mask-image: url(../../../../ui/webui/resources/images/icon_arrow_back.svg); + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: 20px; + background-color: rgb(var(--GG200-rgb)); + content: ''; + display: block; + height: 20px; + left: 0; + position: absolute; + top: 0; width: 20px; } @@ -266,6 +318,11 @@ background-size: 36px 36px; } +html[darkmode=true] #bg-sel-back-circle:active, +html[darkmode=true] #bg-sel-back-circle:focus { + background: rgb(var(--GG800-rgb)); +} + .is-col-sel #bg-sel-back { display: none; text-align: start; @@ -309,6 +366,10 @@ text-align: center; } +html[darkmode=true] #bg-sel-title { + color: rgb(var(--GG200-rgb)); +} + .is-col-sel #bg-sel-title { padding-inline-start: 0; text-align: center; @@ -337,6 +398,10 @@ width: 100%; } +html[darkmode=true] #bg-sel-footer { + border-color: rgba(255, 255, 255, 0.1); +} + .bg-sel-footer-button { margin-top: 16px; } @@ -380,6 +445,10 @@ width: calc(33% - 8px); } +html[darkmode=true] .bg-sel-tile-bg { + background-color: rgb(var(--GG900-rgb)); +} + /* The width here should match that used in customBackgrounds.getTilesWide. */ @media (max-width: 517px) { #bg-sel-menu { @@ -416,6 +485,10 @@ width: 100%; } +html[darkmode=true] .selected-border { + border-color: rgb(var(--GB300-rgb)); +} + .selected-circle { background: #FFF no-repeat center; border-radius: 50%; @@ -431,6 +504,10 @@ right: 66px; } +html[darkmode=true] .selected-circle { + background-color: rgb(var(--GG900-rgb)); +} + .selected-check { background: url(../../../../ui/webui/resources/images/check_circle.svg) no-repeat center; background-size: 28px 28px; @@ -446,6 +523,25 @@ right: 63px; } +html[darkmode=true] .selected-check { + background: transparent; +} + +/* We use ::after without content to provide the masked check element. */ +html[darkmode=true] .selected-check::after { + -webkit-mask-image: url(../../../../ui/webui/resources/images/check_circle.svg); + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: 28px; + background-color: rgb(var(--GB300-rgb)); + content: ''; + display: block; + height: 28px; + left: 0; + position: absolute; + top: 0; + width: 28px; +} + .bg-sel-tile-title { background-color: rgba(var(--GG900-rgb), 0.71); bottom: 0;
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.css b/chrome/browser/resources/local_ntp/custom_links_edit.css index ec2bd4a..8a27be6 100644 --- a/chrome/browser/resources/local_ntp/custom_links_edit.css +++ b/chrome/browser/resources/local_ntp/custom_links_edit.css
@@ -25,6 +25,12 @@ z-index: 10000; } +html[darkmode=true] #edit-link-dialog { + background-color: rgb(41, 42, 45); + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), + 0 4px 8px 3px rgba(0, 0, 0, 0.15); +} + #edit-link-dialog::backdrop { background: transparent; } @@ -41,6 +47,10 @@ margin-bottom: 16px; } +html[darkmode=true] #dialog-title { + color: rgb(var(--GG200-rgb)); +} + .field-container { margin-bottom: 16px; } @@ -52,6 +62,10 @@ margin-bottom: 4px; } +html[darkmode=true] .field-title { + color: rgb(var(--GG400-rgb)); +} + .input-container { position: relative; } @@ -76,10 +90,20 @@ text-align: right; /* csschecker-disable-line left-right */ } +html[darkmode=true] input { + background-color: rgba(0, 0, 0, 0.3); + caret-color: rgb(var(--GB300-rgb)); + color: rgb(var(--GG200-rgb)); +} + input::placeholder { color: rgba(var(--GG900-rgb), 0.38); } +html[darkmode=true] input::placeholder { + color: rgb(var(--GG500-rgb)); +} + .underline { border-bottom: 2px solid rgb(var(--GB600-rgb)); bottom: 0; @@ -93,6 +117,10 @@ width: 0; } +html[darkmode=true] .underline { + border-color: rgb(var(--GB300-rgb)); +} + input:focus + .underline { opacity: 1; transition: width 180ms ease-out, opacity 120ms ease-in; @@ -103,6 +131,10 @@ color: rgb(var(--GB600-rgb)); } +html[darkmode=true] .field-title.focused { + color: rgb(var(--GB300-rgb)); +} + .error-msg { color: rgb(var(--GR600-rgb)); display: none; @@ -111,10 +143,18 @@ margin-top: 6px; } +html[darkmode=true] .error-msg { + color: rgb(var(--GR300-rgb)); +} + .invalid label { color: rgb(var(--GR600-rgb)); } +html[darkmode=true] .invalid label { + color: rgb(var(--GR300-rgb)); +} + .invalid .error-msg { display: block; } @@ -126,6 +166,10 @@ width: 100%; } +html[darkmode=true] .invalid .underline { + border-color: rgb(var(--GR300-rgb)); +} + .buttons-container { display: flex; justify-content: space-between;
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.js b/chrome/browser/resources/local_ntp/custom_links_edit.js index c4e50fba..a417f2e 100644 --- a/chrome/browser/resources/local_ntp/custom_links_edit.js +++ b/chrome/browser/resources/local_ntp/custom_links_edit.js
@@ -256,10 +256,13 @@ document.title = queryArgs['editTitle']; // Enable RTL. - // TODO(851293): Add RTL formatting. if (queryArgs['rtl'] == '1') { - let html = document.querySelector('html'); - html.dir = 'rtl'; + document.documentElement.setAttribute('dir', 'rtl'); + } + + // Enable dark mode. + if (queryArgs['enableDarkMode'] == '1') { + document.documentElement.setAttribute('darkmode', true); } // Populate text content.
diff --git a/chrome/browser/resources/local_ntp/doodles.js b/chrome/browser/resources/local_ntp/doodles.js index 98e6c2b..4aa99b4 100644 --- a/chrome/browser/resources/local_ntp/doodles.js +++ b/chrome/browser/resources/local_ntp/doodles.js
@@ -313,8 +313,9 @@ doodles.isDoodleCurrentlyVisible = function() { var haveDoodle = ($(doodles.IDS.LOGO_DOODLE) .classList.contains(doodles.CLASSES.SHOW_LOGO)); - var wantDoodle = (doodles.targetDoodle.image !== null) && - (doodles.targetDoodle.metadata !== null); + var wantDoodle = (doodles.targetDoodle.metadata !== null) && + (doodles.targetDoodle.image !== null || + doodles.targetDoodle.metadata.type === doodles.LOGO_TYPE.INTERACTIVE); if (!haveDoodle || !wantDoodle) { return haveDoodle === wantDoodle; }
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css index 5b45ca7..25cab2a0 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.css +++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -145,10 +145,18 @@ transition: background-color 300ms ease-in-out, opacity 200ms } +html[darkmode=true] #fakebox { + background-color: rgb(var(--GG900-rgb)); +} + #fakebox:hover { background-color: rgb(var(--GG200-rgb)); } +html[darkmode=true] #fakebox:hover { + background-color: rgb(42, 43, 46); +} + .non-google-page #fakebox-container { display: none; } @@ -188,6 +196,10 @@ white-space: nowrap; } +html[darkmode=true] #fakebox-text { + color: rgb(var(--GG200-rgb)); +} + html[dir=rtl] #fakebox-text { left: auto; right: 0; @@ -208,6 +220,10 @@ right: 20px; } +html[darkmode=true] #fakebox-cursor { + background: rgb(var(--GB300-rgb)); +} + #fakebox-microphone { background: url(icons/googlemic_clr_24px.svg) no-repeat center; background-size: 24px 24px; @@ -500,6 +516,14 @@ width: 100%; } +.customize-dialog::backdrop { + background-color: rgba(255, 255, 255, .75); +} + +html[darkmode=true] .customize-dialog::backdrop { + background-color: rgba(0, 0, 0, 0.4); +} + #custom-links-edit-dialog { background: transparent; border: none; @@ -510,10 +534,6 @@ width: 100%; } -#custom-links-edit-dialog::backdrop { - background-color: rgba(255, 255, 255, .75); -} - #custom-links-edit { border: none; height: 100%;
diff --git a/chrome/browser/resources/local_ntp/local_ntp.html b/chrome/browser/resources/local_ntp/local_ntp.html index 318e0358..d663892 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.html +++ b/chrome/browser/resources/local_ntp/local_ntp.html
@@ -145,7 +145,7 @@ </div> </dialog> - <dialog id="bg-sel-menu"> + <dialog id="bg-sel-menu" class="customize-dialog"> <div id="bg-sel-title-bar"> <div id="bg-sel-back-circle" tabindex="0" role="button"> <div id="bg-sel-back"></div>
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js index f22f1e64..b6a121bc 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.js +++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -71,6 +71,8 @@ */ var CLASSES = { ALTERNATE_LOGO: 'alternate-logo', // Shows white logo if required by theme + // Applies styles to dialogs used in customization. + CUSTOMIZE_DIALOG: 'customize-dialog', DARK: 'dark', DEFAULT_THEME: 'default-theme', DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', @@ -93,7 +95,7 @@ // Vertically centers the most visited section for a non-Google provided page. NON_GOOGLE_PAGE: 'non-google-page', NON_WHITE_BG: 'non-white-bg', - RTL: 'rtl', // Right-to-left language text. + RTL: 'rtl', // Right-to-left language text. }; @@ -297,13 +299,20 @@ /** * Heuristic to determine whether a theme should be considered to be dark, so * the colors of various UI elements can be adjusted. + * + * The user theme/custom background will always take precedence over dark mode + * when considering darkness. Therefore, dark mode should only be checked if + * this is the default NTP. Dark mode is considered a dark theme if enabled. + * * @param {ThemeBackgroundInfo|undefined} info Theme background information. * @return {boolean} Whether the theme is dark. * @private */ function getIsThemeDark() { var info = getThemeBackgroundInfo(); - if (!info) { + // Only check for dark mode if this is the default NTP (i.e. no theme or + // custom background set). + if (!info || info.usingDefaultTheme && !info.customBackgroundConfigured) { // Dark mode is always considered a dark theme. return configData.isDarkModeEnabled; } @@ -1163,6 +1172,10 @@ clArgs.push('rtl=1'); } + if (configData.isDarkModeEnabled) { + clArgs.push('enableDarkMode=1'); + } + clArgs.push( 'addTitle=' + encodeURIComponent(configData.translatedStrings.addLinkTitle)); @@ -1196,6 +1209,7 @@ clIframe.src = 'chrome-search://most-visited/edit.html?' + clArgs.join('&'); let clIframeDialog = document.createElement('dialog'); clIframeDialog.id = IDS.CUSTOM_LINKS_EDIT_IFRAME_DIALOG; + clIframeDialog.classList.add(CLASSES.CUSTOMIZE_DIALOG); clIframeDialog.appendChild(clIframe); document.body.appendChild(clIframeDialog); }
diff --git a/chrome/browser/resources/local_ntp/voice.css b/chrome/browser/resources/local_ntp/voice.css index 89d321d..76c00da 100644 --- a/chrome/browser/resources/local_ntp/voice.css +++ b/chrome/browser/resources/local_ntp/voice.css
@@ -55,6 +55,10 @@ background-color: white; } +html[darkmode=true] .overlay-dialog::backdrop { + background-color: rgb(41, 42, 45); +} + /* The background element. */ .overlay, .overlay-hidden { @@ -66,6 +70,11 @@ z-index: 10000; } +html[darkmode=true] .overlay, +html[darkmode=true] .overlay-hidden { + background-color: rgb(41, 42, 45); +} + /* Full Page visible style for the background element. */ .overlay { opacity: 1; @@ -95,6 +104,10 @@ right: auto; } +html[darkmode=true] .close-button { + color: rgb(var(--GG200-rgb)); +} + .close-button:hover { opacity: .66; } @@ -159,6 +172,12 @@ transition: background-color 218ms, border 218ms, box-shadow 218ms; } +html[darkmode=true] .button { + background-color: rgb(var(--GG900-rgb)); + border-color: rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.3), 0 4px 8px 3px rgba(0, 0, 0, 0.15); +} + /* Button state when speech recognition is inactive. */ .overlay-hidden .button { opacity: 0; @@ -182,6 +201,10 @@ box-shadow: none; } +html[darkmode=true] .voice-rs .button { + background-color: rgb(var(--GR300-rgb)); +} + /* Vibrating input volume level. */ .level { background-color: var(--level_animation_color); @@ -198,6 +221,10 @@ width: 301px; } +html[darkmode=true] .level { + background-color: rgb(var(--GG700-rgb)); +} + /* Container for scaling and positioning of the button. */ .button-container { float: right; @@ -235,11 +262,19 @@ background-color: var(--dark_red); } +html[darkmode=true] .voice-rs .button:active { + background-color: rgb(223, 128, 119); +} + /* Style applied to the button when clicked. */ .button:active { background-color: var(--light_grey); } +html[darkmode=true] .button:active { + background-color: rgb(53, 54, 57); +} + /* TEXT */ /* Classes: * - voice-text - Text area style class @@ -315,11 +350,19 @@ color: var(--grey); } +html[darkmode=true] #voice-text-i { + color: rgb(var(--GG500-rgb)); +} + /* Final (high confidence) text. */ #voice-text-f { color: black; } +html[darkmode=true] #voice-text-f { + color: rgb(var(--GG200-rgb)); +} + /* Text area links. */ .voice-text-link { color: var(--text_link_color); @@ -330,6 +373,10 @@ text-decoration: underline; } +html[darkmode=true] .voice-text-link { + color: rgb(var(--GB300-rgb)); +} + /* Range of motion for the typing animation. */ @keyframes type { from { @@ -413,6 +460,10 @@ width: 24px; } +html[darkmode=true] .receiver { + background-color: rgb(var(--GG500-rgb)); +} + /* Part 2 of CSS-only microphone icon: the shell and stem wrapper element. * Positioned below the audio receiver element. */ .wrapper { @@ -438,6 +489,10 @@ z-index: 1; /* z-index is only used to specify position relative to stem. */ } +html[darkmode=true] .stem { + background-color: rgb(var(--GG500-rgb)); +} + /* Part 4 of CSS-only microphone icon: shell that holds the receiver. * Positioned below the audio receiver element and above the stem element. */ .shell { @@ -451,6 +506,10 @@ z-index: 0; /* z-index is only used to specify position relative to stem. */ } +html[darkmode=true] .shell { + border-color: rgb(var(--GG500-rgb)); +} + /* The .voice-ml style is applied when the UI is in * the 'listening for audio' state. */ .voice-ml .receiver, @@ -458,10 +517,19 @@ background-color: var(--listening_icon_color); } +html[darkmode=true] .voice-ml .receiver, +html[darkmode=true] .voice-ml .stem { + background-color: rgb(var(--GR300-rgb)); +} + .voice-ml .shell { border-color: var(--listening_icon_color); } +html[darkmode=true] .voice-ml .shell { + border-color: rgb(var(--GR300-rgb)); +} + /* The .voice-rs style is applied when the UI is in * the 'receiving speech' state. */ .voice-rs .receiver, @@ -469,6 +537,15 @@ background-color: var(--active_icon_color); } +html[darkmode=true] .voice-rs .receiver, +html[darkmode=true] .voice-rs .stem { + background-color: rgb(var(--GG200-rgb)); +} + .voice-rs .shell { border-color: var(--active_icon_color); } + +html[darkmode=true] .voice-rs .shell { + border-color: rgb(var(--GG200-rgb)); +}
diff --git a/chrome/browser/resources/management/management.html b/chrome/browser/resources/management/management.html index 8097cdbd..b6bedf3 100644 --- a/chrome/browser/resources/management/management.html +++ b/chrome/browser/resources/management/management.html
@@ -37,6 +37,11 @@ <ul id="reporting-info-list"></ul> </section> + <section id="browser-policies" hidden> + <h2 class="section-title">$i18n{browserReporting}</h2> + <ul id="browser-reporting-info-list"></ul> + </section> + <section id="extensions" hidden> <h2 class="section-title">$i18n{extensionReporting}</h2> <div id="extensions-installed">
diff --git a/chrome/browser/resources/management/management.js b/chrome/browser/resources/management/management.js index 0cd0ff1..f4e8f0a 100644 --- a/chrome/browser/resources/management/management.js +++ b/chrome/browser/resources/management/management.js
@@ -57,6 +57,22 @@ $('reporting-info-list').appendChild(element); } }); + // Show descriptions of the types of reporting in the |reportingSources| + // list. + this.browserProxy_.getBrowserReportingInfo().then(function( + reportingSources) { + if (reportingSources.length == 0) { + return; + } + + $('browser-policies').hidden = false; + + for (const id of reportingSources) { + const element = document.createElement('li'); + element.textContent = loadTimeData.getString(id); + $('browser-reporting-info-list').appendChild(element); + } + }); // Show names and permissions of |extensions| in a table. this.browserProxy_.getExtensions().then(function(extensions) { @@ -120,6 +136,11 @@ getReportingInfo() {} /** + * @return {!Promise<!Array<string>>} List of reporting info. + */ + getBrowserReportingInfo() {} + + /** * Each extension has a name and a list of permission messages. * @return {!Promise<!Array<!Extension>>} List of extensions. */ @@ -147,6 +168,11 @@ } /** @override */ + getBrowserReportingInfo() { + return cr.sendWithPromise('getBrowserReportingInfo'); + } + + /** @override */ getExtensions() { return cr.sendWithPromise('getExtensions'); }
diff --git a/chrome/browser/resources/md_downloads/manager.js b/chrome/browser/resources/md_downloads/manager.js index 65e3b1d..7983162 100644 --- a/chrome/browser/resources/md_downloads/manager.js +++ b/chrome/browser/resources/md_downloads/manager.js
@@ -126,15 +126,17 @@ */ insertItems_: function(index, items) { // Insert |items| at the given |index| via Array#splice(). - this.items_.splice.apply(this.items_, [index, 0].concat(items)); - this.updateHideDates_(index, index + items.length); - this.notifySplices('items_', [{ - index: index, - addedCount: items.length, - object: this.items_, - type: 'splice', - removed: [], - }]); + if (items.length > 0) { + this.items_.splice.apply(this.items_, [index, 0].concat(items)); + this.updateHideDates_(index, index + items.length); + this.notifySplices('items_', [{ + index: index, + addedCount: items.length, + object: this.items_, + type: 'splice', + removed: [], + }]); + } if (this.hasAttribute('loading')) { this.removeAttribute('loading');
diff --git a/chrome/browser/resources/md_extensions/detail_view.html b/chrome/browser/resources/md_extensions/detail_view.html index b4ed12f..fd79444f 100644 --- a/chrome/browser/resources/md_extensions/detail_view.html +++ b/chrome/browser/resources/md_extensions/detail_view.html
@@ -24,6 +24,7 @@ <link rel="import" href="navigation_helper.html"> <link rel="import" href="runtime_host_permissions.html"> <link rel="import" href="shared_style.html"> +<link rel="import" href="shared_vars.html"> <link rel="import" href="strings.html"> <link rel="import" href="toggle_row.html"> @@ -31,7 +32,7 @@ <template> <style include="iron-flex cr-shared-style cr-icons action-link paper-button-style shared-style"> :host { - --iron-icon-fill-color: var(--google-grey-refresh-700); + --iron-icon-fill-color: var(--cr-secondary-text-color); display: block; height: 100%; } @@ -53,6 +54,10 @@ color: var(--google-blue-500); } + :host-context([dark]) #enable-section .enabled-text { + color: var(--google-blue-refresh-300); + } + #icon { height: 24px; margin-inline-end: 12px; @@ -65,11 +70,6 @@ @apply --cr-title-text; } - #learn-more-link { - color: var(--google-blue-700); - text-decoration: none; - } - .section { @apply --cr-section; } @@ -102,27 +102,26 @@ } .inspectable-view { - color: var(--google-blue-700); height: 20px; width: auto; /* override the default button size of 24x24 */ } - .warning .action-button { + :host-context(html:not([dark])) .warning .action-button { background: white; color: var(--google-blue-500); } - #reload-button { + :host-context(html:not([dark])) #reload-button { color: var(--google-blue-500); } .warning span { - color: var(--google-red-700); + color: var(--error-color); flex: 1; } .warning-icon { - --iron-icon-fill-color: var(--google-red-700); + --iron-icon-fill-color: var(--error-color); flex-shrink: 0; height: 18px; margin-inline-end: 8px; @@ -180,7 +179,7 @@ <span id="name">[[data.name]]</span> </div> <div class="section continuation control-line" id="enable-section"> - <span class$="{{computeEnabledStyle_(data.state)}}"> + <span class$="[[computeEnabledStyle_(data.state)]]"> [[computeEnabledText_(data.state, '$i18nPolymer{itemOn}', '$i18nPolymer{itemOff}')]] </span> @@ -222,8 +221,7 @@ <iron-icon class="warning-icon" icon="cr:warning"></iron-icon> <span> $i18n{itemSuspiciousInstall} - <a target="_blank" id="learn-more-link" - href="$i18n{suspiciousInstallHelpUrl}"> + <a target="_blank" href="$i18n{suspiciousInstallHelpUrl}"> $i18n{learnMore} </a> </span>
diff --git a/chrome/browser/resources/md_extensions/error_page.html b/chrome/browser/resources/md_extensions/error_page.html index 80747fc6..04a4688 100644 --- a/chrome/browser/resources/md_extensions/error_page.html +++ b/chrome/browser/resources/md_extensions/error_page.html
@@ -34,11 +34,12 @@ } iron-icon[icon='cr:warning'] { + /* TODO(dbeam): find dark mode equivalent for this orange. */ --iron-icon-fill-color: var(--paper-orange-500); } iron-icon[icon='cr:error'] { - --iron-icon-fill-color: var(--paper-red-700); + --iron-icon-fill-color: var(--error-color); } .section {
diff --git a/chrome/browser/resources/md_extensions/host_permissions_toggle_list.html b/chrome/browser/resources/md_extensions/host_permissions_toggle_list.html index 8d5f710..56126ec 100644 --- a/chrome/browser/resources/md_extensions/host_permissions_toggle_list.html +++ b/chrome/browser/resources/md_extensions/host_permissions_toggle_list.html
@@ -20,11 +20,6 @@ margin-top: 12px; } - a[href] { - color: var(--google-blue-700); - text-decoration: none; - } - extensions-toggle-row { color: black; }
diff --git a/chrome/browser/resources/md_extensions/item.html b/chrome/browser/resources/md_extensions/item.html index be6dcbf..569b4c3 100644 --- a/chrome/browser/resources/md_extensions/item.html +++ b/chrome/browser/resources/md_extensions/item.html
@@ -14,6 +14,8 @@ <link rel="import" href="icons.html"> <link rel="import" href="item_behavior.html"> <link rel="import" href="item_util.html"> +<link rel="import" href="shared_style.html"> +<link rel="import" href="shared_vars.html"> <link rel="import" href="strings.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> @@ -23,8 +25,7 @@ <dom-module id="extensions-item"> <template> - <style include= - "iron-flex cr-hidden-style cr-icons action-link paper-button-style"> + <style include="iron-flex cr-hidden-style cr-icons action-link paper-button-style shared-style"> .bounded-text, .multiline-clippable-text, .clippable-flex-text { @@ -102,13 +103,13 @@ } #warnings { - color: var(--google-red-700); + color: var(--error-color); flex: 1; margin-bottom: 8px; } #error-icon { - --iron-icon-fill-color: var(--google-red-700); + --iron-icon-fill-color: var(--error-color); height: 18px; margin-inline-end: 4px; width: 18px; @@ -148,11 +149,6 @@ margin-inline-start: 8px; } - #learn-more-link { - color: var(--google-blue-700); - text-decoration: none; - } - #source-indicator { margin-inline-start: 24px; margin-top: 24px; @@ -184,12 +180,8 @@ }; } - .action-button { - color: var(--google-blue-500); - } - #errors-button { - color: var(--google-red-700); + color: var(--error-color); } #dev-reload-button-container { @@ -270,8 +262,7 @@ <span id="suspicious-warning" aria-describedby="a11yAssociation" hidden$="[[!data.disableReasons.suspiciousInstall]]"> $i18n{itemSuspiciousInstall} - <a target="_blank" id="learn-more-link" - href="$i18n{suspiciousInstallHelpUrl}"> + <a target="_blank" href="$i18n{suspiciousInstallHelpUrl}"> $i18n{learnMore} </a> </span>
diff --git a/chrome/browser/resources/md_extensions/manager.js b/chrome/browser/resources/md_extensions/manager.js index 8331782..9e2c0e9 100644 --- a/chrome/browser/resources/md_extensions/manager.js +++ b/chrome/browser/resources/md_extensions/manager.js
@@ -438,16 +438,14 @@ }, /** - * @param {!CustomEvent} e + * @param {!CustomEvent<!chrome.developerPrivate.LoadError>} e * @private */ onLoadError_: function(e) { - const loadError = - /** @type {!chrome.developerPrivate.LoadError} */ (e.detail); this.showLoadErrorDialog_ = true; this.async(() => { const dialog = this.$$('#load-error'); - dialog.loadError = loadError; + dialog.loadError = e.detail; dialog.show(); }); },
diff --git a/chrome/browser/resources/md_extensions/runtime_host_permissions.html b/chrome/browser/resources/md_extensions/runtime_host_permissions.html index 2d807a7af..9eaad24 100644 --- a/chrome/browser/resources/md_extensions/runtime_host_permissions.html +++ b/chrome/browser/resources/md_extensions/runtime_host_permissions.html
@@ -63,11 +63,6 @@ cr-radio-button.multi-row { align-items: normal; } - - a[href] { - color: var(--google-blue-700); - text-decoration: none; - } </style> <div id="permissions-mode"> <div id="section-heading">
diff --git a/chrome/browser/resources/md_extensions/shared_style.html b/chrome/browser/resources/md_extensions/shared_style.html index 2e216b6..b6f3208 100644 --- a/chrome/browser/resources/md_extensions/shared_style.html +++ b/chrome/browser/resources/md_extensions/shared_style.html
@@ -4,6 +4,11 @@ <dom-module id="shared-style"> <template> <style include="cr-shared-style"> + a[href] { + color: var(--cr-link-color); + text-decoration: none; + } + .page-container { height: 100%; overflow: overlay;
diff --git a/chrome/browser/resources/md_extensions/shared_vars.html b/chrome/browser/resources/md_extensions/shared_vars.html index 44c5c59..ad311071 100644 --- a/chrome/browser/resources/md_extensions/shared_vars.html +++ b/chrome/browser/resources/md_extensions/shared_vars.html
@@ -1,9 +1,19 @@ <link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> + <custom-style> <style is="custom-style"> html { + /* Note: error-color is used for many warnings. There's also an orange-y + * warning color in 1 place. */ + --error-color: var(--google-red-700); --separator-gap: 9px; } + + html[dark] { + --error-color: var(--google-red-refresh-300); + } </style> </custom-style>
diff --git a/chrome/browser/resources/md_extensions/sidebar.html b/chrome/browser/resources/md_extensions/sidebar.html index e4eb819..8aaf1ef 100644 --- a/chrome/browser/resources/md_extensions/sidebar.html +++ b/chrome/browser/resources/md_extensions/sidebar.html
@@ -11,7 +11,6 @@ <template> <style include="cr-icons"> :host { - --selected-color: var(--google-blue-700); --sidebar-inactive-color: #5a5a5a; color: var(--sidebar-inactive-color); display: flex; @@ -24,12 +23,11 @@ } :host-context([dark]) { - --selected-color: var(--google-blue-refresh-300); --sidebar-inactive-color: var(--cr-primary-text-color); } iron-selector .iron-selected { - color: var(--selected-color); + color: var(--cr-link-color); } #sectionMenu {
diff --git a/chrome/browser/resources/md_extensions/toolbar.js b/chrome/browser/resources/md_extensions/toolbar.js index 4fc7895..c9ee828 100644 --- a/chrome/browser/resources/md_extensions/toolbar.js +++ b/chrome/browser/resources/md_extensions/toolbar.js
@@ -91,11 +91,11 @@ }, /** - * @param {!CustomEvent} e + * @param {!CustomEvent<boolean>} e * @private */ onDevModeToggleChange_: function(e) { - this.delegate.setProfileInDevMode(/** @type {boolean} */ (e.detail)); + this.delegate.setProfileInDevMode(e.detail); chrome.metricsPrivate.recordUserAction( 'Options_ToggleDeveloperMode_' + (e.detail ? 'Enabled' : 'Disabled')); },
diff --git a/chrome/browser/resources/omnibox/omnibox_output.js b/chrome/browser/resources/omnibox/omnibox_output.js index ed12754..85a4a80 100644 --- a/chrome/browser/resources/omnibox/omnibox_output.js +++ b/chrome/browser/resources/omnibox/omnibox_output.js
@@ -638,7 +638,7 @@ /** @type {!Element} */ this.image_ = document.createElement('img'); - this.image_.classList.add('pair-item', 'image'); + this.image_.classList.add('pair-item'); this.container_.appendChild(this.image_); /** @type {!Element} */ @@ -655,6 +655,11 @@ this.answer_ = document.createElement('div'); this.answer_.classList.add('pair-item', 'answer'); this.container_.appendChild(this.answer_); + + /** @type {!Element} */ + this.imageUrl_ = document.createElement('a'); + this.imageUrl_.classList.add('pair-item', 'image-url'); + this.container_.appendChild(this.imageUrl_); } /** @param {string} imageData */ @@ -667,6 +672,8 @@ this.contents_.textContent = this.values_[1]; this.description_.textContent = this.values_[2]; this.answer_.textContent = this.values_[3]; + this.imageUrl_.textContent = this.values_[0]; + this.imageUrl_.href = this.values_[0]; } /** @override @return {string} */
diff --git a/chrome/browser/resources/omnibox/output_results_group.css b/chrome/browser/resources/omnibox/output_results_group.css index a2471d62..f125cc08 100644 --- a/chrome/browser/resources/omnibox/output_results_group.css +++ b/chrome/browser/resources/omnibox/output_results_group.css
@@ -115,6 +115,10 @@ color: blue; } +.header-contents-and-description .header-container :nth-child(3) { + color: orange; +} + .header-fill-and-inline .header-container :nth-child(2) { border: 1px solid; } @@ -157,6 +161,10 @@ color: orange; } +.cell-contents-and-description .pair-item.image-url { + font-size: .5rem; +} + .cell-fill-and-inline .pair-container { margin-inline-end: -1px; }
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js index c1aa135..f98dfc0a 100644 --- a/chrome/browser/resources/pdf/pdf_viewer.js +++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -1473,9 +1473,9 @@ this.saveData_(message.data); break; case 'consumeSaveToken': - const resolve = this.pendingTokens_.get(message.data.token); + const resolver = this.pendingTokens_.get(message.data.token); assert(this.pendingTokens_.delete(message.data.token)); - resolve(null); + resolver.resolve(null); break; } }
diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js index d49c6a6c..9a1fdc85 100644 --- a/chrome/browser/resources/print_preview/data/destination_store.js +++ b/chrome/browser/resources/print_preview/data/destination_store.js
@@ -1302,10 +1302,15 @@ if (this.autoSelectMatchingDestination_ && this.autoSelectMatchingDestination_.matchIdAndOrigin( eventDetail.destinationId, eventDetail.origin)) { - console.error( + console.warn( 'Failed to fetch last used printer caps: ' + eventDetail.destinationId); this.selectDefaultDestination_(); + } else { + // Log the failure + console.warn( + 'Failed to fetch printer capabilities for ' + + eventDetail.destinationId + ' with origin ' + eventDetail.origin); } }
diff --git a/chrome/browser/resources/print_preview/new/app.js b/chrome/browser/resources/print_preview/new/app.js index 94c76d494..030cdd3 100644 --- a/chrome/browser/resources/print_preview/new/app.js +++ b/chrome/browser/resources/print_preview/new/app.js
@@ -392,14 +392,18 @@ assert(this.cloudPrintInterface_).getEventTarget(), cloudprint.CloudPrintInterfaceEventType.SUBMIT_DONE, this.close_.bind(this)); + [cloudprint.CloudPrintInterfaceEventType.SEARCH_FAILED, - cloudprint.CloudPrintInterfaceEventType.SUBMIT_FAILED, cloudprint.CloudPrintInterfaceEventType.PRINTER_FAILED, ].forEach(eventType => { this.tracker_.add( assert(this.cloudPrintInterface_).getEventTarget(), eventType, - this.onCloudPrintError_.bind(this)); + this.checkCloudPrintStatus_.bind(this)); }); + this.tracker_.add( + assert(this.cloudPrintInterface_).getEventTarget(), + cloudprint.CloudPrintInterfaceEventType.SUBMIT_FAILED, + this.onCloudPrintError_.bind(this)); this.destinationStore_.setCloudPrintInterface(this.cloudPrintInterface_); this.invitationStore_.setCloudPrintInterface(this.cloudPrintInterface_); @@ -443,11 +447,12 @@ }, /** - * @param {!CustomEvent} e Event containing the sticky settings string. + * @param {!CustomEvent<string>} e Event containing the sticky settings + * string. * @private */ onSaveStickySettings_: function(e) { - this.nativeLayer_.saveAppState(/** @type {string} */ (e.detail)); + this.nativeLayer_.saveAppState(e.detail); }, /** @private */ @@ -506,14 +511,13 @@ }, /** - * @param {!CustomEvent} e The event containing the new validity. + * @param {!CustomEvent<boolean>} e The event containing the new validity. * @private */ onSettingValidChanged_: function(e) { this.$.state.transitTo( - /** @type {boolean} */ (e.detail) ? - print_preview_new.State.READY : - print_preview_new.State.INVALID_TICKET); + e.detail ? print_preview_new.State.READY : + print_preview_new.State.INVALID_TICKET); }, /** @private */ @@ -607,24 +611,37 @@ }, /** + * Updates the cloud print status to NOT_SIGNED_IN if there is an + * authentication error. + * @param {!CustomEvent<{status: number}>} event Contains the error status + * @private + */ + checkCloudPrintStatus_: function(event) { + if (event.detail.status != 403 || this.isInAppKioskMode_) { + return; + } + + // Should not have sent a message to Cloud Print if cloud print is + // disabled. + assert(this.cloudPrintState_ !== print_preview.CloudPrintState.DISABLED); + this.cloudPrintState_ = print_preview.CloudPrintState.NOT_SIGNED_IN; + console.warn('Google Cloud Print Error: HTTP status 403'); + }, + + /** * Called when there was an error communicating with Google Cloud print. * Displays an error message in the print header. * @param {!CustomEvent} event Contains the error message. * @private */ onCloudPrintError_: function(event) { - if (event.detail.status == 0) { - return; // Ignore, the system does not have internet connectivity. + this.checkCloudPrintStatus_(event); + if (event.detail.status == 0 || + (event.detail.status == 403 && !this.isInAppKioskMode_)) { + return; // No internet connectivity or handled by checkCloudPrintStatus_. } - if (event.detail.status == 403 && !this.isInAppKioskMode_) { - // Should not have sent a message to Cloud Print if cloud print is - // disabled. - assert(this.cloudPrintState_ !== print_preview.CloudPrintState.DISABLED); - this.cloudPrintState_ = print_preview.CloudPrintState.NOT_SIGNED_IN; - } else { - this.errorMessage_ = event.detail.message; - this.$.state.transitTo(print_preview_new.State.FATAL_ERROR); - } + this.errorMessage_ = event.detail.message; + this.$.state.transitTo(print_preview_new.State.FATAL_ERROR); if (event.detail.status == 200) { console.error( 'Google Cloud Print Error: ' + @@ -691,11 +708,11 @@ }, /** - * @param {!CustomEvent} e Contains the new preview request ID. + * @param {!CustomEvent<number>} e Contains the new preview request ID. * @private */ onPreviewStart_: function(e) { - this.$.documentInfo.inFlightRequestId = /** @type {number} */ (e.detail); + this.$.documentInfo.inFlightRequestId = e.detail; }, // <if expr="chromeos">
diff --git a/chrome/browser/resources/print_preview/new/destination_dialog.js b/chrome/browser/resources/print_preview/new/destination_dialog.js index 369fcf9b..b5d3299 100644 --- a/chrome/browser/resources/print_preview/new/destination_dialog.js +++ b/chrome/browser/resources/print_preview/new/destination_dialog.js
@@ -186,13 +186,12 @@ }, /** - * @param {!CustomEvent} e Event containing the selected destination list item - * element. + * @param {!CustomEvent<!PrintPreviewDestinationListItemElement>} e Event + * containing the selected destination list item element. * @private */ onDestinationSelected_: function(e) { - const listItem = - /** @type {!PrintPreviewDestinationListItemElement} */ (e.detail); + const listItem = e.detail; const destination = listItem.destination; // ChromeOS local destinations that don't have capabilities need to be
diff --git a/chrome/browser/resources/print_preview/new/destination_select.html b/chrome/browser/resources/print_preview/new/destination_select.html index 4d657fd..e601bfea 100644 --- a/chrome/browser/resources/print_preview/new/destination_select.html +++ b/chrome/browser/resources/print_preview/new/destination_select.html
@@ -17,18 +17,28 @@ <dom-module id="print-preview-destination-select"> <template> <style include="print-preview-shared md-select cr-hidden-style"> + :host { + --printer-icon-side-padding: 4px; + --printer-icon-size: 20px; + } + .md-select { + background-position: var(--printer-icon-side-padding) center, + calc(100% - var(--md-select-side-padding)) center; + background-size: var(--printer-icon-size), var(--md-arrow-width); padding-inline-start: 32px; --md-select-width: calc(100% - 4px); } + + :host-context([dir=rtl]) .md-select { + background-position-x: calc(100% - var(--printer-icon-side-padding)), + var(--md-select-side-padding); + } </style> <select class="md-select" aria-label$="[[i18n(destinationLabel)]]" - style="background: - [[getIconImage_(destination.icon, noDestinationsFound)]] - 4px center/20px no-repeat, - url(chrome://resources/images/arrow_down.svg) - calc(100% - 8px) center/10px no-repeat; - background-color: var(--google-grey-100);" + style="background-image: + [[getIconImage_(destination.icon, noDestinationsFound)]], + url(chrome://resources/images/arrow_down.svg);" disabled$="[[disabled]]" value="{{selectedValue::change}}"> <option value="noDestinations" hidden$="[[!noDestinationsFound]]"
diff --git a/chrome/browser/resources/print_preview/new/margin_control_container.js b/chrome/browser/resources/print_preview/new/margin_control_container.js index 21dccbd..ac4a7123 100644 --- a/chrome/browser/resources/print_preview/new/margin_control_container.js +++ b/chrome/browser/resources/print_preview/new/margin_control_container.js
@@ -436,11 +436,11 @@ }, /** - * @param {!CustomEvent} e Event containing the new textbox value. + * @param {!CustomEvent<string>} e Event containing the new textbox value. * @private */ onTextChange_: function(e) { - const marginValue = this.parseValueToPts_(/** @type {string} */ (e.detail)); + const marginValue = this.parseValueToPts_(e.detail); const control = /** @type {!PrintPreviewMarginControlElement} */ (e.target); if (marginValue == null) {
diff --git a/chrome/browser/resources/print_preview/new/number_settings_section.js b/chrome/browser/resources/print_preview/new/number_settings_section.js index 560c792..1a1b4c8 100644 --- a/chrome/browser/resources/print_preview/new/number_settings_section.js +++ b/chrome/browser/resources/print_preview/new/number_settings_section.js
@@ -55,11 +55,11 @@ }, /** - * @param {!CustomEvent} e Contains the new input value. + * @param {!CustomEvent<string>} e Contains the new input value. * @private */ onInputChange_: function(e) { - this.inputString_ = /** @type {string} */ (e.detail); + this.inputString_ = e.detail; }, /**
diff --git a/chrome/browser/resources/print_preview/new/pages_settings.js b/chrome/browser/resources/print_preview/new/pages_settings.js index bbc06f28..e41820f 100644 --- a/chrome/browser/resources/print_preview/new/pages_settings.js +++ b/chrome/browser/resources/print_preview/new/pages_settings.js
@@ -126,11 +126,11 @@ }, /** - * @param {!CustomEvent} e Contains the new input value. + * @param {!CustomEvent<string>} e Contains the new input value. * @private */ onInputChange_: function(e) { - this.inputString_ = /** @type {string} */ (e.detail); + this.inputString_ = e.detail; }, /**
diff --git a/chrome/browser/resources/print_preview/new/preview_area.js b/chrome/browser/resources/print_preview/new/preview_area.js index a2f4ec6..c7d2c51 100644 --- a/chrome/browser/resources/print_preview/new/preview_area.js +++ b/chrome/browser/resources/print_preview/new/preview_area.js
@@ -505,8 +505,8 @@ }, /** - * @param {!CustomEvent} e Contains information about where the plugin - * should scroll to. + * @param {!CustomEvent<{x: number, y: number}>} e Contains information about + * where the plugin should scroll to. * @private */ onTextFocusPosition_: function(e) { @@ -519,7 +519,7 @@ this.scrollTop = 0; this.scrollLeft = 0; - const position = /** @type {{ x: number, y: number }} */ (e.detail); + const position = e.detail; if (position.x === 0 && position.y === 0) { return; }
diff --git a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js index db8be8b..571e5d7 100644 --- a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js +++ b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js
@@ -225,12 +225,11 @@ }, /** - * @param {!CustomEvent} e + * @param {!CustomEvent<boolean>} e * @private */ toggleStartupSoundEnabled_: function(e) { - const checked = /** @type {boolean} */ (e.detail); - chrome.send('setStartupSoundEnabled', [checked]); + chrome.send('setStartupSoundEnabled', [e.detail]); }, /**
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.js b/chrome/browser/resources/settings/controls/settings_toggle_button.js index 62d26d4..e7de425 100644 --- a/chrome/browser/resources/settings/controls/settings_toggle_button.js +++ b/chrome/browser/resources/settings/controls/settings_toggle_button.js
@@ -85,11 +85,11 @@ }, /** - * @param {!CustomEvent} e + * @param {!CustomEvent<boolean>} e * @private */ onChange_: function(e) { - this.checked = /** @type {boolean} */ (e.detail); + this.checked = e.detail; this.notifyChangedByUserInteraction(); }, });
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_browser_proxy.js b/chrome/browser/resources/settings/google_assistant_page/google_assistant_browser_proxy.js index 0e4cd58..6389e71 100644 --- a/chrome/browser/resources/settings/google_assistant_page/google_assistant_browser_proxy.js +++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_browser_proxy.js
@@ -10,18 +10,6 @@ cr.define('settings', function() { /** @interface */ class GoogleAssistantBrowserProxy { - /** - * Enables or disables the Google Assistant. - * @param {boolean} enabled - */ - setGoogleAssistantEnabled(enabled) {} - - /** - * Enables or disables screen context for the Google Assistant. - * @param {boolean} enabled - */ - setGoogleAssistantContextEnabled(enabled) {} - /** Launches into the Google Assistant app settings. */ launchGoogleAssistantSettings() {} @@ -35,16 +23,6 @@ /** @implements {settings.GoogleAssistantBrowserProxy} */ class GoogleAssistantBrowserProxyImpl { /** @override */ - setGoogleAssistantEnabled(enabled) { - chrome.send('setGoogleAssistantEnabled', [enabled]); - } - - /** @override */ - setGoogleAssistantContextEnabled(enabled) { - chrome.send('setGoogleAssistantContextEnabled', [enabled]); - } - - /** @override */ showGoogleAssistantSettings() { chrome.send('showGoogleAssistantSettings'); }
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html index 13c674fc..57fe166 100644 --- a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html +++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
@@ -19,16 +19,14 @@ class="first primary-toggle" pref="{{prefs.settings.voice_interaction.enabled}}" label="[[getAssistantOnOffLabel_( - prefs.settings.voice_interaction.enabled.value)]]" - on-change="onGoogleAssistantEnableChange_"> + prefs.settings.voice_interaction.enabled.value)]]"> </settings-toggle-button> <template is="dom-if" if="[[prefs.settings.voice_interaction.enabled.value]]"> <settings-toggle-button id="googleAssistantContextEnable" pref="{{prefs.settings.voice_interaction.context.enabled}}" label="$i18n{googleAssistantEnableContext}" - sub-label="$i18n{googleAssistantEnableContextDescription}" - on-change="onGoogleAssistantContextEnableChange_"> + sub-label="$i18n{googleAssistantEnableContextDescription}"> </settings-toggle-button> <template is="dom-if" if="[[assistantFeatureEnabled_]]"> <settings-toggle-button id="googleAssistantHotwordEnable"
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js index fffae918..7aaa74f 100644 --- a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js +++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js
@@ -97,18 +97,6 @@ }, /** @private */ - onGoogleAssistantEnableChange_: function() { - this.browserProxy_.setGoogleAssistantEnabled( - !!this.getPref('settings.voice_interaction.enabled.value')); - }, - - /** @private */ - onGoogleAssistantContextEnableChange_: function() { - this.browserProxy_.setGoogleAssistantContextEnabled( - !!this.getPref('settings.voice_interaction.context.enabled.value')); - }, - - /** @private */ onGoogleAssistantSettingsTapped_: function() { this.browserProxy_.showGoogleAssistantSettings(); },
diff --git a/chrome/browser/resources/settings/languages_page/add_languages_dialog.js b/chrome/browser/resources/settings/languages_page/add_languages_dialog.js index 30527e2..9d498bb4 100644 --- a/chrome/browser/resources/settings/languages_page/add_languages_dialog.js +++ b/chrome/browser/resources/settings/languages_page/add_languages_dialog.js
@@ -68,11 +68,11 @@ }, /** - * @param {!CustomEvent} e + * @param {!CustomEvent<string>} e * @private */ onSearchChanged_: function(e) { - this.filterValue_ = /** @type {string} */ (e.detail); + this.filterValue_ = e.detail; }, /**
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html index 35d12be..aa08477a7 100644 --- a/chrome/browser/resources/settings/settings_menu/settings_menu.html +++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -40,7 +40,7 @@ } iron-icon { - --iron-icon-fill-color: var(--settings-nav-item-color); + --iron-icon-fill-color: var(--settings-nav-icon-color); margin-inline-end: 24px; pointer-events: none; vertical-align: top;
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage.html b/chrome/browser/resources/settings/settings_page/settings_subpage.html index 87853ffd..b6ab9f01 100644 --- a/chrome/browser/resources/settings/settings_page/settings_subpage.html +++ b/chrome/browser/resources/settings/settings_page/settings_subpage.html
@@ -55,7 +55,6 @@ } h1 { - color: var(--google-grey-refresh-700); flex: 1; /* Push other items to the end. */ @apply --cr-title-text; }
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html index 0220524b..d383b13 100644 --- a/chrome/browser/resources/settings/settings_shared_css.html +++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -20,7 +20,7 @@ h2 { align-items: center; align-self: flex-start; - color: var(--google-grey-refresh-700); + color: var(--cr-secondary-text-color); display: flex; font-size: inherit; font-weight: 500;
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js index c0f76f1dd..1280113 100644 --- a/chrome/browser/resources/settings/settings_ui/settings_ui.js +++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -227,12 +227,11 @@ }, /** - * @param {!CustomEvent} e + * @param {!CustomEvent<string>} e * @private */ onRefreshPref_: function(e) { - const prefName = /** @type {string} */ (e.detail); - return /** @type {SettingsPrefsElement} */ (this.$.prefs).refresh(prefName); + return /** @type {SettingsPrefsElement} */ (this.$.prefs).refresh(e.detail); }, /**
diff --git a/chrome/browser/resources/settings/settings_vars_css.html b/chrome/browser/resources/settings/settings_vars_css.html index 2f711ea..333e86d 100644 --- a/chrome/browser/resources/settings/settings_vars_css.html +++ b/chrome/browser/resources/settings/settings_vars_css.html
@@ -28,6 +28,7 @@ padding-top: 0; } + /* No --settings-nav-icon-color needed in light mode. */ --settings-nav-item-color: var(--google-grey-refresh-700); --settings-page-vertical-margin: 21px; @@ -40,9 +41,6 @@ --settings-separator-height: var(--cr-separator-height); --settings-separator-line: var(--cr-separator-line); - --settings-title-bar-color: rgb(255, 255, 255); - --settings-title-search-color: rgb(192, 199, 205); - /* Spacing between a control (e.g. checkbox) and its label. */ --settings-control-label-spacing: 20px; @@ -59,6 +57,9 @@ } html[dark] { + --iron-icon-fill-color: var(--google-grey-refresh-500); + --settings-error-color: var(--google-red-refresh-300); + --settings-nav-icon-color: var(--google-grey-refresh-500); --settings-nav-item-color: var(--cr-primary-text-color); } </style>
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.js b/chrome/browser/resources/settings/site_settings/all_sites.js index 57171e0..a904667 100644 --- a/chrome/browser/resources/settings/site_settings/all_sites.js +++ b/chrome/browser/resources/settings/site_settings/all_sites.js
@@ -139,7 +139,6 @@ } }, 500); }); - this.populateList_(); }, /** @override */ @@ -152,6 +151,21 @@ }, /** + * Reload the site list when the all sites page is visited. + * + * settings.RouteObserverBehavior + * @param {!settings.Route} currentRoute + * @protected + */ + currentRouteChanged: function(currentRoute) { + settings.GlobalScrollTargetBehaviorImpl.currentRouteChanged.call( + this, currentRoute); + if (currentRoute == settings.routes.SITE_SETTINGS_ALL) { + this.populateList_(); + } + }, + + /** * Retrieves a list of all known sites with site details. * @private */ @@ -185,30 +199,7 @@ const newMap = /** @type {!Map<string, !SiteGroup>} */ (new Map(this.siteGroupMap)); list.forEach(storageSiteGroup => { - if (newMap.has(storageSiteGroup.etldPlus1)) { - const siteGroup = newMap.get(storageSiteGroup.etldPlus1); - const storageOriginInfoMap = new Map(); - - siteGroup.numCookies = storageSiteGroup.numCookies; - storageSiteGroup.origins.forEach( - originInfo => - storageOriginInfoMap.set(originInfo.origin, originInfo)); - - // If there is an overlapping origin, update the original - // |originInfo|. - siteGroup.origins.forEach(originInfo => { - if (storageOriginInfoMap.has(originInfo.origin)) { - Object.assign( - originInfo, storageOriginInfoMap.get(originInfo.origin)); - storageOriginInfoMap.delete(originInfo.origin); - } - }); - // Otherwise, add it to the list. - storageOriginInfoMap.forEach( - originInfo => siteGroup.origins.push(originInfo)); - } else { - newMap.set(storageSiteGroup.etldPlus1, storageSiteGroup); - } + newMap.set(storageSiteGroup.etldPlus1, storageSiteGroup); }); this.siteGroupMap = newMap; },
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html index 730957b..6029e86 100644 --- a/chrome/browser/resources/settings/site_settings/site_details.html +++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -202,8 +202,7 @@ </div> </template> <website-usage-private-api id="usageApi" - website-data-usage="{{storedData_}}" - website-storage-type="{{storageType_}}"> + website-data-usage="{{storedData_}}"> </website-usage-private-api> </template> <script src="site_details.js"></script>
diff --git a/chrome/browser/resources/settings/site_settings/site_details.js b/chrome/browser/resources/settings/site_settings/site_details.js index 95474bf..64a8fdcc 100644 --- a/chrome/browser/resources/settings/site_settings/site_details.js +++ b/chrome/browser/resources/settings/site_settings/site_details.js
@@ -55,12 +55,6 @@ return loadTimeData.getBoolean('enableSiteSettings'); }, }, - - /** - * The type of storage for the origin. - * @private - */ - storageType_: Number, }, listeners: { @@ -235,8 +229,7 @@ // Since usage is only shown when "Site Settings" is enabled, don't // clear it when it's not shown. if (this.enableSiteSettings_ && this.storedData_ != '') { - this.$.usageApi.clearUsage( - this.toUrl(this.origin).href, this.storageType_); + this.$.usageApi.clearUsage(this.toUrl(this.origin).href); } this.onCloseDialog_(e);
diff --git a/chrome/browser/resources/settings/site_settings/website_usage_private_api.js b/chrome/browser/resources/settings/site_settings/website_usage_private_api.js index cae659c..23720b0 100644 --- a/chrome/browser/resources/settings/site_settings/website_usage_private_api.js +++ b/chrome/browser/resources/settings/site_settings/website_usage_private_api.js
@@ -16,14 +16,6 @@ type: String, notify: true, }, - - /** - * The type of data used by the given website. - */ - websiteStorageType: { - type: Number, - notify: true, - }, }, /** @override */ @@ -38,10 +30,9 @@ /** * @param {string} origin - * @param {number} type */ - clearUsage: function(origin, type) { - settings.WebsiteUsagePrivateApi.clearUsage(origin, type); + clearUsage: function(origin) { + settings.WebsiteUsagePrivateApi.clearUsage(origin); }, /** @param {string} origin */ @@ -84,9 +75,8 @@ * @param {string} host The host that the usage was fetched for. * @param {string} usage The string showing how much data the given host * is using. - * @param {number} type The storage type. */ - const returnUsageTotal = function(host, usage, type) { + const returnUsageTotal = function(host, usage) { const instance = settings.WebsiteUsagePrivateApi.websiteUsagePolymerInstance; if (instance == null) { @@ -95,24 +85,15 @@ if (hostName == host) { instance.websiteDataUsage = usage; - instance.websiteStorageType = type; } }; /** * Deletes the storage being used for a given origin. * @param {string} origin The origin to delete storage for. - * @param {number} type The type of storage to delete. */ - const clearUsage = function(origin, type) { - chrome.send('clearUsage', [origin, type]); - }; - - /** - * Callback for when the usage has been cleared. - * @param {string} origin The origin that the usage was fetched for. - */ - const onUsageCleared = function(origin) { + const clearUsage = function(origin) { + chrome.send('clearUsage', [origin]); const instance = settings.WebsiteUsagePrivateApi.websiteUsagePolymerInstance; if (instance == null) { @@ -127,6 +108,5 @@ fetchUsageTotal: fetchUsageTotal, returnUsageTotal: returnUsageTotal, clearUsage: clearUsage, - onUsageCleared: onUsageCleared, }; });
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index 79395b0..39785c8 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -17,10 +17,32 @@ deps = [ "//chrome/app:generated_resources", + "//chrome/common", + "//chrome/common:constants", + "//chrome/common/safe_browsing:file_type_policies", + "//components/browser_sync", "//components/chrome_cleaner/public/interfaces", + "//components/data_use_measurement/core", + "//components/keyed_service/content", + "//components/language/core/browser", + "//components/password_manager/core/browser", + "//components/password_manager/core/browser:hash_password_manager", + "//components/pref_registry", + "//components/resources:components_resources_grit", + "//components/safe_browsing:features", + "//components/safe_browsing:ping_manager", + "//components/safe_browsing/browser:referrer_chain_provider", "//components/safe_browsing/common:interfaces", + "//components/safe_browsing/db:database_manager", + "//components/safe_browsing/db:v4_local_database_manager", + "//components/safe_browsing/web_ui", + "//components/search_engines", + "//components/sessions", + "//components/url_formatter", "//mojo/public/cpp/platform", "//mojo/public/cpp/system", + "//services/identity/public/cpp", + "//services/preferences/public/cpp", ] if (enable_extensions) { @@ -67,7 +89,10 @@ "settings_reset_prompt/settings_reset_prompt_util_win.cc", "settings_reset_prompt/settings_reset_prompt_util_win.h", ] - deps += [ "//components/keep_alive_registry" ] + deps += [ + "//components/keep_alive_registry", + "//extensions/browser", + ] } if (is_chrome_branded && is_win) { @@ -217,7 +242,10 @@ ] deps += [ ":advanced_protection", + "//chrome/common/safe_browsing:archive_analyzer_results", + "//chrome/common/safe_browsing:binary_feature_extractor", "//chrome/common/safe_browsing:disk_image_type_sniffer_mac", + "//chrome/common/safe_browsing:download_type_util", "//chrome/services/file_util/public/cpp", "//components/content_settings/core/browser:browser", "//components/language/core/common:common",
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc index 70ec786..5ac2654 100644 --- a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc +++ b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
@@ -8,7 +8,6 @@ #include "base/metrics/histogram_macros.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h" -#include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/common/safe_browsing_prefs.h" @@ -16,6 +15,7 @@ #include "content/public/browser/browser_thread.h" #include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/oauth2_id_token_decoder.h" +#include "services/identity/public/cpp/accounts_mutator.h" #include "services/identity/public/cpp/primary_account_access_token_fetcher.h" using content::BrowserThread; @@ -38,7 +38,6 @@ : profile_(profile), identity_manager_(nullptr), access_token_fetcher_(nullptr), - account_tracker_service_(nullptr), is_under_advanced_protection_(false), minimum_delay_(kMinimumRefreshDelay) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -51,8 +50,6 @@ void AdvancedProtectionStatusManager::Initialize() { identity_manager_ = IdentityManagerFactory::GetForProfile(profile_); - account_tracker_service_ = - AccountTrackerServiceFactory::GetForProfile(profile_); SubscribeToSigninEvents(); } @@ -88,12 +85,10 @@ AdvancedProtectionStatusManager::~AdvancedProtectionStatusManager() {} void AdvancedProtectionStatusManager::SubscribeToSigninEvents() { - AccountTrackerServiceFactory::GetForProfile(profile_)->AddObserver(this); IdentityManagerFactory::GetForProfile(profile_)->AddObserver(this); } void AdvancedProtectionStatusManager::UnsubscribeFromSigninEvents() { - AccountTrackerServiceFactory::GetForProfile(profile_)->RemoveObserver(this); IdentityManagerFactory::GetForProfile(profile_)->RemoveObserver(this); } @@ -117,7 +112,7 @@ } } -void AdvancedProtectionStatusManager::OnAccountRemoved( +void AdvancedProtectionStatusManager::OnAccountRemovedWithInfo( const AccountInfo& info) { if (profile_->IsOffTheRecord()) return; @@ -267,8 +262,9 @@ // This also triggers |OnAccountUpdated()|. if (is_under_advanced_protection_ != service_flags.is_under_advanced_protection) { - account_tracker_service_->SetIsAdvancedProtectionAccount( - GetPrimaryAccountId(), service_flags.is_under_advanced_protection); + identity_manager_->GetAccountsMutator()->UpdateAccountInfo( + GetPrimaryAccountId(), false, + service_flags.is_under_advanced_protection); } else if (service_flags.is_under_advanced_protection) { OnAdvancedProtectionEnabled(); } else { @@ -281,7 +277,6 @@ const base::TimeDelta& min_delay) : profile_(profile), identity_manager_(nullptr), - account_tracker_service_(nullptr), is_under_advanced_protection_(false), minimum_delay_(min_delay) { if (profile_->IsOffTheRecord())
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager.h b/chrome/browser/safe_browsing/advanced_protection_status_manager.h index e4285a1..abaf42f 100644 --- a/chrome/browser/safe_browsing/advanced_protection_status_manager.h +++ b/chrome/browser/safe_browsing/advanced_protection_status_manager.h
@@ -7,7 +7,7 @@ #include "base/timer/timer.h" #include "components/keyed_service/core/keyed_service.h" -#include "components/signin/core/browser/account_tracker_service.h" +#include "components/signin/core/browser/account_info.h" #include "services/identity/public/cpp/access_token_info.h" #include "services/identity/public/cpp/identity_manager.h" @@ -27,7 +27,6 @@ // of its original profile. class AdvancedProtectionStatusManager : public KeyedService, - public AccountTrackerService::Observer, public identity::IdentityManager::Observer { public: explicit AdvancedProtectionStatusManager(Profile* profile); @@ -82,13 +81,11 @@ // Subscribes from sign-in events. void UnsubscribeFromSigninEvents(); - // AccountTrackerService::Observer implementations. - void OnAccountUpdated(const AccountInfo& info) override; - void OnAccountRemoved(const AccountInfo& info) override; - // IdentityManager::Observer implementations. void OnPrimaryAccountSet(const AccountInfo& account_info) override; void OnPrimaryAccountCleared(const AccountInfo& account_info) override; + void OnAccountUpdated(const AccountInfo& info) override; + void OnAccountRemovedWithInfo(const AccountInfo& info) override; void OnAdvancedProtectionEnabled();
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.h b/chrome/browser/safe_browsing/client_side_detection_host.h index 5adff52..e2376a6 100644 --- a/chrome/browser/safe_browsing/client_side_detection_host.h +++ b/chrome/browser/safe_browsing/client_side_detection_host.h
@@ -82,7 +82,7 @@ virtual void OnMalwarePreClassificationDone(bool should_classify); private: - friend class ClientSideDetectionHostTest; + friend class ClientSideDetectionHostTestBase; class ShouldClassifyUrlRequest; friend class ShouldClassifyUrlRequest;
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc index 0777311..7190a04 100644 --- a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc +++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
@@ -176,14 +176,6 @@ DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager); }; -class MockTestingProfile : public TestingProfile { - public: - MockTestingProfile() {} - ~MockTestingProfile() override {} - - MOCK_CONST_METHOD0(IsOffTheRecord, bool()); -}; - class MockBrowserFeatureExtractor : public BrowserFeatureExtractor { public: explicit MockBrowserFeatureExtractor( @@ -245,10 +237,13 @@ DISALLOW_COPY_AND_ASSIGN(FakePhishingDetector); }; -class ClientSideDetectionHostTest : public ChromeRenderViewHostTestHarness { +class ClientSideDetectionHostTestBase : public ChromeRenderViewHostTestHarness { public: typedef security_interstitials::UnsafeResource UnsafeResource; + explicit ClientSideDetectionHostTestBase(bool is_incognito) + : is_incognito_(is_incognito) {} + void InitTestApi() { service_manager::InterfaceProvider* remote_interfaces = web_contents()->GetMainFrame()->GetRemoteInterfaces(); @@ -263,6 +258,14 @@ void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); + + if (is_incognito_) { + auto incognito_web_contents = + content::WebContentsTester::CreateTestWebContents( + profile()->GetOffTheRecordProfile(), nullptr); + SetContents(std::move(incognito_web_contents)); + } + InitTestApi(); // Inject service classes. @@ -270,6 +273,7 @@ database_manager_ = new StrictMock<MockSafeBrowsingDatabaseManager>(); ui_manager_ = new StrictMock<MockSafeBrowsingUIManager>( SafeBrowsingService::CreateSafeBrowsingService()); + csd_host_ = ClientSideDetectionHost::Create(web_contents()); csd_host_->set_client_side_detection_service(csd_service_.get()); csd_host_->set_safe_browsing_managers(ui_manager_.get(), @@ -287,15 +291,8 @@ database_manager_ = NULL; ui_manager_ = NULL; base::RunLoop().RunUntilIdle(); - ChromeRenderViewHostTestHarness::TearDown(); - } - content::BrowserContext* CreateBrowserContext() override { - // Set custom profile object so that we can mock calls to IsOffTheRecord. - // This needs to happen before we call the parent SetUp() function. We use - // a nice mock because other parts of the code are calling IsOffTheRecord. - mock_profile_ = new NiceMock<MockTestingProfile>(); - return mock_profile_; + ChromeRenderViewHostTestHarness::TearDown(); } void PhishingDetectionDone(const std::string& verdict_str) { @@ -314,7 +311,6 @@ void ExpectPreClassificationChecks(const GURL& url, const bool* is_private, - const bool* is_incognito, const bool* match_csd_whitelist, const bool* get_valid_cached_result, const bool* is_in_cache, @@ -324,10 +320,6 @@ EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_)) .WillOnce(Return(*is_private)); } - if (is_incognito) { - EXPECT_CALL(*mock_profile_, IsOffTheRecord()) - .WillRepeatedly(Return(*is_incognito)); - } if (match_csd_whitelist) { EXPECT_CALL(*database_manager_.get(), CheckCsdWhitelistUrl(url, _)) .WillOnce(Return(*match_csd_whitelist ? AsyncMatch::MATCH @@ -357,7 +349,6 @@ EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get())); EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get())); EXPECT_TRUE(Mock::VerifyAndClear(database_manager_.get())); - EXPECT_TRUE(Mock::VerifyAndClear(mock_profile_)); } void SetFeatureExtractor(BrowserFeatureExtractor* extractor) { @@ -479,8 +470,21 @@ std::unique_ptr<StrictMock<MockClientSideDetectionService>> csd_service_; scoped_refptr<StrictMock<MockSafeBrowsingUIManager> > ui_manager_; scoped_refptr<StrictMock<MockSafeBrowsingDatabaseManager> > database_manager_; - MockTestingProfile* mock_profile_; // We don't own this object FakePhishingDetector fake_phishing_detector_; + const bool is_incognito_; +}; + +class ClientSideDetectionHostTest : public ClientSideDetectionHostTestBase { + public: + ClientSideDetectionHostTest() + : ClientSideDetectionHostTestBase(false /*is_incognito*/) {} +}; + +class ClientSideDetectionHostIncognitoTest + : public ClientSideDetectionHostTestBase { + public: + ClientSideDetectionHostIncognitoTest() + : ClientSideDetectionHostTestBase(true /*is_incognito*/) {} }; TEST_F(ClientSideDetectionHostTest, PhishingDetectionDoneInvalidVerdict) { @@ -645,7 +649,7 @@ csd_host_.get())); GURL other_phishing_url("http://other_phishing_url.com/bla"); ExpectPreClassificationChecks(other_phishing_url, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse, &kFalse); // We navigate away. The callback cb should be revoked. NavigateAndCommit(other_phishing_url); // Wait for the pre-classification checks to finish for other_phishing_url. @@ -724,7 +728,7 @@ // First we have to navigate to the URL to set the unique page ID. ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); SetUnsafeSubResourceForCurrent(true /* expect_unsafe_resource */); @@ -750,7 +754,7 @@ // Do an initial navigation to a safe host. GURL start_url("http://safe.example.com/"); ExpectPreClassificationChecks(start_url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(start_url); WaitAndCheckPreClassificationChecks(); @@ -763,7 +767,7 @@ verdict.set_is_phishing(false); ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateWithSBHitAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -779,7 +783,7 @@ EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get())); ExpectPreClassificationChecks(start_url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateWithoutSBHitAndCommit(start_url); WaitAndCheckPreClassificationChecks(); } @@ -793,7 +797,7 @@ // Do an initial navigation to a safe host. GURL start_url("http://safe.example.com/"); ExpectPreClassificationChecks(start_url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(start_url); WaitAndCheckPreClassificationChecks(); @@ -805,7 +809,7 @@ verdict.set_is_phishing(false); ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateWithoutSBHitAndCommit(url); // Simulate a subresource malware hit on committed page. @@ -869,7 +873,7 @@ badipurl->set_url("http://badip.com"); ExpectPreClassificationChecks(GURL(malware_verdict.url()), &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse, &kFalse, &kFalse); NavigateAndCommit(GURL(malware_verdict.url())); WaitAndCheckPreClassificationChecks(); @@ -984,10 +988,10 @@ EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_)) .WillOnce(Return(false)) .WillOnce(Return(false)); - ExpectPreClassificationChecks(first_url, NULL, &kFalse, &kFalse, NULL, NULL, - NULL, NULL); + ExpectPreClassificationChecks(first_url, NULL, &kFalse, NULL, NULL, NULL, + NULL); ExpectPreClassificationChecks(second_url, NULL, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(first_url); // Don't flush the message loop, as we want to navigate to a different @@ -1000,7 +1004,7 @@ // Navigate the tab to a page. We should see a StartPhishingDetection IPC. GURL url("http://host.com/"); ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1012,7 +1016,7 @@ TestPreClassificationCheckSameDocumentNavigation) { GURL url("http://host.com/"); ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1023,8 +1027,7 @@ // Now try an same-document navigation. This should not trigger an IPC. EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_)).Times(0); GURL inpage("http://host.com/#foo"); - ExpectPreClassificationChecks(inpage, NULL, NULL, NULL, NULL, NULL, NULL, - NULL); + ExpectPreClassificationChecks(inpage, NULL, NULL, NULL, NULL, NULL, NULL); NavigateAndCommit(inpage); WaitAndCheckPreClassificationChecks(); @@ -1038,7 +1041,7 @@ RenderFrameHostTester::For(web_contents()->GetMainFrame())-> SetContentsMimeType("application/xhtml+xml"); ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1050,7 +1053,7 @@ // Navigate to two hosts, which should cause two IPCs. GURL url1("http://host1.com/"); ExpectPreClassificationChecks(url1, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(url1); WaitAndCheckPreClassificationChecks(); @@ -1059,7 +1062,7 @@ GURL url2("http://host2.com/"); ExpectPreClassificationChecks(url2, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(url2); // Re-override the binder for PhishingDetector because navigation causes // a new web InterfaceProvider to be created @@ -1081,7 +1084,7 @@ RenderFrameHostTester::For(web_contents()->GetMainFrame())-> SetContentsMimeType("image/jpeg"); ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1093,8 +1096,7 @@ TestPreClassificationCheckPrivateIpAddress) { // If IsPrivateIPAddress returns true, no IPC should be triggered. GURL url("http://host3.com/"); - ExpectPreClassificationChecks(url, &kTrue, &kFalse, NULL, NULL, NULL, NULL, - NULL); + ExpectPreClassificationChecks(url, &kTrue, NULL, NULL, NULL, NULL, NULL); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1102,13 +1104,14 @@ ExpectShouldClassifyForMalwareResult(false); } -TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckIncognito) { +TEST_F(ClientSideDetectionHostIncognitoTest, + TestPreClassificationCheckIncognito) { // If the tab is incognito there should be no IPC. Also, we shouldn't // even check the csd-whitelist. GURL url("http://host4.com/"); - ExpectPreClassificationChecks(url, &kFalse, &kTrue, NULL, NULL, NULL, NULL, - NULL); - NavigateAndCommit(url); + ExpectPreClassificationChecks(url, &kFalse, NULL, NULL, NULL, NULL, NULL); + + content::WebContentsTester::For(web_contents())->NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); fake_phishing_detector_.CheckMessage(NULL); @@ -1119,8 +1122,8 @@ // If the URL is on the csd whitelist no phishing IPC should be sent // but we should classify the URL for malware. GURL url("http://host5.com/"); - ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kTrue, &kFalse, &kFalse, - &kFalse, &kFalse); + ExpectPreClassificationChecks(url, &kFalse, &kTrue, &kFalse, &kFalse, &kFalse, + &kFalse); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1133,7 +1136,7 @@ // The malware killswitch should be ignored. GURL url("http://host5.com/kill-switch"); ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1145,8 +1148,8 @@ // If item is in the cache but it isn't valid, we will classify regardless // of whether we are over the reporting limit. GURL url("http://host6.com/"); - ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, &kTrue, - NULL, &kFalse); + ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kTrue, NULL, + &kFalse); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1160,8 +1163,8 @@ // If the url isn't in the cache and we are over the reporting limit, we // don't do classification. GURL url("http://host7.com/"); - ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kTrue, &kFalse); + ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, &kTrue, + &kFalse); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1173,7 +1176,7 @@ TestPreClassificationCheckOverMalwareReportingLimit) { GURL url("http://host.com/"); ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kTrue); + &kFalse, &kTrue); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1184,8 +1187,8 @@ TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckOverBothReportingLimits) { GURL url("http://host.com/"); - ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kTrue, &kTrue); + ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, &kTrue, + &kTrue); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1196,7 +1199,7 @@ TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckHttpsUrl) { GURL url("https://host.com/"); ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1208,7 +1211,7 @@ TestPreClassificationCheckNoneHttpOrHttpsUrl) { GURL url("file://host.com/"); ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, - &kFalse, &kFalse, &kFalse); + &kFalse, &kFalse); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks(); @@ -1220,8 +1223,8 @@ // If result is cached, we will try and display the blocking page directly // with no start classification message. GURL url("http://host8.com/"); - ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kTrue, &kFalse, - &kFalse, &kFalse); + ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kTrue, &kFalse, &kFalse, + &kFalse); UnsafeResource resource; EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_)) @@ -1240,13 +1243,12 @@ TEST_F(ClientSideDetectionHostTest, TestPreClassificationWhitelistedByPolicy) { // Configures enterprise whitelist. - ListPrefUpdate update(mock_profile_->GetPrefs(), + ListPrefUpdate update(profile()->GetPrefs(), prefs::kSafeBrowsingWhitelistDomains); update->AppendString("example.com"); GURL url("http://example.com/"); - ExpectPreClassificationChecks(url, &kFalse, &kFalse, NULL, NULL, NULL, NULL, - NULL); + ExpectPreClassificationChecks(url, &kFalse, NULL, NULL, NULL, NULL, NULL); NavigateAndCommit(url); WaitAndCheckPreClassificationChecks();
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h index bc3678c6..a87b29d3 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
@@ -80,7 +80,7 @@ protected: friend class SafeBrowsingBlockingPageFactoryImpl; - friend class SafeBrowsingBlockingPageTest; + friend class SafeBrowsingBlockingPageTestBase; friend class SafeBrowsingBlockingPageBrowserTest; friend class SafeBrowsingBlockingQuietPageFactoryImpl; friend class SafeBrowsingBlockingQuietPageTest; @@ -94,7 +94,7 @@ ExtendedReportingNotShownOnSecurePage); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingBlockingPageTest, MalwareReportsTransitionDisabled); - FRIEND_TEST_ALL_PREFIXES(SafeBrowsingBlockingPageTest, + FRIEND_TEST_ALL_PREFIXES(SafeBrowsingBlockingPageIncognitoTest, ExtendedReportingNotShownInIncognito); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingBlockingPageTest, ExtendedReportingNotShownNotAllowExtendedReporting);
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc index ce73d8d..141d81d 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include <list> +#include <utility> #include "base/bind.h" #include "base/run_loop.h" @@ -129,14 +130,6 @@ } }; -class MockTestingProfile : public TestingProfile { - public: - MockTestingProfile() {} - ~MockTestingProfile() override {} - - MOCK_CONST_METHOD0(IsOffTheRecord, bool()); -}; - class TestSafeBrowsingBlockingPageQuiet : public SafeBrowsingBlockingPage { public: TestSafeBrowsingBlockingPageQuiet( @@ -214,7 +207,8 @@ } // namespace -class SafeBrowsingBlockingPageTest : public ChromeRenderViewHostTestHarness { +class SafeBrowsingBlockingPageTestBase + : public ChromeRenderViewHostTestHarness { public: // The decision the user made. enum UserResponse { @@ -223,8 +217,9 @@ CANCEL }; - SafeBrowsingBlockingPageTest() - : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()) { + explicit SafeBrowsingBlockingPageTestBase(bool is_incognito) + : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()), + is_incognito_(is_incognito) { ResetUserResponse(); // The safe browsing UI manager does not need a service for this test. ui_manager_ = new TestSafeBrowsingUIManager(NULL); @@ -233,6 +228,13 @@ void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); + if (is_incognito_) { + auto incognito_web_contents = + content::WebContentsTester::CreateTestWebContents( + profile()->GetOffTheRecordProfile(), nullptr); + SetContents(std::move(incognito_web_contents)); + } + system_request_context_getter_ = base::MakeRefCounted<net::TestURLRequestContextGetter>( base::CreateSingleThreadTaskRunnerWithTraits( @@ -257,7 +259,11 @@ Profile::FromBrowserContext(web_contents()->GetBrowserContext()); safe_browsing_service->AddPrefService(profile->GetPrefs()); #if BUILDFLAG(ENABLE_EXTENSIONS) - test_event_router_ = extensions::CreateAndUseTestEventRouter(profile); + // EventRouterFactory redirects incognito context to original profile. + test_event_router_ = + extensions::CreateAndUseTestEventRouter(profile->GetOriginalProfile()); + DCHECK(test_event_router_); + extensions::SafeBrowsingPrivateEventRouterFactory::GetInstance() ->SetTestingFactory( profile, base::BindRepeating(&BuildSafeBrowsingPrivateEventRouter)); @@ -279,19 +285,6 @@ ChromeRenderViewHostTestHarness::TearDown(); } - content::BrowserContext* CreateBrowserContext() override { - // Set custom profile object so that we can mock calls to IsOffTheRecord. - // This needs to happen before we call the parent SetUp() function. We use - // a nice mock because other parts of the code are calling IsOffTheRecord. - mock_profile_ = new testing::NiceMock<MockTestingProfile>(); - return mock_profile_; - } - - void SetProfileOffTheRecord() { - EXPECT_CALL(*mock_profile_, IsOffTheRecord()) - .WillRepeatedly(testing::Return(true)); - } - void OnBlockingPageComplete(bool proceed) { if (proceed) user_response_ = OK; @@ -351,9 +344,6 @@ scoped_refptr<TestSafeBrowsingUIManager> ui_manager_; scoped_refptr<net::URLRequestContextGetter> system_request_context_getter_; - // Owned by TestSafeBrowsingBlockingPage. - MockTestingProfile* mock_profile_; - #if BUILDFLAG(ENABLE_EXTENSIONS) extensions::TestEventRouter* test_event_router_; std::unique_ptr<TestExtensionEventObserver> observer_; @@ -365,7 +355,7 @@ const GURL& url, SBThreatType type) { resource->callback = - base::Bind(&SafeBrowsingBlockingPageTest::OnBlockingPageComplete, + base::Bind(&SafeBrowsingBlockingPageTestBase::OnBlockingPageComplete, base::Unretained(this)); resource->callback_thread = base::CreateSingleThreadTaskRunnerWithTraits( {content::BrowserThread::IO}); @@ -382,6 +372,20 @@ ScopedTestingLocalState scoped_testing_local_state_; UserResponse user_response_; TestSafeBrowsingBlockingPageFactory factory_; + const bool is_incognito_; +}; + +class SafeBrowsingBlockingPageTest : public SafeBrowsingBlockingPageTestBase { + public: + SafeBrowsingBlockingPageTest() + : SafeBrowsingBlockingPageTestBase(false /*is_incognito*/) {} +}; + +class SafeBrowsingBlockingPageIncognitoTest + : public SafeBrowsingBlockingPageTestBase { + public: + SafeBrowsingBlockingPageIncognitoTest() + : SafeBrowsingBlockingPageTestBase(true /*is_incognito*/) {} }; // Tests showing a blocking page for a malware page and not proceeding. @@ -888,13 +892,11 @@ } // Test that extended reporting option is not shown in incognito window. -TEST_F(SafeBrowsingBlockingPageTest, +TEST_F(SafeBrowsingBlockingPageIncognitoTest, ExtendedReportingNotShownInIncognito) { - // Make profile in incognito mode. - SetProfileOffTheRecord(); // Enable malware details. - Profile* profile = Profile::FromBrowserContext( - web_contents()->GetBrowserContext()); + Profile* profile = + Profile::FromBrowserContext(web_contents()->GetBrowserContext()); ASSERT_TRUE(profile->IsOffTheRecord()); SetExtendedReportingPref(profile->GetPrefs(), true); @@ -1087,9 +1089,6 @@ scoped_refptr<TestSafeBrowsingUIManager> ui_manager_; - // Owned by TestSafeBrowsingBlockingQuietPage. - MockTestingProfile* mock_profile_; - private: void InitResource(security_interstitials::UnsafeResource* resource, bool is_subresource,
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h index b872e57f..1571211 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.h +++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -220,7 +220,7 @@ friend struct content::BrowserThread::DeleteOnThread< content::BrowserThread::UI>; friend class base::DeleteHelper<SafeBrowsingService>; - friend class SafeBrowsingBlockingPageTest; + friend class SafeBrowsingBlockingPageTestBase; friend class SafeBrowsingBlockingQuietPageTest; friend class SafeBrowsingServerTest; friend class SafeBrowsingUIManagerTest;
diff --git a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc index 489c9ed9..e6c79593 100644 --- a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc +++ b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc
@@ -5,20 +5,27 @@ #include "chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h" #include <algorithm> +#include <memory> +#include <utility> +#include "base/files/file_path.h" #include "base/metrics/histogram_macros.h" +#include "base/task/post_task.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" -#include "components/download/public/common/download_item.h" #include "components/keyed_service/core/service_access_type.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/features.h" -#include "components/safe_browsing/triggers/trigger_manager.h" +#include "components/safe_browsing/ping_manager.h" +#include "components/safe_browsing/web_ui/safe_browsing_ui.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/download_item_utils.h" #include "content/public/browser/download_manager.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/storage_partition.h" +#include "content/public/browser/web_contents.h" namespace safe_browsing { @@ -26,23 +33,67 @@ // MIME-type for APKs. const char kApkMimeType[] = "application/vnd.android.package-archive"; +// The number of user gestures to trace back for the referrer chain. +const int kAndroidTelemetryUserGestureLimit = 2; + bool IsFeatureEnabled() { return base::FeatureList::IsEnabled(safe_browsing::kTelemetryForApkDownloads); } + +// Enumerates the possibilities for whether the CSBRR report was sent (or not). +enum class ApkDownloadTelemetryOutcome { + NOT_SENT_SAFE_BROWSING_NOT_ENABLED = 0, + // |web_contents| was nullptr. This happens sometimes when downloads are + // resumed but it's not clear exactly when. + NOT_SENT_MISSING_WEB_CONTENTS = 1, + // No ping sent because the user is in Incognito mode. + NOT_SENT_INCOGNITO = 2, + // No ping sent because the user hasn't enabled extended reporting. + NOT_SENT_EXTENDED_REPORTING_DISABLED = 3, + // Download was cancelled. + NOT_SENT_DOWNLOAD_CANCELLED = 4, + // Failed to serialize the report. + NOT_SENT_FAILED_TO_SERIALIZE = 5, + // Feature not enabled so don't send. + NOT_SENT_FEATURE_NOT_ENABLED = 6, + // Download completed. Ping sent. + SENT = 7, + + kMaxValue = SENT +}; + +void RecordApkDownloadTelemetryOutcome(ApkDownloadTelemetryOutcome outcome) { + UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.AndroidTelemetry.ApkDownload.Outcome", + outcome); +} + +enum class ApkDownloadTelemetryIncompleteReason { + // |web_contents| was nullptr. This happens sometimes when downloads are + // resumed but it's not clear exactly when. + MISSING_WEB_CONTENTS = 0, + // Navigation manager wasn't ready yet to provide the referrer chain. + SB_NAVIGATION_MANAGER_NOT_READY = 1, + // Full referrer chain captured. + COMPLETE = 2, + + kMaxValue = COMPLETE, +}; + +void RecordApkDownloadTelemetryIncompleteReason( + ApkDownloadTelemetryIncompleteReason reason) { + UMA_HISTOGRAM_ENUMERATION( + "SafeBrowsing.AndroidTelemetry.ApkDownload.IncompleteReason", reason); +} + } // namespace AndroidTelemetryService::AndroidTelemetryService( SafeBrowsingService* sb_service, Profile* profile) - : TelemetryService(), - profile_(profile), - sb_service_(sb_service), - trigger_manager_(sb_service->trigger_manager()) { + : TelemetryService(), profile_(profile), sb_service_(sb_service) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(profile_); - DCHECK(IsSafeBrowsingEnabled()); - if (!IsFeatureEnabled()) { - return; - } + DCHECK(sb_service_); content::DownloadManager* download_manager = content::BrowserContext::GetDownloadManager(profile_); @@ -53,6 +104,7 @@ } AndroidTelemetryService::~AndroidTelemetryService() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); content::DownloadManager* download_manager = content::BrowserContext::GetDownloadManager(profile_); if (download_manager) { @@ -63,36 +115,71 @@ void AndroidTelemetryService::OnDownloadCreated( content::DownloadManager* manager, download::DownloadItem* item) { - DCHECK(IsFeatureEnabled()); - - content::WebContents* web_contents = - content::DownloadItemUtils::GetWebContents(item); - if (!web_contents) { - // TODO(vakh): This can happen sometimes on a browser launch. Identify this - // case and document it better. - return; - } + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (item->GetMimeType() != kApkMimeType) { return; } + if (!CanSendPing(item)) { + return; + } + item->AddObserver(this); - StartThreatDetailsCollection(web_contents); } void AndroidTelemetryService::OnDownloadUpdated(download::DownloadItem* item) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(IsFeatureEnabled()); DCHECK_EQ(kApkMimeType, item->GetMimeType()); if (item->GetState() == download::DownloadItem::COMPLETE) { - // Download completed. Send report, if allowed. - content::WebContents* web_contents = - content::DownloadItemUtils::GetWebContents(item); - FinishCollectingThreatDetails(web_contents); + // Download completed. Send report. + MaybeSendApkDownloadReport(item); + } else if (item->GetState() == download::DownloadItem::CANCELLED) { + RecordApkDownloadTelemetryOutcome( + ApkDownloadTelemetryOutcome::NOT_SENT_DOWNLOAD_CANCELLED); } } +bool AndroidTelemetryService::CanSendPing(download::DownloadItem* item) { + content::WebContents* web_contents = + content::DownloadItemUtils::GetWebContents(item); + if (!web_contents) { + // TODO(vakh): This can happen sometimes when a download resumes on a + // browser re-launch. Identify this case and document it better. + RecordApkDownloadTelemetryOutcome( + ApkDownloadTelemetryOutcome::NOT_SENT_MISSING_WEB_CONTENTS); + return false; + } + + if (!IsSafeBrowsingEnabled()) { + RecordApkDownloadTelemetryOutcome( + ApkDownloadTelemetryOutcome::NOT_SENT_SAFE_BROWSING_NOT_ENABLED); + return false; + } + + if (web_contents->GetBrowserContext()->IsOffTheRecord()) { + RecordApkDownloadTelemetryOutcome( + ApkDownloadTelemetryOutcome::NOT_SENT_INCOGNITO); + return false; + } + + if (!IsExtendedReportingEnabled(*GetPrefs())) { + RecordApkDownloadTelemetryOutcome( + ApkDownloadTelemetryOutcome::NOT_SENT_EXTENDED_REPORTING_DISABLED); + return false; + } + + if (!IsFeatureEnabled()) { + RecordApkDownloadTelemetryOutcome( + ApkDownloadTelemetryOutcome::NOT_SENT_FEATURE_NOT_ENABLED); + return false; + } + + return true; +} + const PrefService* AndroidTelemetryService::GetPrefs() { return profile_->GetPrefs(); } @@ -101,36 +188,85 @@ return GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled); } -void AndroidTelemetryService::StartThreatDetailsCollection( - content::WebContents* web_contents) { - security_interstitials::UnsafeResource resource; - resource.threat_type = SB_THREAT_TYPE_APK_DOWNLOAD; - resource.url = web_contents->GetLastCommittedURL(); - resource.web_contents_getter = resource.GetWebContentsGetter( - web_contents->GetMainFrame()->GetProcess()->GetID(), - web_contents->GetMainFrame()->GetRoutingID()); +void AndroidTelemetryService::FillReferrerChain( + content::WebContents* web_contents, + ClientSafeBrowsingReportRequest* report) { + if (!SafeBrowsingNavigationObserverManager::IsEnabledAndReady(profile_)) { + RecordApkDownloadTelemetryIncompleteReason( + ApkDownloadTelemetryIncompleteReason::SB_NAVIGATION_MANAGER_NOT_READY); + return; + } - TriggerManagerReason reason; - // Ignores the return of |StartCollectingThreatDetails()| here and - // let TriggerManager decide whether it should start data - // collection. - trigger_manager_->StartCollectingThreatDetailsWithReason( - safe_browsing::TriggerType::APK_DOWNLOAD, web_contents, resource, - sb_service_->GetURLLoaderFactory(), - HistoryServiceFactory::GetForProfile(profile_, - ServiceAccessType::EXPLICIT_ACCESS), - TriggerManager::GetSBErrorDisplayOptions(*GetPrefs(), web_contents), - &reason); - // TODO(vakh): Log |reason|. + RecordApkDownloadTelemetryIncompleteReason( + web_contents + ? ApkDownloadTelemetryIncompleteReason::COMPLETE + : ApkDownloadTelemetryIncompleteReason::MISSING_WEB_CONTENTS); + SafeBrowsingNavigationObserverManager::AttributionResult result = + sb_service_->navigation_observer_manager() + ->IdentifyReferrerChainByWebContents( + web_contents, kAndroidTelemetryUserGestureLimit, + report->mutable_referrer_chain()); + + size_t referrer_chain_length = report->referrer_chain().size(); + UMA_HISTOGRAM_COUNTS_100( + "SafeBrowsing.ReferrerURLChainSize.ApkDownloadTelemetry", + referrer_chain_length); + UMA_HISTOGRAM_ENUMERATION( + "SafeBrowsing.ReferrerAttributionResult.ApkDownloadTelemetry", result, + SafeBrowsingNavigationObserverManager::ATTRIBUTION_FAILURE_TYPE_MAX); + + // Determines how many recent navigation events to append to referrer chain. + size_t recent_navigations_to_collect = + profile_ ? SafeBrowsingNavigationObserverManager:: + CountOfRecentNavigationsToAppend(*profile_, result) + : 0u; + sb_service_->navigation_observer_manager()->AppendRecentNavigations( + recent_navigations_to_collect, report->mutable_referrer_chain()); } -void AndroidTelemetryService::FinishCollectingThreatDetails( - content::WebContents* web_contents) { - trigger_manager_->FinishCollectingThreatDetails( - safe_browsing::TriggerType::APK_DOWNLOAD, web_contents, - base::TimeDelta::FromMilliseconds(0), /*did_proceed=*/false, - /*num_visit=*/0, - TriggerManager::GetSBErrorDisplayOptions(*GetPrefs(), web_contents)); +void AndroidTelemetryService::MaybeSendApkDownloadReport( + download::DownloadItem* item) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(item->IsDone()); + + std::unique_ptr<ClientSafeBrowsingReportRequest> report( + new ClientSafeBrowsingReportRequest()); + report->set_type( + safe_browsing::ClientSafeBrowsingReportRequest::APK_DOWNLOAD); + report->set_url(item->GetOriginalUrl().spec()); + + // Fill referrer chain. + content::WebContents* web_contents = + content::DownloadItemUtils::GetWebContents(item); + FillReferrerChain(web_contents, report.get()); + + // Fill DownloadItemInfo + ClientSafeBrowsingReportRequest::DownloadItemInfo* + mutable_download_item_info = report->mutable_download_item_info(); + mutable_download_item_info->set_url(item->GetURL().spec()); + mutable_download_item_info->mutable_digests()->set_sha256(item->GetHash()); + mutable_download_item_info->set_length(item->GetReceivedBytes()); + mutable_download_item_info->set_file_basename( + item->GetTargetFilePath().BaseName().value()); + // TODO(vakh): Capture |safety_net_id_on_ui_thread_|. It is unset currently. + report->set_safety_net_id(safety_net_id_on_ui_thread_); + + std::string serialized; + if (!report->SerializeToString(&serialized)) { + DLOG(ERROR) << "Unable to serialize the APK download telemetry report."; + RecordApkDownloadTelemetryOutcome( + ApkDownloadTelemetryOutcome::NOT_SENT_FAILED_TO_SERIALIZE); + return; + } + sb_service_->ping_manager()->ReportThreatDetails(serialized); + + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&WebUIInfoSingleton::AddToCSBRRsSent, + base::Unretained(WebUIInfoSingleton::GetInstance()), + std::move(report))); + + RecordApkDownloadTelemetryOutcome(ApkDownloadTelemetryOutcome::SENT); } } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h index 1c2a33e..0b17ac23 100644 --- a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h +++ b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h
@@ -5,7 +5,7 @@ #ifndef CHROME_BROWSER_SAFE_BROWSING_TELEMETRY_ANDROID_ANDROID_TELEMETRY_SERVICE_H_ #define CHROME_BROWSER_SAFE_BROWSING_TELEMETRY_ANDROID_ANDROID_TELEMETRY_SERVICE_H_ -#include <vector> +#include <string> #include "chrome/browser/safe_browsing/telemetry/telemetry_service.h" #include "components/download/public/common/download_item.h" @@ -22,7 +22,6 @@ namespace safe_browsing { class SafeBrowsingService; -class TriggerManager; // This class is used to send telemetry information to Safe Browsing for // security related incidents. The information is sent only if: @@ -51,16 +50,19 @@ void OnDownloadUpdated(download::DownloadItem* download) override; private: - // Calls into |trigger_manager_| to start collecting information about the - // download event. This information is then sent to Safe Browsing service - // in the form of a |ClientSafeBrowsingReportRequest| message. - // If the download gets cancelled, the report isn't sent. - void StartThreatDetailsCollection(content::WebContents* web_contents); + // Whether the ping can be sent, based on empty web_contents, or incognito + // mode, or extended reporting opt-in status, + bool CanSendPing(download::DownloadItem* item); - // Calls into |trigger_manager_| to prepare to send the referrer chain and - // other information to Safe Browsing service. Only called when the download - // completes and only for users who have opted into extended reporting. - void FinishCollectingThreatDetails(content::WebContents* web_contents); + // Fill the referrer chain in |report| with the actual referrer chain for the + // given |web_contents|, as well as recent navigations. + void FillReferrerChain(content::WebContents* web_contents, + ClientSafeBrowsingReportRequest* report); + + // Sets the relevant fields in an instance of + // |ClientSafeBrowsingReportRequest| and sends it to the Safe Browsing + // backend. The report may not be sent if the proto fails to serialize. + void MaybeSendApkDownloadReport(download::DownloadItem* item); // Helper method to get prefs from |profile_|. const PrefService* GetPrefs(); @@ -71,12 +73,11 @@ // Profile associated with this instance. Unowned. Profile* profile_; + std::string safety_net_id_on_ui_thread_; + // Unowned. SafeBrowsingService* sb_service_; - // Used to send the ClientSafeBrowsingReportRequest report. Unowned. - TriggerManager* trigger_manager_; - DISALLOW_COPY_AND_ASSIGN(AndroidTelemetryService); };
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc index f89421e2..8d1147f3 100644 --- a/chrome/browser/search/local_ntp_source.cc +++ b/chrome/browser/search/local_ntp_source.cc
@@ -423,6 +423,9 @@ } std::string ConvertLogoImageToBase64(const EncodedLogo& logo) { + if (!logo.encoded_image) + return std::string(); + std::string base64; base::Base64Encode(logo.encoded_image->data(), &base64); return base::StringPrintf("data:%s;base64,%s",
diff --git a/chrome/browser/shell_integration_mac.mm b/chrome/browser/shell_integration_mac.mm index 747450788..7d0b430 100644 --- a/chrome/browser/shell_integration_mac.mm +++ b/chrome/browser/shell_integration_mac.mm
@@ -121,17 +121,14 @@ base::string16 GetApplicationNameForProtocol(const GURL& url) { NSURL* ns_url = [NSURL URLWithString: base::SysUTF8ToNSString(url.possibly_invalid_spec())]; - CFURLRef openingApp = NULL; - OSStatus status = LSGetApplicationForURL((CFURLRef)ns_url, - kLSRolesAll, - NULL, - &openingApp); - if (status != noErr) { + base::ScopedCFTypeRef<CFErrorRef> out_err; + base::ScopedCFTypeRef<CFURLRef> openingApp(LSCopyDefaultApplicationURLForURL( + (CFURLRef)ns_url, kLSRolesAll, out_err.InitializeInto())); + if (out_err) { // likely kLSApplicationNotFoundErr return base::string16(); } - NSString* appPath = [(NSURL*)openingApp path]; - CFRelease(openingApp); // NOT A BUG; LSGetApplicationForURL retains for us + NSString* appPath = [base::mac::CFToNSCast(openingApp.get()) path]; NSString* appDisplayName = [[NSFileManager defaultManager] displayNameAtPath:appPath]; return base::SysNSStringToUTF16(appDisplayName);
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service.cc b/chrome/browser/supervised_user/child_accounts/child_account_service.cc index 0288445..024910d 100644 --- a/chrome/browser/supervised_user/child_accounts/child_account_service.cc +++ b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
@@ -13,7 +13,6 @@ #include "base/values.h" #include "build/build_config.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.h" @@ -104,7 +103,7 @@ void ChildAccountService::Init() { SupervisedUserServiceFactory::GetForProfile(profile_)->SetDelegate(this); - AccountTrackerServiceFactory::GetForProfile(profile_)->AddObserver(this); + IdentityManagerFactory::GetForProfile(profile_)->AddObserver(this); PropagateChildStatusToUser(profile_->IsChild()); @@ -122,7 +121,7 @@ void ChildAccountService::Shutdown() { family_fetcher_.reset(); - AccountTrackerServiceFactory::GetForProfile(profile_)->RemoveObserver(this); + IdentityManagerFactory::GetForProfile(profile_)->RemoveObserver(this); SupervisedUserServiceFactory::GetForProfile(profile_)->SetDelegate(nullptr); DCHECK(!active_); } @@ -270,7 +269,7 @@ SetIsChildAccount(info.is_child_account); } -void ChildAccountService::OnAccountRemoved(const AccountInfo& info) { +void ChildAccountService::OnAccountRemovedWithInfo(const AccountInfo& info) { SetIsChildAccount(false); }
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service.h b/chrome/browser/supervised_user/child_accounts/child_account_service.h index b729e70..28e836c 100644 --- a/chrome/browser/supervised_user/child_accounts/child_account_service.h +++ b/chrome/browser/supervised_user/child_accounts/child_account_service.h
@@ -18,9 +18,9 @@ #include "chrome/browser/supervised_user/child_accounts/family_info_fetcher.h" #include "chrome/browser/supervised_user/supervised_user_service.h" #include "components/keyed_service/core/keyed_service.h" -#include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/gaia_cookie_manager_service.h" #include "net/base/backoff_entry.h" +#include "services/identity/public/cpp/identity_manager.h" namespace user_prefs { class PrefRegistrySyncable; @@ -33,7 +33,7 @@ // supervised user experience, fetch information about the parent(s)). class ChildAccountService : public KeyedService, public FamilyInfoFetcher::Consumer, - public AccountTrackerService::Observer, + public identity::IdentityManager::Observer, public SupervisedUserService::Delegate, public GaiaCookieManagerService::Observer { public: @@ -79,9 +79,9 @@ // Sets whether the signed-in account is a child account. void SetIsChildAccount(bool is_child_account); - // AccountTrackerService::Observer implementation. + // identity::IdentityManager::Observer implementation. void OnAccountUpdated(const AccountInfo& info) override; - void OnAccountRemoved(const AccountInfo& info) override; + void OnAccountRemovedWithInfo(const AccountInfo& info) override; // FamilyInfoFetcher::Consumer implementation. void OnGetFamilyMembersSuccess(
diff --git a/chrome/browser/sync/test/integration/autofill_helper.cc b/chrome/browser/sync/test/integration/autofill_helper.cc index 3da2bb0..9218faca 100644 --- a/chrome/browser/sync/test/integration/autofill_helper.cc +++ b/chrome/browser/sync/test/integration/autofill_helper.cc
@@ -279,7 +279,7 @@ pdm->AddObserver(&personal_data_observer); EXPECT_CALL(personal_data_observer, OnPersonalDataFinishedProfileTasks()) - .WillOnce(QuitMessageLoop(&run_loop)); + .WillRepeatedly(QuitMessageLoop(&run_loop)); EXPECT_CALL(personal_data_observer, OnPersonalDataChanged()) .Times(testing::AnyNumber());
diff --git a/chrome/browser/task_manager/sampling/task_group.cc b/chrome/browser/task_manager/sampling/task_group.cc index ac096caad..6a9adda5 100644 --- a/chrome/browser/task_manager/sampling/task_group.cc +++ b/chrome/browser/task_manager/sampling/task_group.cc
@@ -33,9 +33,9 @@ #if defined(OS_WIN) REFRESH_TYPE_START_TIME | REFRESH_TYPE_CPU_TIME | #endif // defined(OS_WIN) -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) REFRESH_TYPE_FD_COUNT | -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) #if BUILDFLAG(ENABLE_NACL) REFRESH_TYPE_NACL | #endif // BUILDFLAG(ENABLE_NACL) @@ -112,9 +112,9 @@ #if BUILDFLAG(ENABLE_NACL) nacl_debug_stub_port_(nacl::kGdbDebugStubPortUnknown), #endif // BUILDFLAG(ENABLE_NACL) -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) open_fd_count_(-1), -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) idle_wakeups_per_second_(-1), gpu_memory_has_duplicates_(false), is_backgrounded_(false), @@ -128,10 +128,10 @@ weak_ptr_factory_.GetWeakPtr()), base::Bind(&TaskGroup::OnIdleWakeupsRefreshDone, weak_ptr_factory_.GetWeakPtr()), -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) base::Bind(&TaskGroup::OnOpenFdCountRefreshDone, weak_ptr_factory_.GetWeakPtr()), -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) base::Bind(&TaskGroup::OnProcessPriorityDone, weak_ptr_factory_.GetWeakPtr())); @@ -296,14 +296,14 @@ } #endif // BUILDFLAG(ENABLE_NACL) -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) void TaskGroup::OnOpenFdCountRefreshDone(int open_fd_count) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); open_fd_count_ = open_fd_count; OnBackgroundRefreshTypeFinished(REFRESH_TYPE_FD_COUNT); } -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) void TaskGroup::OnCpuRefreshDone(double cpu_usage) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/task_manager/sampling/task_group.h b/chrome/browser/task_manager/sampling/task_group.h index 16661eb5..9ada18b 100644 --- a/chrome/browser/task_manager/sampling/task_group.h +++ b/chrome/browser/task_manager/sampling/task_group.h
@@ -106,9 +106,9 @@ int nacl_debug_stub_port() const { return nacl_debug_stub_port_; } #endif // BUILDFLAG(ENABLE_NACL) -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) int open_fd_count() const { return open_fd_count_; } -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) int idle_wakeups_per_second() const { return idle_wakeups_per_second_; } private: @@ -121,9 +121,9 @@ void RefreshNaClDebugStubPort(int child_process_unique_id); void OnRefreshNaClDebugStubPortDone(int port); #endif -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) void OnOpenFdCountRefreshDone(int open_fd_count); -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) void OnCpuRefreshDone(double cpu_usage); void OnSwappedMemRefreshDone(int64_t swapped_mem_bytes); @@ -191,10 +191,10 @@ #if BUILDFLAG(ENABLE_NACL) int nacl_debug_stub_port_; #endif // BUILDFLAG(ENABLE_NACL) -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) // The number of file descriptors currently open by the process. int open_fd_count_; -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) int idle_wakeups_per_second_; bool gpu_memory_has_duplicates_; bool is_backgrounded_;
diff --git a/chrome/browser/task_manager/sampling/task_group_sampler.cc b/chrome/browser/task_manager/sampling/task_group_sampler.cc index c838e91..b9c9f4b3 100644 --- a/chrome/browser/task_manager/sampling/task_group_sampler.cc +++ b/chrome/browser/task_manager/sampling/task_group_sampler.cc
@@ -42,9 +42,9 @@ const OnCpuRefreshCallback& on_cpu_refresh, const OnSwappedMemRefreshCallback& on_swapped_mem_refresh, const OnIdleWakeupsCallback& on_idle_wakeups, -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) const OnOpenFdCountCallback& on_open_fd_count, -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) const OnProcessPriorityCallback& on_process_priority) : process_(std::move(process)), process_metrics_(CreateProcessMetrics(process_.Handle())), @@ -52,9 +52,9 @@ on_cpu_refresh_callback_(on_cpu_refresh), on_swapped_mem_refresh_callback_(on_swapped_mem_refresh), on_idle_wakeups_callback_(on_idle_wakeups), -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) on_open_fd_count_callback_(on_open_fd_count), -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) on_process_priority_callback_(on_process_priority) { DCHECK(blocking_pool_runner.get()); @@ -96,7 +96,7 @@ } #endif // defined(OS_MACOSX) || defined(OS_LINUX) -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_FD_COUNT, refresh_flags)) { base::PostTaskAndReplyWithResult( @@ -105,7 +105,7 @@ base::Bind(&TaskGroupSampler::RefreshOpenFdCount, this), on_open_fd_count_callback_); } -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_PRIORITY, refresh_flags)) { @@ -144,13 +144,13 @@ return process_metrics_->GetIdleWakeupsPerSecond(); } -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) int TaskGroupSampler::RefreshOpenFdCount() { DCHECK(worker_pool_sequenced_checker_.CalledOnValidSequence()); return process_metrics_->GetOpenFdCount(); } -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) bool TaskGroupSampler::RefreshProcessPriority() { DCHECK(worker_pool_sequenced_checker_.CalledOnValidSequence());
diff --git a/chrome/browser/task_manager/sampling/task_group_sampler.h b/chrome/browser/task_manager/sampling/task_group_sampler.h index c0c6241..57d33d1 100644 --- a/chrome/browser/task_manager/sampling/task_group_sampler.h +++ b/chrome/browser/task_manager/sampling/task_group_sampler.h
@@ -32,9 +32,9 @@ using OnCpuRefreshCallback = base::Callback<void(double)>; using OnSwappedMemRefreshCallback = base::Callback<void(int64_t)>; using OnIdleWakeupsCallback = base::Callback<void(int)>; -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) using OnOpenFdCountCallback = base::Callback<void(int)>; -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) using OnProcessPriorityCallback = base::Callback<void(bool)>; TaskGroupSampler( @@ -43,9 +43,9 @@ const OnCpuRefreshCallback& on_cpu_refresh, const OnSwappedMemRefreshCallback& on_memory_refresh, const OnIdleWakeupsCallback& on_idle_wakeups, -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) const OnOpenFdCountCallback& on_open_fd_count, -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) const OnProcessPriorityCallback& on_process_priority); // Refreshes the expensive process' stats (CPU usage, memory usage, and idle @@ -60,9 +60,9 @@ double RefreshCpuUsage(); int64_t RefreshSwappedMem(); int RefreshIdleWakeupsPerSecond(); -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) int RefreshOpenFdCount(); -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) bool RefreshProcessPriority(); // The process that holds the handle that we own so that we can use it for @@ -80,9 +80,9 @@ const OnCpuRefreshCallback on_cpu_refresh_callback_; const OnSwappedMemRefreshCallback on_swapped_mem_refresh_callback_; const OnIdleWakeupsCallback on_idle_wakeups_callback_; -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) const OnOpenFdCountCallback on_open_fd_count_callback_; -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) const OnProcessPriorityCallback on_process_priority_callback_; // To assert we're running on the correct thread.
diff --git a/chrome/browser/task_manager/sampling/task_manager_impl.cc b/chrome/browser/task_manager/sampling/task_manager_impl.cc index fcf6477..f55de38 100644 --- a/chrome/browser/task_manager/sampling/task_manager_impl.cc +++ b/chrome/browser/task_manager/sampling/task_manager_impl.cc
@@ -15,6 +15,7 @@ #include "base/command_line.h" #include "base/containers/adapters.h" #include "base/task/post_task.h" +#include "build/build_config.h" #include "chrome/browser/task_manager/providers/browser_process_task_provider.h" #include "chrome/browser/task_manager/providers/child_process_task_provider.h" #include "chrome/browser/task_manager/providers/fallback_task_provider.h" @@ -206,11 +207,11 @@ } int TaskManagerImpl::GetOpenFdCount(TaskId task_id) const { -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) return GetTaskGroupByTaskId(task_id)->open_fd_count(); #else return -1; -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) } bool TaskManagerImpl::IsTaskOnBackgroundedProcess(TaskId task_id) const {
diff --git a/chrome/browser/task_manager/task_manager_observer.h b/chrome/browser/task_manager/task_manager_observer.h index dfb6814..60b510c 100644 --- a/chrome/browser/task_manager/task_manager_observer.h +++ b/chrome/browser/task_manager/task_manager_observer.h
@@ -43,11 +43,11 @@ // or backgrounded. REFRESH_TYPE_PRIORITY = 1 << 13, -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) // For observers interested in getting the number of open file descriptors of // processes. REFRESH_TYPE_FD_COUNT = 1 << 14, -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) REFRESH_TYPE_KEEPALIVE_COUNT = 1 << 15, REFRESH_TYPE_MEMORY_FOOTPRINT = 1 << 16,
diff --git a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc index 061b016..090d16f 100644 --- a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc +++ b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
@@ -6,6 +6,7 @@ #include "ash/public/cpp/window_properties.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/shell_test_api.test-mojom.h" #include "base/command_line.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc index 6fa734c..188bdd9 100644 --- a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc +++ b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc
@@ -15,8 +15,31 @@ #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" #include "chrome/browser/ui/views/crostini/crostini_app_restart_view.h" #include "chrome/grit/generated_resources.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/strings/grit/ui_strings.h" +namespace { + +bool IsDisplayScaleFactorOne(int64_t display_id) { + display::Display d; + if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id, &d)) + return false; + return d.device_scale_factor() == 1.0; +} + +bool ShouldShowDisplayDensityMenuItem( + const base::Optional<crostini::CrostiniRegistryService::Registration>& reg, + int64_t display_id) { + // The default terminal app is crosh in a Chrome window and it doesn't run in + // the Crostini container so it doesn't support display density the same way. + if (!reg || reg->is_terminal_app()) + return false; + return !IsDisplayScaleFactorOne(display_id); +} + +} // namespace + CrostiniShelfContextMenu::CrostiniShelfContextMenu( ChromeLauncherController* controller, const ash::ShelfItem* item, @@ -60,9 +83,7 @@ // Some apps have high-density display support and do not require scaling // to match the system display density, but others are density-unaware and // look better when scaled to match the display density. - // The default terminal app is crosh in a Chrome window and it doesn't run in - // the Crostini container so it doesn't support display density the same way. - if (registration.has_value() && !registration->is_terminal_app()) { + if (ShouldShowDisplayDensityMenuItem(registration, display_id())) { if (registration->IsScaled()) { menu_model->AddCheckItemWithStringId(ash::CROSTINI_USE_HIGH_DENSITY, IDS_CROSTINI_USE_HIGH_DENSITY);
diff --git a/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc b/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc index 2f28227..bcc65ce 100644 --- a/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc +++ b/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc
@@ -4,6 +4,7 @@ #include "ash/public/cpp/ash_view_ids.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/system_tray_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/system_tray_test_api.test-mojom.h" #include "base/macros.h" #include "base/strings/string16.h"
diff --git a/chrome/browser/ui/ash/shelf_browsertest.cc b/chrome/browser/ui/ash/shelf_browsertest.cc index 54c3e925..f30d8f7 100644 --- a/chrome/browser/ui/ash/shelf_browsertest.cc +++ b/chrome/browser/ui/ash/shelf_browsertest.cc
@@ -4,6 +4,7 @@ #include "ash/public/cpp/shelf_prefs.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/shelf_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/shelf_test_api.test-mojom.h" #include "base/command_line.h" #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/ash/system_tray_client_browsertest.cc b/chrome/browser/ui/ash/system_tray_client_browsertest.cc index 2a45095..f5b9247a 100644 --- a/chrome/browser/ui/ash/system_tray_client_browsertest.cc +++ b/chrome/browser/ui/ash/system_tray_client_browsertest.cc
@@ -6,6 +6,7 @@ #include "ash/public/cpp/ash_view_ids.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/system_tray_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/system_tray_test_api.test-mojom.h" #include "base/i18n/time_formatting.h" #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc index 0fb85bba..48a13856 100644 --- a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc +++ b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
@@ -6,8 +6,10 @@ #include <vector> #include "ash/public/cpp/ash_view_ids.h" +#include "ash/public/interfaces/ash_message_center_controller.mojom-test-utils.h" #include "ash/public/interfaces/ash_message_center_controller.mojom.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/system_tray_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/system_tray_test_api.test-mojom.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/ash/time_to_first_present_recorder_browsertest.cc b/chrome/browser/ui/ash/time_to_first_present_recorder_browsertest.cc index 53b8af8..25870311 100644 --- a/chrome/browser/ui/ash/time_to_first_present_recorder_browsertest.cc +++ b/chrome/browser/ui/ash/time_to_first_present_recorder_browsertest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/time_to_first_present_recorder_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/time_to_first_present_recorder_test_api.test-mojom.h" #include "base/command_line.h" #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index c4cac84..3b04624 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -247,15 +247,16 @@ void ChromeAutofillClient::ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) { #if !defined(OS_ANDROID) autofill::ManageMigrationUiController::CreateForWebContents(web_contents()); autofill::ManageMigrationUiController* controller = autofill::ManageMigrationUiController::FromWebContents(web_contents()); - controller->ShowOfferDialog( - std::move(legal_message), - migratable_credit_cards, std::move(start_migrating_cards_callback)); + controller->ShowOfferDialog(std::move(legal_message), user_email, + migratable_credit_cards, + std::move(start_migrating_cards_callback)); #endif }
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h index b0d7622..9b71d06 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.h +++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -75,6 +75,7 @@ base::OnceClosure show_migration_dialog_closure) override; void ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) override; void ShowLocalCardMigrationResults(
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc index 45835f1..118bb1f2 100644 --- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc +++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
@@ -47,6 +47,7 @@ void LocalCardMigrationDialogControllerImpl::ShowOfferDialog( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, AutofillClient::LocalCardMigrationCallback start_migrating_cards_callback) { if (local_card_migration_dialog_) @@ -67,6 +68,7 @@ CreateLocalCardMigrationDialogView(this, web_contents()); start_migrating_cards_callback_ = std::move(start_migrating_cards_callback); migratable_credit_cards_ = migratable_credit_cards; + user_email_ = user_email; local_card_migration_dialog_->ShowDialog(); UpdateIcon(); dialog_is_visible_duration_timer_ = base::ElapsedTimer(); @@ -144,6 +146,11 @@ return tip_message_; } +const std::string& LocalCardMigrationDialogControllerImpl::GetUserEmail() + const { + return user_email_; +} + void LocalCardMigrationDialogControllerImpl::OnSaveButtonClicked( const std::vector<std::string>& selected_cards_guids) { AutofillMetrics::LogLocalCardMigrationDialogUserSelectionPercentageMetric(
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h index b937a06..6c53370 100644 --- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h +++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
@@ -33,6 +33,7 @@ void ShowOfferDialog( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, AutofillClient::LocalCardMigrationCallback start_migrating_cards_callback); @@ -61,6 +62,7 @@ const std::vector<MigratableCreditCard>& GetCardList() const override; const LegalMessageLines& GetLegalMessageLines() const override; const base::string16& GetTipMessage() const override; + const std::string& GetUserEmail() const override; void OnSaveButtonClicked( const std::vector<std::string>& selected_cards_guids) override; void OnCancelButtonClicked() override; @@ -123,6 +125,9 @@ // feedback dialogs after migration process is finished. base::string16 tip_message_; + // The user email shown in the dialogs. + std::string user_email_; + // Contains observer listening to user's interactions with the dialog. The // observer is responsible for setting flow step upon these interactions. base::ObserverList<LocalCardMigrationControllerObserver>::Unchecked
diff --git a/chrome/browser/ui/autofill/manage_migration_ui_controller.cc b/chrome/browser/ui/autofill/manage_migration_ui_controller.cc index aa6b1e9..d3ae32c3 100644 --- a/chrome/browser/ui/autofill/manage_migration_ui_controller.cc +++ b/chrome/browser/ui/autofill/manage_migration_ui_controller.cc
@@ -37,11 +37,12 @@ void ManageMigrationUiController::ShowOfferDialog( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, AutofillClient::LocalCardMigrationCallback start_migrating_cards_callback) { flow_step_ = LocalCardMigrationFlowStep::OFFER_DIALOG; dialog_controller_->ShowOfferDialog( - std::move(legal_message), migratable_credit_cards, + std::move(legal_message), user_email, migratable_credit_cards, std::move(start_migrating_cards_callback)); }
diff --git a/chrome/browser/ui/autofill/manage_migration_ui_controller.h b/chrome/browser/ui/autofill/manage_migration_ui_controller.h index bdcef7f6..c735b16 100644 --- a/chrome/browser/ui/autofill/manage_migration_ui_controller.h +++ b/chrome/browser/ui/autofill/manage_migration_ui_controller.h
@@ -56,6 +56,7 @@ void ShowOfferDialog( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, AutofillClient::LocalCardMigrationCallback start_migrating_cards_callback);
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc index 65298069..951bfd2 100644 --- a/chrome/browser/ui/browser_navigator.cc +++ b/chrome/browser/ui/browser_navigator.cc
@@ -330,6 +330,7 @@ load_url_params.input_start = params->input_start; load_url_params.was_activated = params->was_activated; load_url_params.href_translate = params->href_translate; + load_url_params.reload_type = params->reload_type; // |frame_tree_node_id| is kNoFrameTreeNodeId for main frame navigations. if (params->frame_tree_node_id ==
diff --git a/chrome/browser/ui/browser_navigator_params.cc b/chrome/browser/ui/browser_navigator_params.cc index c5211e8..1f10745 100644 --- a/chrome/browser/ui/browser_navigator_params.cc +++ b/chrome/browser/ui/browser_navigator_params.cc
@@ -48,6 +48,7 @@ const content::OpenURLParams& params) { this->initiator_origin = params.initiator_origin; this->referrer = params.referrer; + this->reload_type = params.reload_type; this->source_site_instance = params.source_site_instance; this->frame_tree_node_id = params.frame_tree_node_id; this->redirect_chain = params.redirect_chain;
diff --git a/chrome/browser/ui/browser_navigator_params.h b/chrome/browser/ui/browser_navigator_params.h index 634346a..93f52b2 100644 --- a/chrome/browser/ui/browser_navigator_params.h +++ b/chrome/browser/ui/browser_navigator_params.h
@@ -12,6 +12,7 @@ #include "build/build_config.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "content/public/browser/global_request_id.h" +#include "content/public/browser/reload_type.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/site_instance.h" #include "content/public/common/referrer.h" @@ -275,6 +276,9 @@ // language code). Empty otherwise. std::string href_translate; + // Indicates the reload type of this navigation. + content::ReloadType reload_type = content::ReloadType::NONE; + private: NavigateParams(); DISALLOW_COPY_AND_ASSIGN(NavigateParams);
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm index 2bcd809..490da56 100644 --- a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm +++ b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
@@ -407,6 +407,11 @@ return touchBar.autorelease(); } +// TODO(crbug.com/921109): Migrate to the new NSAccessibility API for this +// method. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + - (void)setupBackForwardControl { NSMutableArray* images = [NSMutableArray arrayWithArray:@[ CreateNSImageFromIcon(vector_icons::kBackArrowIcon), @@ -451,6 +456,8 @@ backForwardControl_.reset([control retain]); } +#pragma clang diagnostic pop + - (void)updateWebContents:(content::WebContents*)contents { notificationBridge_->UpdateWebContents(contents); }
diff --git a/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc b/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc index 25af392..5e60a010 100644 --- a/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc +++ b/chrome/browser/ui/search/local_ntp_doodle_browsertest.cc
@@ -395,6 +395,42 @@ } IN_PROC_BROWSER_TEST_F(LocalNTPDoodleTest, + ShouldShowInteractiveLogoWithoutImage) { + EncodedLogo cached_logo; + cached_logo.encoded_image = nullptr; + cached_logo.metadata.type = LogoType::INTERACTIVE; + cached_logo.metadata.full_page_url = + GURL("https://www.chromium.org/interactive"); + cached_logo.metadata.alt_text = "alt text"; + cached_logo.metadata.iframe_width_px = 500; + cached_logo.metadata.iframe_height_px = 200; + + EXPECT_CALL(*logo_service(), GetLogoPtr(_)) + .WillRepeatedly(DoAll( + ReturnCachedLogo(LogoCallbackReason::DETERMINED, cached_logo), + ReturnFreshLogo(LogoCallbackReason::REVALIDATED, base::nullopt))); + + // Open a new blank tab, then go to NTP. + content::WebContents* active_tab = + local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank")); + base::HistogramTester histograms; + ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL)); + + EXPECT_THAT(GetDimension(active_tab, "fakebox", "top"), Eq(kFakeboxTopPx)); + EXPECT_THAT(GetComputedOpacity(active_tab, "logo-default"), Eq(0.0)); + EXPECT_THAT(GetComputedOpacity(active_tab, "logo-doodle"), Eq(1.0)); + EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-container"), + Eq<std::string>("none")); + EXPECT_THAT(GetComputedDisplay(active_tab, "logo-doodle-iframe"), + Eq<std::string>("block")); + + EXPECT_THAT(GetElementProperty(active_tab, "logo-doodle-iframe", "src"), + Eq<std::string>("https://www.chromium.org/interactive")); + EXPECT_THAT(GetElementProperty(active_tab, "logo-doodle-iframe", "title"), + Eq<std::string>("alt text")); +} + +IN_PROC_BROWSER_TEST_F(LocalNTPDoodleTest, ShouldFadeSimpleDoodleToDefaultWhenFetched) { EncodedLogo cached_logo; cached_logo.encoded_image = MakeRefPtr(kCachedB64);
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index c4c5fa2..1d92544 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -343,7 +343,7 @@ SupervisedUserNavigationObserver::CreateForWebContents(web_contents); #endif -#if BUILDFLAG(ENABLE_PRINTING) && !defined(OS_ANDROID) +#if BUILDFLAG(ENABLE_PRINTING) printing::InitializePrinting(web_contents); #endif
diff --git a/chrome/browser/ui/task_manager/task_manager_columns.cc b/chrome/browser/ui/task_manager/task_manager_columns.cc index 643fc3f..b0fc692 100644 --- a/chrome/browser/ui/task_manager/task_manager_columns.cc +++ b/chrome/browser/ui/task_manager/task_manager_columns.cc
@@ -93,10 +93,10 @@ base::size("100000") * kCharWidth, -1, true, false, false}, #endif -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) {IDS_TASK_MANAGER_OPEN_FD_COUNT_COLUMN, ui::TableColumn::RIGHT, -1, 0, base::size("999") * kCharWidth, -1, true, false, false}, -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) {IDS_TASK_MANAGER_PROCESS_PRIORITY_COLUMN, ui::TableColumn::LEFT, -1, 0, base::size("background") * kCharWidth, -1, true, true, false}, {IDS_TASK_MANAGER_KEEPALIVE_COUNT_COLUMN, ui::TableColumn::RIGHT, -1, 0,
diff --git a/chrome/browser/ui/task_manager/task_manager_table_model.cc b/chrome/browser/ui/task_manager/task_manager_table_model.cc index 9910637..19cb421c 100644 --- a/chrome/browser/ui/task_manager/task_manager_table_model.cc +++ b/chrome/browser/ui/task_manager/task_manager_table_model.cc
@@ -430,13 +430,13 @@ ? stringifier_->backgrounded_string() : stringifier_->foregrounded_string(); -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) case IDS_TASK_MANAGER_OPEN_FD_COUNT_COLUMN: { const int fd_count = observed_task_manager()->GetOpenFdCount(tasks_[row]); return fd_count >= 0 ? base::FormatNumber(fd_count) : stringifier_->n_a_string(); } -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) case IDS_TASK_MANAGER_KEEPALIVE_COUNT_COLUMN: { return stringifier_->GetKeepaliveCountText( @@ -590,7 +590,7 @@ return BooleanCompare(is_proc1_bg, is_proc2_bg); } -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) case IDS_TASK_MANAGER_OPEN_FD_COUNT_COLUMN: { const int proc1_fd_count = observed_task_manager()->GetOpenFdCount(tasks_[row1]); @@ -598,7 +598,7 @@ observed_task_manager()->GetOpenFdCount(tasks_[row2]); return ValueCompare(proc1_fd_count, proc2_fd_count); } -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) default: NOTREACHED(); @@ -760,11 +760,11 @@ type = REFRESH_TYPE_KEEPALIVE_COUNT; break; -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_MACOSX) case IDS_TASK_MANAGER_OPEN_FD_COUNT_COLUMN: type = REFRESH_TYPE_FD_COUNT; break; -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_MACOSX) default: NOTREACHED();
diff --git a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc index f2de022..75c4de6 100644 --- a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc +++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
@@ -34,6 +34,13 @@ #include "chrome/browser/offline_pages/offline_page_utils.h" #endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/browser/extension_registry.h" + +// Id for extension that enables users to report sites to Safe Browsing. +const char kPreventElisionExtensionId[] = "ekpgepffboojnckiahkpangdldnjafnj"; +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + ChromeLocationBarModelDelegate::ChromeLocationBarModelDelegate() {} ChromeLocationBarModelDelegate::~ChromeLocationBarModelDelegate() {} @@ -63,6 +70,17 @@ return true; } +bool ChromeLocationBarModelDelegate::ShouldPreventElision() const { +#if BUILDFLAG(ENABLE_EXTENSIONS) + Profile* const profile = GetProfile(); + return profile && extensions::ExtensionRegistry::Get(profile) + ->enabled_extensions() + .Contains(kPreventElisionExtensionId); +#else + return false; +#endif +} + bool ChromeLocationBarModelDelegate::ShouldDisplayURL() const { // Note: The order here is important. // - The WebUI test must come before the extension scheme test because there
diff --git a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h index cdb02ea..26d74e9 100644 --- a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h +++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h
@@ -23,6 +23,9 @@ // Returns active WebContents. virtual content::WebContents* GetActiveWebContents() const = 0; + // Prevents URL elision depending on whether a specified extension installed. + bool ShouldPreventElision() const override; + // LocationBarModelDelegate: bool ShouldDisplayURL() const override;
diff --git a/chrome/browser/ui/views/autofill/dialog_view_ids.h b/chrome/browser/ui/views/autofill/dialog_view_ids.h index eb7d8ac..3a9b2be 100644 --- a/chrome/browser/ui/views/autofill/dialog_view_ids.h +++ b/chrome/browser/ui/views/autofill/dialog_view_ids.h
@@ -8,17 +8,21 @@ #include "components/autofill/core/browser/field_types.h" // This defines an enumeration of IDs that can uniquely identify a view within -// the scope of the local and upload credit card save bubbles. +// the scope of the local and upload credit card save bubbles as well as the +// local card migration bubble and dialogs. namespace autofill { enum DialogViewId : int { VIEW_ID_NONE = 0, - // The following are the important containing views of the bubble. - MAIN_CONTENT_VIEW_LOCAL, // The main content view, for a local save bubble - MAIN_CONTENT_VIEW_UPLOAD, // The main content view, for an upload save bubble - FOOTNOTE_VIEW, // Contains the legal messages for upload save + // The following views are contained in SaveCardBubbleViews. + MAIN_CONTENT_VIEW_LOCAL, // The main content view for a local + // save bubble + MAIN_CONTENT_VIEW_UPLOAD, // The main content view for an upload + // save bubble + FOOTNOTE_VIEW, // The footnote view of either an upload + // save bubble or a manage cards view. SIGN_IN_PROMO_VIEW, // Contains the sign-in promo view MANAGE_CARDS_VIEW, // The manage cards view EXPIRATION_DATE_VIEW, // Contains the dropdowns for expiration date @@ -26,6 +30,12 @@ // The sub-view that contains the sign-in button in the promo. SIGN_IN_VIEW, + // The main content view for a migration offer bubble. + MAIN_CONTENT_VIEW_MIGRATION_BUBBLE, + + // The main content view for the main migration dialog. + MAIN_CONTENT_VIEW_MIGRATION_OFFER_DIALOG, + // The following are views::LabelButton objects (clickable). OK_BUTTON, // Can say [Save], [Next], [Confirm], // or [Done] depending on context
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_browsertest.cc b/chrome/browser/ui/views/autofill/local_card_migration_browsertest.cc new file mode 100644 index 0000000..f124e0c2 --- /dev/null +++ b/chrome/browser/ui/views/autofill/local_card_migration_browsertest.cc
@@ -0,0 +1,675 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <ctime> +#include <list> +#include <memory> +#include <string> +#include <utility> + +#include "base/callback_list.h" +#include "base/command_line.h" +#include "base/macros.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/signin/account_fetcher_service_factory.h" +#include "chrome/browser/signin/account_tracker_service_factory.h" +#include "chrome/browser/signin/fake_account_fetcher_service_builder.h" +#include "chrome/browser/signin/fake_signin_manager_builder.h" +#include "chrome/browser/signin/identity_manager_factory.h" +#include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/browser/sync/profile_sync_service_factory.h" +#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/integration/sync_test.h" +#include "chrome/browser/ui/autofill/chrome_autofill_client.h" +#include "chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl.h" +#include "chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h" +#include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/location_bar/location_bar.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/views/autofill/dialog_view_ids.h" +#include "chrome/browser/ui/views/autofill/local_card_migration_bubble_views.h" +#include "chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h" +#include "chrome/browser/ui/views/autofill/local_card_migration_icon_view.h" +#include "chrome/browser/ui/views/autofill/save_card_bubble_views.h" +#include "chrome/browser/ui/views/location_bar/location_bar_view.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/credit_card_save_manager.h" +#include "components/autofill/core/browser/form_data_importer.h" +#include "components/autofill/core/browser/local_card_migration_manager.h" +#include "components/autofill/core/browser/personal_data_manager.h" +#include "components/autofill/core/browser/test_event_waiter.h" +#include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_prefs.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/network_session_configurator/common/network_switches.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/signin/core/browser/account_tracker_service.h" +#include "components/signin/core/browser/fake_account_fetcher_service.h" +#include "components/sync/test/fake_server/fake_server.h" +#include "components/sync/test/fake_server/fake_server_network_resources.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/test_navigation_observer.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/url_request/test_url_fetcher_factory.h" +#include "services/device/public/cpp/test/scoped_geolocation_overrider.h" +#include "services/identity/public/cpp/identity_manager.h" +#include "services/identity/public/cpp/identity_test_utils.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/base_event_utils.h" +#include "ui/views/bubble/bubble_frame_view.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/test/widget_test.h" +#include "ui/views/window/dialog_client_view.h" + +using base::Bucket; +using testing::ElementsAre; + +namespace autofill { + +namespace { + +constexpr char kURLGetUploadDetailsRequest[] = + "https://payments.google.com/payments/apis/chromepaymentsservice/" + "getdetailsforsavecard"; +constexpr char kResponseGetUploadDetailsSuccess[] = + "{\"legal_message\":{\"line\":[{\"template\":\"Legal message template with " + "link: " + "{0}.\",\"template_parameter\":[{\"display_text\":\"Link\",\"url\":\"https:" + "//www.example.com/\"}]}]},\"context_token\":\"dummy_context_token\"}"; +constexpr char kResponseGetUploadDetailsFailure[] = + "{\"error\":{\"code\":\"FAILED_PRECONDITION\",\"user_error_message\":\"An " + "unexpected error has occurred. Please try again later.\"}}"; + +constexpr char kCreditCardFormURL[] = + "/credit_card_upload_form_address_and_cc.html"; + +constexpr char kFirstCardNumber[] = "5428424047572420"; // Mastercard +constexpr char kSecondCardNumber[] = "4782187095085933"; // Visa + +constexpr double kFakeGeolocationLatitude = 1.23; +constexpr double kFakeGeolocationLongitude = 4.56; + +} // namespace + +class LocalCardMigrationBrowserTest + : public SyncTest, + public LocalCardMigrationManager::ObserverForTest { + protected: + // Various events that can be waited on by the DialogEventWaiter. + enum class DialogEvent : int { + REQUESTED_LOCAL_CARD_MIGRATION, + RECEIVED_GET_UPLOAD_DETAILS_RESPONSE, + SENT_MIGRATE_CARDS_REQUEST, + RECEIVED_MIGRATE_CARDS_RESPONSE + }; + + LocalCardMigrationBrowserTest() : SyncTest(SINGLE_CLIENT) {} + + ~LocalCardMigrationBrowserTest() override {} + + void SetUpOnMainThread() override { + SyncTest::SetUpOnMainThread(); + + // Set up the HTTPS server (uses the embedded_test_server). + ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); + embedded_test_server()->ServeFilesFromSourceDirectory( + "components/test/data/autofill"); + embedded_test_server()->StartAcceptingConnections(); + + ProfileSyncServiceFactory::GetForProfile(browser()->profile()) + ->OverrideNetworkResourcesForTest( + std::make_unique<fake_server::FakeServerNetworkResources>( + GetFakeServer()->AsWeakPtr())); + + std::string username; +#if defined(OS_CHROMEOS) + // In ChromeOS browser tests, the profile may already by authenticated with + // stub account |user_manager::kStubUserEmail|. + AccountInfo info = + IdentityManagerFactory::GetForProfile(browser()->profile()) + ->GetPrimaryAccountInfo(); + username = info.email; +#endif + if (username.empty()) + username = "user@gmail.com"; + + harness_ = ProfileSyncServiceHarness::Create( + browser()->profile(), username, "password", + ProfileSyncServiceHarness::SigninType::FAKE_SIGNIN); + + // Set up the URL loader factory for the payments client so we can intercept + // those network requests too. + test_shared_loader_factory_ = + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_); + ContentAutofillDriver::GetForRenderFrameHost( + GetActiveWebContents()->GetMainFrame()) + ->autofill_manager() + ->client() + ->GetPaymentsClient() + ->set_url_loader_factory_for_testing(test_shared_loader_factory_); + + // Set up this class as the ObserverForTest implementation. + LocalCardMigrationManager* local_card_migration_manager = + ContentAutofillDriver::GetForRenderFrameHost( + GetActiveWebContents()->GetMainFrame()) + ->autofill_manager() + ->client() + ->GetFormDataImporter() + ->local_card_migration_manager_.get(); + + local_card_migration_manager->SetEventObserverForTesting(this); + personal_data_ = local_card_migration_manager->personal_data_manager_; + + // Set up the fake geolocation data. + geolocation_overrider_ = + std::make_unique<device::ScopedGeolocationOverrider>( + kFakeGeolocationLatitude, kFakeGeolocationLongitude); + + // Set up billing customer ID. + ContentAutofillDriver::GetForRenderFrameHost( + GetActiveWebContents()->GetMainFrame()) + ->autofill_manager() + ->client() + ->GetPrefs() + ->SetDouble(prefs::kAutofillBillingCustomerNumber, 1234); + + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillCreditCardLocalCardMigration); + ASSERT_TRUE(harness_->SetupSync()); + SetUploadDetailsRpcPaymentsAccepts(); + } + + void NavigateTo(const std::string& file_path) { + ui_test_utils::NavigateToURL( + browser(), file_path.find("data:") == 0U + ? GURL(file_path) + : embedded_test_server()->GetURL(file_path)); + } + + void OnDecideToRequestLocalCardMigration() override { + if (event_waiter_) + event_waiter_->OnEvent(DialogEvent::REQUESTED_LOCAL_CARD_MIGRATION); + } + + void OnReceivedGetUploadDetailsResponse() override { + if (event_waiter_) + event_waiter_->OnEvent(DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE); + } + + void OnSentMigrateCardsRequest() override { + if (event_waiter_) + event_waiter_->OnEvent(DialogEvent::SENT_MIGRATE_CARDS_REQUEST); + } + + void OnReceivedMigrateCardsResponse() override { + if (event_waiter_) + event_waiter_->OnEvent(DialogEvent::RECEIVED_MIGRATE_CARDS_RESPONSE); + } + + void SaveLocalCard(std::string card_number) { + CreditCard local_card; + test::SetCreditCardInfo(&local_card, "John Smith", card_number.c_str(), + "12", test::NextYear().c_str(), "1"); + local_card.set_guid("00000000-0000-0000-0000-" + card_number.substr(0, 12)); + local_card.set_record_type(CreditCard::LOCAL_CARD); + personal_data_->AddCreditCard(local_card); + } + + void SaveServerCard(std::string card_number) { + CreditCard server_card; + test::SetCreditCardInfo(&server_card, "John Smith", card_number.c_str(), + "12", test::NextYear().c_str(), "1"); + server_card.set_guid("00000000-0000-0000-0000-" + + card_number.substr(0, 12)); + server_card.set_record_type(CreditCard::FULL_SERVER_CARD); + server_card.set_server_id("full_id_" + card_number); + personal_data_->AddFullServerCreditCard(server_card); + } + + void UseCardAndWaitForMigrationOffer(std::string card_number) { + // Reusing a card should show the migration offer bubble. + ResetEventWaiterForSequence( + {DialogEvent::REQUESTED_LOCAL_CARD_MIGRATION, + DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE}); + FillAndSubmitFormWithCard(card_number); + WaitForObservedEvent(); + } + + void FillAndSubmitFormWithCard(std::string card_number) { + NavigateTo(kCreditCardFormURL); + content::WebContents* web_contents = GetActiveWebContents(); + + const std::string click_fill_button_js = + "(function() { document.getElementById('fill_form').click(); })();"; + ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + + const std::string fill_cc_number_js = + "(function() { document.getElementsByName(\"cc_number\")[0].value = " + + card_number + "; })();"; + ASSERT_TRUE(content::ExecuteScript(web_contents, fill_cc_number_js)); + + const std::string click_submit_button_js = + "(function() { document.getElementById('submit').click(); })();"; + content::TestNavigationObserver nav_observer(web_contents); + ASSERT_TRUE(content::ExecuteScript(web_contents, click_submit_button_js)); + nav_observer.Wait(); + } + + void SetUploadDetailsRpcPaymentsAccepts() { + test_url_loader_factory()->AddResponse(kURLGetUploadDetailsRequest, + kResponseGetUploadDetailsSuccess); + } + + void SetUploadDetailsRpcPaymentsDeclines() { + test_url_loader_factory()->AddResponse(kURLGetUploadDetailsRequest, + kResponseGetUploadDetailsFailure); + } + + void ClickOnView(views::View* view) { + DCHECK(view); + ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, + ui::EF_LEFT_MOUSE_BUTTON); + view->OnMousePressed(pressed); + ui::MouseEvent released_event = + ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), + ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, + ui::EF_LEFT_MOUSE_BUTTON); + view->OnMouseReleased(released_event); + } + + void ClickOnDialogViewAndWait( + views::View* view, + views::DialogDelegateView* local_card_migration_view) { + DCHECK(local_card_migration_view); + views::test::WidgetDestroyedWaiter destroyed_waiter( + local_card_migration_view->GetWidget()); + local_card_migration_view->GetDialogClientView() + ->ResetViewShownTimeStampForTesting(); + views::BubbleFrameView* bubble_frame_view = + static_cast<views::BubbleFrameView*>( + local_card_migration_view->GetWidget() + ->non_client_view() + ->frame_view()); + bubble_frame_view->ResetViewShownTimeStampForTesting(); + ClickOnView(view); + destroyed_waiter.Wait(); + } + + views::View* FindViewInDialogById( + DialogViewId view_id, + views::DialogDelegateView* local_card_migration_view) { + DCHECK(local_card_migration_view); + + views::View* specified_view = + local_card_migration_view->GetViewByID(static_cast<int>(view_id)); + + if (!specified_view) { + specified_view = + local_card_migration_view->GetDialogClientView()->GetViewByID( + static_cast<int>(view_id)); + } + + return specified_view; + } + + void ClickOnOkButton(views::DialogDelegateView* local_card_migration_view) { + views::View* ok_button = + local_card_migration_view->GetDialogClientView()->ok_button(); + + ClickOnDialogViewAndWait(ok_button, local_card_migration_view); + } + + void ClickOnCancelButton( + views::DialogDelegateView* local_card_migration_view) { + views::View* cancel_button = + local_card_migration_view->GetDialogClientView()->cancel_button(); + ClickOnDialogViewAndWait(cancel_button, local_card_migration_view); + } + + views::DialogDelegateView* GetLocalCardMigrationOfferBubbleViews() { + LocalCardMigrationBubbleControllerImpl* + local_card_migration_bubble_controller_impl = + LocalCardMigrationBubbleControllerImpl::FromWebContents( + GetActiveWebContents()); + if (!local_card_migration_bubble_controller_impl) + return nullptr; + return static_cast<LocalCardMigrationBubbleViews*>( + local_card_migration_bubble_controller_impl + ->local_card_migration_bubble_view()); + } + + views::DialogDelegateView* GetLocalCardMigrationMainDialogView() { + LocalCardMigrationDialogControllerImpl* + local_card_migration_dialog_controller_impl = + LocalCardMigrationDialogControllerImpl::FromWebContents( + GetActiveWebContents()); + if (!local_card_migration_dialog_controller_impl) + return nullptr; + return static_cast<LocalCardMigrationDialogView*>( + local_card_migration_dialog_controller_impl + ->local_card_migration_dialog_view()); + } + + LocalCardMigrationIconView* GetLocalCardMigrationIconView() { + if (!browser()) + return nullptr; + LocationBarView* location_bar_view = + static_cast<LocationBarView*>(browser()->window()->GetLocationBar()); + DCHECK(location_bar_view->local_card_migration_icon_view()); + return location_bar_view->local_card_migration_icon_view(); + } + + views::View* GetCloseButton() { + LocalCardMigrationBubbleViews* local_card_migration_bubble_views = + static_cast<LocalCardMigrationBubbleViews*>( + GetLocalCardMigrationOfferBubbleViews()); + DCHECK(local_card_migration_bubble_views); + return local_card_migration_bubble_views->GetBubbleFrameView() + ->GetCloseButtonForTest(); + } + + views::View* GetCardListView() { + return static_cast<LocalCardMigrationDialogView*>( + GetLocalCardMigrationMainDialogView()) + ->card_list_view_; + } + + content::WebContents* GetActiveWebContents() { + return browser()->tab_strip_model()->GetActiveWebContents(); + } + + void ResetEventWaiterForSequence(std::list<DialogEvent> event_sequence) { + event_waiter_ = + std::make_unique<EventWaiter<DialogEvent>>(std::move(event_sequence)); + } + + void WaitForObservedEvent() { event_waiter_->Wait(); } + + network::TestURLLoaderFactory* test_url_loader_factory() { + return &test_url_loader_factory_; + } + + PersonalDataManager* personal_data_ = nullptr; + + std::unique_ptr< + base::CallbackList<void(content::BrowserContext*)>::Subscription> + will_create_browser_context_services_subscription_; + + base::test::ScopedFeatureList scoped_feature_list_; + + std::unique_ptr<ProfileSyncServiceHarness> harness_; + + private: + std::unique_ptr<autofill::EventWaiter<DialogEvent>> event_waiter_; + std::unique_ptr<net::FakeURLFetcherFactory> url_fetcher_factory_; + network::TestURLLoaderFactory test_url_loader_factory_; + scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; + std::unique_ptr<device::ScopedGeolocationOverrider> geolocation_overrider_; + + DISALLOW_COPY_AND_ASSIGN(LocalCardMigrationBrowserTest); +}; + +// Ensures that migration is not offered when user saves a new card. +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, + UsingNewCardDoesNotShowIntermediateMigrationOffer) { + base::HistogramTester histogram_tester; + + SaveLocalCard(kFirstCardNumber); + FillAndSubmitFormWithCard(kSecondCardNumber); + + // No migration bubble should be showing, because the single card upload + // bubble should be displayed instead. + EXPECT_EQ(nullptr, GetLocalCardMigrationOfferBubbleViews()); + // No metrics are recorded when migration is not offered. + histogram_tester.ExpectTotalCount( + "Autofill.LocalCardMigrationBubbleOffer.FirstShow", 0); +} + +// Ensures that migration is not offered when payments declines the cards. +IN_PROC_BROWSER_TEST_F( + LocalCardMigrationBrowserTest, + IntermediateMigrationOfferDoesNotShowWhenPaymentsDeclines) { + base::HistogramTester histogram_tester; + SetUploadDetailsRpcPaymentsDeclines(); + + SaveLocalCard(kFirstCardNumber); + SaveLocalCard(kSecondCardNumber); + FillAndSubmitFormWithCard(kFirstCardNumber); + + // No bubble should be showing. + EXPECT_EQ(nullptr, GetLocalCardMigrationOfferBubbleViews()); + // No metrics are recorded when migration is not offered. + histogram_tester.ExpectTotalCount( + "Autofill.LocalCardMigrationBubbleOffer.FirstShow", 0); +} + +// Ensures that the intermediate migration bubble is not shown after reusing a +// saved server card, if there are no other cards to migrate. +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, + ReusingServerCardDoesNotShowIntermediateMigrationOffer) { + base::HistogramTester histogram_tester; + + SaveServerCard(kFirstCardNumber); + FillAndSubmitFormWithCard(kFirstCardNumber); + + // No bubble should be showing. + EXPECT_EQ(nullptr, GetLocalCardMigrationOfferBubbleViews()); + // No metrics are recorded when migration is not offered. + histogram_tester.ExpectTotalCount( + "Autofill.LocalCardMigrationBubbleOffer.FirstShow", 0); +} + +// Ensures that the intermediate migration bubble is not shown after reusing a +// previously saved local card, if there are no other cards to migrate. +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, + ReusingLocalCardDoesNotShowIntermediateMigrationOffer) { + base::HistogramTester histogram_tester; + + SaveLocalCard(kFirstCardNumber); + FillAndSubmitFormWithCard(kFirstCardNumber); + + // No migration bubble should be showing, because the single card upload + // bubble should be displayed instead. + EXPECT_EQ(nullptr, GetLocalCardMigrationOfferBubbleViews()); + // No metrics are recorded when migration is not offered. + histogram_tester.ExpectTotalCount( + "Autofill.LocalCardMigrationBubbleOffer.FirstShow", 0); +} + +// Ensures that the intermediate migration bubble is triggered after reusing a +// saved local card, if there are multiple local cards available to migrate. +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, + ReusingLocalCardShowsIntermediateMigrationOffer) { + base::HistogramTester histogram_tester; + + SaveLocalCard(kFirstCardNumber); + SaveLocalCard(kSecondCardNumber); + UseCardAndWaitForMigrationOffer(kFirstCardNumber); + + // The intermediate migration bubble should show. + EXPECT_TRUE( + FindViewInDialogById(DialogViewId::MAIN_CONTENT_VIEW_MIGRATION_BUBBLE, + GetLocalCardMigrationOfferBubbleViews()) + ->visible()); + // Metrics + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Autofill.LocalCardMigrationBubbleOffer.FirstShow"), + ElementsAre( + Bucket(AutofillMetrics::LOCAL_CARD_MIGRATION_BUBBLE_REQUESTED, 1), + Bucket(AutofillMetrics::LOCAL_CARD_MIGRATION_BUBBLE_SHOWN, 1))); + histogram_tester.ExpectUniqueSample( + "Autofill.LocalCardMigrationOrigin.UseOfLocalCard", + AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 1); +} + +// Ensures that clicking [X] on the offer bubble makes the bubble disappear. +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, + ClickingCloseClosesBubble) { + base::HistogramTester histogram_tester; + + SaveLocalCard(kFirstCardNumber); + SaveLocalCard(kSecondCardNumber); + UseCardAndWaitForMigrationOffer(kFirstCardNumber); + ClickOnDialogViewAndWait(GetCloseButton(), + GetLocalCardMigrationOfferBubbleViews()); + + // No bubble should be showing. + EXPECT_EQ(nullptr, GetLocalCardMigrationOfferBubbleViews()); + // Metrics + histogram_tester.ExpectUniqueSample( + "Autofill.LocalCardMigrationOrigin.UseOfLocalCard", + AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 1); +} + +// Ensures that clicking on the credit card icon in the omnibox reopens the +// offer bubble after closing it. +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, + ClickingOmniboxIconReshowsBubble) { + base::HistogramTester histogram_tester; + + SaveLocalCard(kFirstCardNumber); + SaveLocalCard(kSecondCardNumber); + UseCardAndWaitForMigrationOffer(kFirstCardNumber); + ClickOnDialogViewAndWait(GetCloseButton(), + GetLocalCardMigrationOfferBubbleViews()); + ClickOnView(GetLocalCardMigrationIconView()); + + // Clicking the icon should reshow the bubble. + EXPECT_TRUE( + FindViewInDialogById(DialogViewId::MAIN_CONTENT_VIEW_MIGRATION_BUBBLE, + GetLocalCardMigrationOfferBubbleViews()) + ->visible()); + // Metrics + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Autofill.LocalCardMigrationOrigin.UseOfLocalCard"), + ElementsAre(Bucket(AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 1))); + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Autofill.LocalCardMigrationBubbleOffer.Reshows"), + ElementsAre( + Bucket(AutofillMetrics::LOCAL_CARD_MIGRATION_BUBBLE_REQUESTED, 1), + Bucket(AutofillMetrics::LOCAL_CARD_MIGRATION_BUBBLE_SHOWN, 1))); +} + +// Ensures that accepting the intermediate migration offer opens up the main +// migration dialog. +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, + ClickingContinueOpensDialog) { + base::HistogramTester histogram_tester; + + SaveLocalCard(kFirstCardNumber); + SaveLocalCard(kSecondCardNumber); + UseCardAndWaitForMigrationOffer(kFirstCardNumber); + // Click the [Continue] button. + ClickOnOkButton(GetLocalCardMigrationOfferBubbleViews()); + + // Dialog should be visible. + EXPECT_TRUE(FindViewInDialogById( + DialogViewId::MAIN_CONTENT_VIEW_MIGRATION_OFFER_DIALOG, + GetLocalCardMigrationMainDialogView()) + ->visible()); + // Intermediate bubble should be gone. + EXPECT_EQ(nullptr, GetLocalCardMigrationOfferBubbleViews()); + // Metrics + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Autofill.LocalCardMigrationOrigin.UseOfLocalCard"), + ElementsAre(Bucket(AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 1), + Bucket(AutofillMetrics::INTERMEDIATE_BUBBLE_ACCEPTED, 1), + Bucket(AutofillMetrics::MAIN_DIALOG_SHOWN, 1))); + histogram_tester.ExpectUniqueSample( + "Autofill.LocalCardMigrationBubbleUserInteraction.FirstShow", + AutofillMetrics::LOCAL_CARD_MIGRATION_BUBBLE_CLOSED_ACCEPTED, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.LocalCardMigrationDialogOffer", + AutofillMetrics::LOCAL_CARD_MIGRATION_DIALOG_SHOWN, 1); +} + +// Ensures that rejecting the main migration dialog closes the dialog. +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, + ClickingCancelClosesDialog) { + base::HistogramTester histogram_tester; + + SaveLocalCard(kFirstCardNumber); + SaveLocalCard(kSecondCardNumber); + UseCardAndWaitForMigrationOffer(kFirstCardNumber); + // Click the [Continue] button. + ClickOnOkButton(GetLocalCardMigrationOfferBubbleViews()); + // Click the [Cancel] button. + ClickOnCancelButton(GetLocalCardMigrationMainDialogView()); + + // No dialog should be showing. + EXPECT_EQ(nullptr, GetLocalCardMigrationMainDialogView()); + // Metrics + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Autofill.LocalCardMigrationOrigin.UseOfLocalCard"), + ElementsAre(Bucket(AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 1), + Bucket(AutofillMetrics::INTERMEDIATE_BUBBLE_ACCEPTED, 1), + Bucket(AutofillMetrics::MAIN_DIALOG_SHOWN, 1))); + histogram_tester.ExpectUniqueSample( + "Autofill.LocalCardMigrationDialogUserInteraction", + AutofillMetrics::LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED, + 1); +} + +// Ensures that accepting the main migration dialog closes the dialog. +IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTest, + ClickingSaveClosesDialog) { + base::HistogramTester histogram_tester; + + SaveLocalCard(kFirstCardNumber); + SaveLocalCard(kSecondCardNumber); + UseCardAndWaitForMigrationOffer(kFirstCardNumber); + // Click the [Continue] button in the bubble. + ClickOnOkButton(GetLocalCardMigrationOfferBubbleViews()); + // Click the [Save] button in the dialog. + // TODO(crbug.com/897998): Add Payments Rpc setup and event waiter. + ClickOnOkButton(GetLocalCardMigrationMainDialogView()); + + // No dialog should be showing. + EXPECT_EQ(nullptr, GetLocalCardMigrationMainDialogView()); + // Metrics + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Autofill.LocalCardMigrationOrigin.UseOfLocalCard"), + ElementsAre(Bucket(AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 1), + Bucket(AutofillMetrics::INTERMEDIATE_BUBBLE_ACCEPTED, 1), + Bucket(AutofillMetrics::MAIN_DIALOG_SHOWN, 1), + Bucket(AutofillMetrics::MAIN_DIALOG_ACCEPTED, 1))); + histogram_tester.ExpectUniqueSample( + "Autofill.LocalCardMigrationDialogUserInteraction", + AutofillMetrics::LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED, + 1); +} + +// TODO(crbug.com/897998): Add these following tests. +// 1) Reusing a server card shows the intermediate bubble. +// 2) All valid cards are visible in the migration offer view. +// 3) Local cards should get deleted after migration. +// 4) Expired and invalid cards should not be shown. +// 5) When user navigates away after five seconds, the bubble disappears. +// 6) When user navigates away after five seconds, the dialog should stay. +// 7) When user clicks legal message links, browser should show a pop-up window. +// 8) Simulate checkboxes to ensure +// LocalCardMigrationDialogUserSelectionPercentage is logged correctly. +// 9) Ensure LocalCardMigrationDialogActiveDuration is logged correctly. + +} // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc b/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc index b2cfc02..472062fe 100644 --- a/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc +++ b/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc
@@ -6,6 +6,7 @@ #include <stddef.h> #include <memory> +#include <utility> #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" @@ -29,6 +30,7 @@ #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/style/typography.h" +#include "ui/views/window/dialog_client_view.h" namespace autofill { @@ -154,6 +156,7 @@ explanatory_message->SetHorizontalAlignment(gfx::ALIGN_LEFT); explanatory_message->SetMultiLine(true); AddChildView(explanatory_message); + set_id(DialogViewId::MAIN_CONTENT_VIEW_MIGRATION_BUBBLE); } } // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.h b/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.h index 80b3503d..aa0f787 100644 --- a/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.h +++ b/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.h
@@ -47,6 +47,8 @@ void WindowClosing() override; private: + friend class LocalCardMigrationBrowserTest; + ~LocalCardMigrationBubbleViews() override; // views::BubbleDialogDelegateView:
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc index 5eb93e5..3ce85b2 100644 --- a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc +++ b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
@@ -4,6 +4,11 @@ #include "chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h" +#include <memory> +#include <string> +#include <vector> + +#include "base/i18n/message_formatter.h" #include "base/location.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h" @@ -83,29 +88,38 @@ return title; } -// Create the explanation text label container for the migration dialogs. The -// text depends on the |view_state| of the dialog and the |card_list_size|. +// Create the explanation text label with |user_email| for the migration +// dialogs. The text content depends on the |view_state| of the dialog and the +// |card_list_size|. std::unique_ptr<views::Label> CreateExplanationText( LocalCardMigrationDialogState view_state, - int card_list_size) { - int message_id; + int card_list_size, + const base::string16& user_email) { + DCHECK_NE((int)user_email.length(), 0); + auto explanation_text = + std::make_unique<views::Label>(base::string16(), CONTEXT_BODY_TEXT_LARGE, + ChromeTextStyle::STYLE_SECONDARY); switch (view_state) { case LocalCardMigrationDialogState::kOffered: - message_id = IDS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_MESSAGE_OFFER; + explanation_text->SetText( + base::i18n::MessageFormatter::FormatWithNumberedArgs( + l10n_util::GetStringFUTF16( + IDS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_MESSAGE_OFFER, + user_email), + card_list_size)); break; case LocalCardMigrationDialogState::kFinished: - message_id = + explanation_text->SetText(l10n_util::GetPluralStringFUTF16( card_list_size == 0 ? IDS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_MESSAGE_INVALID_CARD_REMOVED - : IDS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_MESSAGE_DONE; + : IDS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_MESSAGE_DONE, + card_list_size)); break; case LocalCardMigrationDialogState::kActionRequired: - message_id = IDS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_MESSAGE_FIX; + explanation_text->SetText(l10n_util::GetStringUTF16( + IDS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_MESSAGE_FIX)); break; } - auto explanation_text = std::make_unique<views::Label>( - l10n_util::GetPluralStringFUTF16(message_id, card_list_size), - CONTEXT_BODY_TEXT_LARGE, ChromeTextStyle::STYLE_SECONDARY); explanation_text->SetMultiLine(true); explanation_text->SetHorizontalAlignment(gfx::ALIGN_LEFT); return explanation_text; @@ -206,7 +220,8 @@ const int card_list_size = card_list.size(); feedback_view->AddChildView( - CreateExplanationText(view_state, card_list_size).release()); + CreateExplanationText(view_state, card_list_size, base::string16()) + .release()); if (card_list_size > 0) { feedback_view->AddChildView( @@ -256,7 +271,8 @@ int card_list_size = card_list.size(); contents_container->AddChildView( - CreateExplanationText(controller_->GetViewState(), card_list_size) + CreateExplanationText(controller_->GetViewState(), card_list_size, + base::UTF8ToUTF16(controller_->GetUserEmail())) .release()); std::unique_ptr<views::ScrollView> scroll_view = @@ -299,6 +315,8 @@ } private: + friend class LocalCardMigrationDialogView; + LocalCardMigrationDialogController* controller_; views::View* card_list_view_ = nullptr; @@ -455,6 +473,8 @@ if (view_state == LocalCardMigrationDialogState::kOffered) { offer_view_ = new LocalCardMigrationOfferView(controller_, this); + offer_view_->set_id(DialogViewId::MAIN_CONTENT_VIEW_MIGRATION_OFFER_DIALOG); + card_list_view_ = offer_view_->card_list_view_; AddChildView(offer_view_); } else { AddChildView(CreateFeedbackContentView(controller_, this).release());
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h index 4b2759b..5f559cd 100644 --- a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h +++ b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h
@@ -51,7 +51,10 @@ void UpdateLayout(); private: + friend class LocalCardMigrationBrowserTest; + void ConstructView(); + base::string16 GetOkButtonLabel() const; base::string16 GetCancelButtonLabel() const; @@ -63,6 +66,10 @@ // dialog is not in the 'offer' state. LocalCardMigrationOfferView* offer_view_ = nullptr; + // The view containing a list of cards. It is the content of the scroll bar. + // Owned by the LocalCardMigrationOfferView. + views::View* card_list_view_; + DISALLOW_COPY_AND_ASSIGN(LocalCardMigrationDialogView); };
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc index 4730786..a0ad731 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -489,29 +489,6 @@ return false; } -bool BrowserNonClientFrameViewAsh::OnMouseDragged(const ui::MouseEvent& event) { - if (!features::IsUsingWindowService()) - return false; - - StartWindowMove(event); - return true; -} - -void BrowserNonClientFrameViewAsh::OnMouseReleased( - const ui::MouseEvent& event) { - // If a window move has already been triggered and OnMouseReleased() is - // called, it means the mouse was released before the Ash asserted mouse - // capture, and the move should be cancelled. Note that if something else - // grabs mouse capture right after PerformWindowMove(), Ash may re-assert that - // capture instead of cancelling the move. - if (performing_window_move_) { - aura::WindowTreeHostMus* window_tree_host_mus = - static_cast<aura::WindowTreeHostMus*>( - GetWidget()->GetNativeWindow()->GetHost()); - window_tree_host_mus->CancelWindowMove(); - } -} - void BrowserNonClientFrameViewAsh::OnGestureEvent(ui::GestureEvent* event) { if (!features::IsUsingWindowService()) return; @@ -529,16 +506,9 @@ } break; - case ui::ET_GESTURE_SCROLL_UPDATE: - StartWindowMove(*event); - break; - default: break; } - // Always set the event as handled, otherwise the gesture recognizer will not - // emit ui::ET_GESTURE_SCROLL_UPDATE events. - event->SetHandled(); } /////////////////////////////////////////////////////////////////////////////// @@ -921,44 +891,6 @@ return GetFrameWindow()->GetProperty(ash::kIsShowingInOverviewKey); } -void BrowserNonClientFrameViewAsh::StartWindowMove( - const ui::LocatedEvent& event) { - DCHECK(features::IsUsingWindowService()); - - // The client may receive multiple events before Ash has taken over the window - // move. In this case, ignore the extras. - if (performing_window_move_) - return; - - aura::WindowTreeHostMus* window_tree_host_mus = - static_cast<aura::WindowTreeHostMus*>( - GetWidget()->GetNativeWindow()->GetHost()); - performing_window_move_ = true; - // Don't use display::Screen::GetCursorScreenPoint(), that's incorrect for - // touch events. - aura::Window* window = GetWidget()->GetNativeWindow(); - gfx::Point cursor_location = window->GetBoundsInScreen().origin() + - event.location().OffsetFromOrigin(); - ws::mojom::MoveLoopSource source = ws::mojom::MoveLoopSource::MOUSE; - if (!event.IsMouseEvent()) { - source = ws::mojom::MoveLoopSource::TOUCH; - aura::Window* root = window->GetRootWindow(); - // When using WindowService, the touch events for the window move will - // happen on the root window, so the events need to be transferred from - // widget to its root before starting move loop. - window->env()->gesture_recognizer()->TransferEventsTo( - window, root, ui::TransferTouchesBehavior::kDontCancel); - } - window_tree_host_mus->PerformWindowMove( - source, cursor_location, - base::BindRepeating(&BrowserNonClientFrameViewAsh::OnWindowMoveDone, - weak_ptr_factory_.GetWeakPtr())); -} - -void BrowserNonClientFrameViewAsh::OnWindowMoveDone(bool success) { - performing_window_move_ = false; -} - const aura::Window* BrowserNonClientFrameViewAsh::GetFrameWindow() const { return const_cast<BrowserNonClientFrameViewAsh*>(this)->GetFrameWindow(); }
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h index 0cf8573..0ba8aad 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
@@ -91,8 +91,6 @@ void OnThemeChanged() override; void ChildPreferredSizeChanged(views::View* child) override; bool OnMousePressed(const ui::MouseEvent& event) override; - bool OnMouseDragged(const ui::MouseEvent& event) override; - void OnMouseReleased(const ui::MouseEvent& event) override; void OnGestureEvent(ui::GestureEvent* event) override; // BrowserFrameHeaderAsh::AppearanceProvider: @@ -218,10 +216,6 @@ // Returns whether this window is currently in the overview list. bool IsInOverviewMode() const; - void StartWindowMove(const ui::LocatedEvent& event); - - void OnWindowMoveDone(bool success); - // Returns the top level aura::Window for this browser window. const aura::Window* GetFrameWindow() const; aura::Window* GetFrameWindow(); @@ -251,8 +245,6 @@ ScopedObserver<aura::Window, aura::WindowObserver> window_observer_{this}; - bool performing_window_move_ = false; - // Maintains the current split view state. ash::mojom::SplitViewState split_view_state_ = ash::mojom::SplitViewState::NO_SNAP;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc index aa3c06e6..8066389 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -15,11 +15,12 @@ #include "ash/public/cpp/vector_icons/vector_icons.h" #include "ash/public/cpp/window_properties.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/shelf_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/shelf_test_api.test-mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" +#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/window_pin_type.mojom.h" #include "ash/shell.h" // mash-ok -#include "ash/wm/overview/window_selector_controller.h" // mash-ok +#include "ash/wm/overview/overview_controller.h" // mash-ok #include "ash/wm/splitview/split_view_controller.h" // mash-ok #include "ash/wm/tablet_mode/tablet_mode_controller.h" // mash-ok #include "base/run_loop.h" @@ -148,7 +149,7 @@ run_loop.Run(); aura::test::WaitForAllChangesToComplete(); } else { - ash::Shell::Get()->window_selector_controller()->ToggleOverview(); + ash::Shell::Get()->overview_controller()->ToggleOverview(); } }
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc index a5516ea..b69d459 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
@@ -10,6 +10,7 @@ #include "ash/public/cpp/ash_switches.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/cros_display_config.mojom-test-utils.h" #include "ash/public/interfaces/cros_display_config.mojom.h" #include "base/bind.h" #include "base/command_line.h"
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index 8fb246e5..0bd826ba 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -327,7 +327,7 @@ bool text_is_url = model()->CurrentTextIsURL(); GetRenderText()->SetDirectionalityMode( text_is_url ? gfx::DIRECTIONALITY_AS_URL : gfx::DIRECTIONALITY_FROM_TEXT); - SetStyle(gfx::STRIKE, false); + SetStyle(gfx::TEXT_STYLE_STRIKE, false); base::string16 text = GetText(); bool path_eligible_for_fading = UpdateTextStyle( @@ -954,7 +954,7 @@ return; ApplyColor(location_bar_view_->GetSecurityChipColor(security_level_), range); if (security_level_ == security_state::DANGEROUS) - ApplyStyle(gfx::STRIKE, true, range); + ApplyStyle(gfx::TEXT_STYLE_STRIKE, true, range); } void OmniboxViewViews::OnMouseMoved(const ui::MouseEvent& event) { @@ -1230,15 +1230,16 @@ // Save the user's existing selection to restore it later. saved_selection_for_focus_change_ = GetSelectedRange(); - // Revert the URL if the user has not made any changes. If steady-state - // elisions is on, this will also re-elide the URL. + // If the view is showing text that's not user-text, revert the text to the + // permanent display text. This usually occurs if Steady State Elisions is on + // and the user has unelided, but not edited the URL. // // Because merely Alt-Tabbing to another window and back should not change the // Omnibox state, we only revert the text only if the Omnibox is blurred in // favor of some other View in the same Widget. if (GetWidget() && GetWidget()->IsActive() && - model()->user_input_in_progress() && - text() == model()->GetPermanentDisplayText()) { + !model()->user_input_in_progress() && + text() != model()->GetPermanentDisplayText()) { RevertAll(); } @@ -1724,8 +1725,6 @@ } } -void OmniboxViewViews::OnCompositingChildResizing(ui::Compositor* compositor) {} - void OmniboxViewViews::OnCompositingShuttingDown(ui::Compositor* compositor) { scoped_compositor_observer_.RemoveAll(); }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h index 0890b887..b84027be 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -103,6 +103,10 @@ using OmniboxView::SetUserText; void SetUserText(const base::string16& text, bool update_popup) override; + void SetWindowTextAndCaretPos(const base::string16& text, + size_t caret_pos, + bool update_popup, + bool notify_text_changed) override; void EnterKeywordModeForDefaultSearchProvider() override; bool IsSelectAll() const override; void GetSelectionBounds(base::string16::size_type* start, @@ -192,10 +196,6 @@ bool MaybeUnfocusTabButton(); // OmniboxView: - void SetWindowTextAndCaretPos(const base::string16& text, - size_t caret_pos, - bool update_popup, - bool notify_text_changed) override; void SetCaretPos(size_t caret_pos) override; void UpdatePopup() override; void ApplyCaretVisibility() override; @@ -273,7 +273,6 @@ void OnCompositingStarted(ui::Compositor* compositor, base::TimeTicks start_time) override; void OnCompositingEnded(ui::Compositor* compositor) override; - void OnCompositingChildResizing(ui::Compositor* compositor) override; void OnCompositingShuttingDown(ui::Compositor* compositor) override; // TemplateURLServiceObserver:
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc index 819d0da0..7e8706f 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -386,8 +386,7 @@ location_bar_model()->set_url(GURL("http://www.example.com/?query=1")); const base::string16 text = base::ASCIIToUTF16("http://www.example.com/?query=1"); - static_cast<OmniboxView*>(omnibox_view()) - ->SetWindowTextAndCaretPos(text, 23U, false, false); + omnibox_view()->SetWindowTextAndCaretPos(text, 23U, false, false); ui::KeyEvent shift_up_pressed(ui::ET_KEY_PRESSED, ui::VKEY_UP, ui::EF_SHIFT_DOWN); @@ -399,8 +398,7 @@ EXPECT_EQ(0U, end); omnibox_view()->CheckUpdatePopupNotCalled(); - static_cast<OmniboxView*>(omnibox_view()) - ->SetWindowTextAndCaretPos(text, 18U, false, false); + omnibox_view()->SetWindowTextAndCaretPos(text, 18U, false, false); ui::KeyEvent shift_down_pressed(ui::ET_KEY_PRESSED, ui::VKEY_DOWN, ui::EF_SHIFT_DOWN); @@ -431,8 +429,7 @@ omnibox_textfield()->OnFocus(); const base::string16 kContentsRtl = base::WideToUTF16(L"\x05e8\x05e2.\x05e7\x05d5\x05dd/0123/abcd"); - static_cast<OmniboxView*>(omnibox_view()) - ->SetWindowTextAndCaretPos(kContentsRtl, 0, false, false); + omnibox_view()->SetWindowTextAndCaretPos(kContentsRtl, 0, false, false); EXPECT_EQ(gfx::NO_ELIDE, render_text->elide_behavior()); // NOTE: Technically (depending on the font), this expectation could fail if // the entire domain fits in 60 pixels. However, 60px is so small it should @@ -497,14 +494,28 @@ } TEST_F(OmniboxViewViewsTest, RevertOnBlur) { - location_bar_model()->set_url(GURL("https://permanent-text.com/")); + location_bar_model()->set_url(GURL("https://example.com/")); omnibox_view()->model()->ResetDisplayTexts(); omnibox_view()->RevertAll(); - EXPECT_EQ(base::ASCIIToUTF16("https://permanent-text.com/"), - omnibox_view()->text()); + EXPECT_EQ(base::ASCIIToUTF16("https://example.com/"), omnibox_view()->text()); EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress()); + // Set the view text without updating the model's user text. This usually + // occurs when the omnibox unapplies Steady State Elisions to temporarily show + // the full URL to the user. + omnibox_view()->SetWindowTextAndCaretPos(base::ASCIIToUTF16("view text"), 0, + false, false); + EXPECT_EQ(base::ASCIIToUTF16("view text"), omnibox_view()->text()); + EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress()); + + // Expect that on blur, we revert to the original text and are not in user + // input mode. + omnibox_textfield()->OnBlur(); + EXPECT_EQ(base::ASCIIToUTF16("https://example.com/"), omnibox_view()->text()); + EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress()); + + // Now set user text, which is reflected into the model as well. omnibox_view()->SetUserText(base::ASCIIToUTF16("user text")); EXPECT_EQ(base::ASCIIToUTF16("user text"), omnibox_view()->text()); EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress()); @@ -513,16 +524,6 @@ omnibox_textfield()->OnBlur(); EXPECT_EQ(base::ASCIIToUTF16("user text"), omnibox_view()->text()); EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress()); - - // Expect that on blur, if the text is the same as the - // https://permanent-text.com, exit user input mode. - omnibox_view()->SetUserText( - base::ASCIIToUTF16("https://permanent-text.com/")); - EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress()); - omnibox_textfield()->OnBlur(); - EXPECT_EQ(base::ASCIIToUTF16("https://permanent-text.com/"), - omnibox_view()->text()); - EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress()); } TEST_F(OmniboxViewViewsTest, RevertOnEscape) { @@ -696,13 +697,7 @@ void ExpectFullUrlDisplayed() { EXPECT_EQ(base::UTF8ToUTF16(kFullUrl.spec()), omnibox_view()->text()); - EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress()); - - // We test the user text stored in the model has been updated as well. The - // model user text is used to populate the text in the Omnibox after some - // state transitions, such as the ZeroSuggest popup opening. - EXPECT_EQ(base::UTF8ToUTF16(kFullUrl.spec()), - omnibox_view()->model()->GetUserTextForTesting()); + EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress()); } bool IsElidedUrlDisplayed() {
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc index 75abe3f..5c8fa5e 100644 --- a/chrome/browser/ui/views/overlay/overlay_window_views.cc +++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -41,7 +41,9 @@ #if defined(OS_CHROMEOS) #include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/window_properties.h" // nogncheck +#include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" +#include "ui/base/ui_base_features.h" #endif // static @@ -227,6 +229,12 @@ #if defined(OS_CHROMEOS) GetNativeWindow()->SetProperty(ash::kWindowPipTypeKey, true); + if (features::IsUsingWindowService()) { + aura::Window* window = GetNativeWindow()->GetRootWindow(); + window->SetProperty(aura::client::kMinimumSize, + new gfx::Size(kMinWindowSize)); + window->SetProperty(aura::client::kMaximumSize, new gfx::Size(max_size_)); + } #endif // defined(OS_CHROMEOS) is_initialized_ = true; @@ -247,6 +255,12 @@ // Lower bound size of the window is a fixed value to allow for minimal sizes // on UI affordances, such as buttons. min_size_ = kMinWindowSize; +#if defined(OS_CHROMEOS) + if (features::IsUsingWindowService() && is_initialized_) { + GetNativeWindow()->GetRootWindow()->SetProperty(aura::client::kMaximumSize, + new gfx::Size(max_size_)); + } +#endif gfx::Size window_size = window_bounds_.size(); if (!has_been_shown_) {
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc index 50895ba..b4ea285 100644 --- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc +++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -460,8 +460,10 @@ PersonalDataLoadedObserverMock personal_data_observer; personal_data_manager->AddObserver(&personal_data_observer); base::RunLoop data_loop; - EXPECT_CALL(personal_data_observer, OnPersonalDataChanged()) + EXPECT_CALL(personal_data_observer, OnPersonalDataFinishedProfileTasks()) .WillOnce(QuitMessageLoop(&data_loop)); + EXPECT_CALL(personal_data_observer, OnPersonalDataChanged()) + .Times(testing::AnyNumber()); personal_data_manager->AddProfile(profile); data_loop.Run(); @@ -482,8 +484,11 @@ PersonalDataLoadedObserverMock personal_data_observer; personal_data_manager->AddObserver(&personal_data_observer); base::RunLoop data_loop; - EXPECT_CALL(personal_data_observer, OnPersonalDataChanged()) + EXPECT_CALL(personal_data_observer, OnPersonalDataFinishedProfileTasks()) .WillOnce(QuitMessageLoop(&data_loop)); + EXPECT_CALL(personal_data_observer, OnPersonalDataChanged()) + .Times(testing::AnyNumber()); + personal_data_manager->AddCreditCard(card); data_loop.Run(); @@ -491,6 +496,18 @@ EXPECT_EQ(card_count + 1, personal_data_manager->GetCreditCards().size()); } +void PaymentRequestBrowserTestBase::WaitForOnPersonalDataChanged() { + autofill::PersonalDataManager* personal_data_manager = GetDataManager(); + PersonalDataLoadedObserverMock personal_data_observer; + personal_data_manager->AddObserver(&personal_data_observer); + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer, OnPersonalDataChanged()) + .Times(testing::AnyNumber()); + run_loop.Run(); +} + void PaymentRequestBrowserTestBase::CreatePaymentRequestForTest( payments::mojom::PaymentRequestRequest request, content::RenderFrameHost* render_frame_host) {
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h index e9ad8447..db732e0 100644 --- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h +++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
@@ -55,6 +55,7 @@ ~PersonalDataLoadedObserverMock() override; MOCK_METHOD0(OnPersonalDataChanged, void()); + MOCK_METHOD0(OnPersonalDataFinishedProfileTasks, void()); }; // Base class for any interactive PaymentRequest test that will need to open @@ -178,6 +179,7 @@ // are added close to each other. void AddAutofillProfile(const autofill::AutofillProfile& profile); void AddCreditCard(const autofill::CreditCard& card); + void WaitForOnPersonalDataChanged(); void CreatePaymentRequestForTest( payments::mojom::PaymentRequestRequest request,
diff --git a/chrome/browser/ui/views/payments/payment_request_use_stats_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_use_stats_browsertest.cc index 4384e63..14dfc32 100644 --- a/chrome/browser/ui/views/payments/payment_request_use_stats_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_use_stats_browsertest.cc
@@ -62,6 +62,7 @@ InvokePaymentRequestUI(); ResetEventWaiter(DialogEvent::DIALOG_CLOSED); PayWithCreditCardAndWait(base::ASCIIToUTF16("123")); + WaitForOnPersonalDataChanged(); // Check that the usage of the card was recorded. autofill::CreditCard* updated_card = @@ -111,6 +112,7 @@ InvokePaymentRequestUI(); ResetEventWaiter(DialogEvent::DIALOG_CLOSED); PayWithCreditCardAndWait(base::ASCIIToUTF16("123")); + WaitForOnPersonalDataChanged(); // Check that the usage of the profile was recorded. autofill::AutofillProfile* updated_shipping = @@ -159,6 +161,7 @@ InvokePaymentRequestUI(); ResetEventWaiter(DialogEvent::DIALOG_CLOSED); PayWithCreditCardAndWait(base::ASCIIToUTF16("123")); + WaitForOnPersonalDataChanged(); // Check that the usage of the profile was recorded. autofill::AutofillProfile* updated_contact = @@ -209,6 +212,7 @@ InvokePaymentRequestUI(); ResetEventWaiter(DialogEvent::DIALOG_CLOSED); PayWithCreditCardAndWait(base::ASCIIToUTF16("123")); + WaitForOnPersonalDataChanged(); // Check that the usage of the profile was only recorded once. autofill::AutofillProfile* updated_multi =
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc index ef1ce60..d85868b78 100644 --- a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc +++ b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
@@ -7,6 +7,7 @@ #include <memory> #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/shell_test_api.test-mojom.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h"
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc index 469085a..d06bc67b 100644 --- a/chrome/browser/ui/views/tabs/tab.cc +++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -249,13 +249,8 @@ if (showing_icon_) { // Height should go to the bottom of the tab for the crashed tab animation // to pop out of the bottom. - favicon_bounds.set_y( - contents_rect.y() + - Center(contents_rect.height(), - gfx::kFaviconSize + icon_->GetInsets().height())); - favicon_bounds.set_size( - gfx::Size(icon_->GetPreferredSize().width(), - contents_rect.height() - favicon_bounds.y())); + favicon_bounds.set_y(contents_rect.y() + + Center(contents_rect.height(), gfx::kFaviconSize)); if (center_icon_) { // When centering the favicon, the favicon is allowed to escape the normal // contents rect. @@ -263,6 +258,11 @@ } else { MaybeAdjustLeftForPinnedTab(&favicon_bounds, gfx::kFaviconSize); } + // Add space for insets outside the favicon bounds. + favicon_bounds.Inset(-icon_->GetInsets()); + favicon_bounds.set_size( + gfx::Size(icon_->GetPreferredSize().width(), + contents_rect.height() - favicon_bounds.y())); } icon_->SetBoundsRect(favicon_bounds); icon_->SetVisible(showing_icon_); @@ -339,7 +339,8 @@ // icon view width (which will include extra room for the alert // indicator), but rather the normal favicon width which is what it will // look like. - const int after_favicon = favicon_bounds.x() + gfx::kFaviconSize + + const int after_favicon = favicon_bounds.x() + icon_->GetInsets().left() + + gfx::kFaviconSize + GetLayoutConstant(TAB_PRE_TITLE_PADDING); title_left = std::max(title_left, after_favicon); }
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc index 972de91..41fc42e 100644 --- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc +++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
@@ -80,10 +80,16 @@ AppMenuIconController::TypeAndSeverity type_and_severity) { type_and_severity_ = type_and_severity; - SetTooltipText( - type_and_severity_.severity == AppMenuIconController::Severity::NONE - ? l10n_util::GetStringUTF16(IDS_APPMENU_TOOLTIP) - : l10n_util::GetStringUTF16(IDS_APPMENU_TOOLTIP_UPDATE_AVAILABLE)); + int message_id; + if (type_and_severity.severity == AppMenuIconController::Severity::NONE) { + message_id = IDS_APPMENU_TOOLTIP; + } else if (type_and_severity.type == + AppMenuIconController::IconType::UPGRADE_NOTIFICATION) { + message_id = IDS_APPMENU_TOOLTIP_UPDATE_AVAILABLE; + } else { + message_id = IDS_APPMENU_TOOLTIP_ALERT; + } + SetTooltipText(l10n_util::GetStringUTF16(message_id)); UpdateIcon(); }
diff --git a/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc index c43fe5c8..b9fb995 100644 --- a/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc
@@ -59,8 +59,8 @@ void AppDownloadingScreenHandler::Show() { ShowScreen(kScreenId); - CallJSWithPrefix("updateNumberOfSelectedApps", - base::Value(GetNumberOfUserSelectedApps())); + CallJS("login.AppDownloadingScreen.updateNumberOfSelectedApps", + base::Value(GetNumberOfUserSelectedApps())); } void AppDownloadingScreenHandler::Hide() {}
diff --git a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc index b05ff748..1349a4a 100644 --- a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
@@ -114,7 +114,7 @@ } void AppLaunchSplashScreenHandler::ToggleNetworkConfig(bool visible) { - CallJSWithPrefix("toggleNetworkConfig", visible); + CallJS("login.AppLaunchSplashScreen.toggleNetworkConfig", visible); } void AppLaunchSplashScreenHandler::UpdateAppLaunchState(AppLaunchState state) { @@ -228,7 +228,7 @@ } void AppLaunchSplashScreenHandler::SetLaunchText(const std::string& text) { - CallJSWithPrefix("updateMessage", text); + CallJS("login.AppLaunchSplashScreen.updateMessage", text); } int AppLaunchSplashScreenHandler::GetProgressMessageFromState(
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.cc index 53d5efa3..e20d080d 100644 --- a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.cc
@@ -94,7 +94,7 @@ } void ArcKioskSplashScreenHandler::SetLaunchText(const std::string& text) { - CallJSWithPrefix("updateArcKioskMessage", text); + CallJS("login.ArcKioskSplashScreen.updateArcKioskMessage", text); } int ArcKioskSplashScreenHandler::GetProgressMessageFromState(
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc index b5c64ad..c7d1051 100644 --- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
@@ -87,7 +87,7 @@ if (!ignore_network_state && !default_network) return; const std::string country_code = base::CountryCodeForCurrentTimezone(); - CallJSWithPrefix("loadPlayStoreToS", country_code); + CallJS("login.ArcTermsOfServiceScreen.loadPlayStoreToS", country_code); } void ArcTermsOfServiceScreenHandler::OnCurrentScreenChanged( @@ -192,20 +192,22 @@ : IDS_ARC_OOBE_TERMS_DIALOG_METRICS_MANAGED_DISABLED; } } - CallJSWithPrefix("setMetricsMode", l10n_util::GetStringUTF16(message_id), - true); + CallJS("login.ArcTermsOfServiceScreen.setMetricsMode", + l10n_util::GetStringUTF16(message_id), true); } void ArcTermsOfServiceScreenHandler::OnBackupAndRestoreModeChanged( bool enabled, bool managed) { backup_restore_managed_ = managed; - CallJSWithPrefix("setBackupAndRestoreMode", enabled, managed); + CallJS("login.ArcTermsOfServiceScreen.setBackupAndRestoreMode", enabled, + managed); } void ArcTermsOfServiceScreenHandler::OnLocationServicesModeChanged( bool enabled, bool managed) { location_services_managed_ = managed; - CallJSWithPrefix("setLocationServicesMode", enabled, managed); + CallJS("login.ArcTermsOfServiceScreen.setLocationServicesMode", enabled, + managed); } void ArcTermsOfServiceScreenHandler::AddObserver( @@ -269,7 +271,7 @@ Profile* profile = ProfileManager::GetActiveUserProfile(); CHECK(profile); - CallJSWithPrefix("clearDemoMode"); + CallJS("login.ArcTermsOfServiceScreen.clearDemoMode"); // Enable ARC to match ArcSessionManager logic. ArcSessionManager expects that // ARC is enabled (prefs::kArcEnabled = true) on showing Terms of Service. If @@ -280,7 +282,7 @@ // Hide the Skip button if the ToS screen can not be skipped during OOBE. if (base::CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kEnableArcOobeOptinNoSkip)) { - CallJSWithPrefix("hideSkipButton"); + CallJS("login.ArcTermsOfServiceScreen.hideSkipButton"); } action_taken_ = false; @@ -288,7 +290,7 @@ ShowScreen(kScreenId); arc_managed_ = arc::IsArcPlayStoreEnabledPreferenceManagedForProfile(profile); - CallJSWithPrefix("setArcManaged", arc_managed_); + CallJS("login.ArcTermsOfServiceScreen.setArcManaged", arc_managed_); MaybeLoadPlayStoreToS(true); StartNetworkAndTimeZoneObserving(); @@ -301,7 +303,7 @@ void ArcTermsOfServiceScreenHandler::DoShowForDemoModeSetup() { DCHECK(arc::IsArcDemoModeSetupFlow()); - CallJSWithPrefix("setupForDemoMode"); + CallJS("login.ArcTermsOfServiceScreen.setupForDemoMode"); action_taken_ = false; ShowScreen(kScreenId); MaybeLoadPlayStoreToS(true);
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc index a65fffc..484921a 100644 --- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
@@ -161,16 +161,19 @@ } void AssistantOptInFlowScreenHandler::OnListeningHotword() { - CallJSWithPrefix("onVoiceMatchUpdate", base::Value("listen")); + CallJS("login.AssistantOptInFlowScreen.onVoiceMatchUpdate", + base::Value("listen")); } void AssistantOptInFlowScreenHandler::OnProcessingHotword() { - CallJSWithPrefix("onVoiceMatchUpdate", base::Value("process")); + CallJS("login.AssistantOptInFlowScreen.onVoiceMatchUpdate", + base::Value("process")); } void AssistantOptInFlowScreenHandler::OnSpeakerIdEnrollmentDone() { settings_manager_->StopSpeakerIdEnrollment(base::DoNothing()); - CallJSWithPrefix("onVoiceMatchUpdate", base::Value("done")); + CallJS("login.AssistantOptInFlowScreen.onVoiceMatchUpdate", + base::Value("done")); } void AssistantOptInFlowScreenHandler::OnSpeakerIdEnrollmentFailure() { @@ -192,7 +195,7 @@ } void AssistantOptInFlowScreenHandler::ShowNextScreen() { - CallJSWithPrefix("showNextScreen"); + CallJS("login.AssistantOptInFlowScreen.showNextScreen"); } void AssistantOptInFlowScreenHandler::OnActivityControlOptInResult( @@ -271,12 +274,12 @@ } void AssistantOptInFlowScreenHandler::ReloadContent(const base::Value& dict) { - CallJSWithPrefix("reloadContent", dict); + CallJS("login.AssistantOptInFlowScreen.reloadContent", dict); } void AssistantOptInFlowScreenHandler::AddSettingZippy(const std::string& type, const base::Value& data) { - CallJSWithPrefix("addSettingZippy", type, data); + CallJS("login.AssistantOptInFlowScreen.addSettingZippy", type, data); } void AssistantOptInFlowScreenHandler::OnGetSettingsResponse( @@ -490,7 +493,7 @@ if (screen_) screen_->OnUserAction(kFlowFinished); else - CallJSWithPrefix("closeDialog"); + CallJS("login.AssistantOptInFlowScreen.closeDialog"); } void AssistantOptInFlowScreenHandler::HandleFlowInitialized(
diff --git a/chrome/browser/ui/webui/chromeos/login/base_webui_handler.cc b/chrome/browser/ui/webui/chromeos/login/base_webui_handler.cc index a5a6172..bd3c4c6 100644 --- a/chrome/browser/ui/webui/chromeos/login/base_webui_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/base_webui_handler.cc
@@ -16,10 +16,6 @@ namespace chromeos { -namespace { -const char kMethodContextChanged[] = "contextChanged"; -} // namespace - JSCallsContainer::JSCallsContainer() = default; JSCallsContainer::~JSCallsContainer() = default; @@ -66,7 +62,7 @@ if (!page_is_ready()) pending_context_changes_.MergeDictionary(&diff); else - CallJSWithPrefix(kMethodContextChanged, diff); + CallJS(FullMethodPath("contextChanged"), diff); } void BaseWebUIHandler::GetAdditionalParameters(base::DictionaryValue* dict) {} @@ -75,10 +71,6 @@ web_ui()->CallJavascriptFunctionUnsafe(method); } -void BaseWebUIHandler::CallJSWithPrefix(const std::string& method) { - CallJS(FullMethodPath(method)); -} - void BaseWebUIHandler::ShowScreen(OobeScreen screen) { ShowScreenWithData(screen, nullptr); }
diff --git a/chrome/browser/ui/webui/chromeos/login/base_webui_handler.h b/chrome/browser/ui/webui/chromeos/login/base_webui_handler.h index eda314c..d699a2a 100644 --- a/chrome/browser/ui/webui/chromeos/login/base_webui_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/base_webui_handler.h
@@ -119,11 +119,7 @@ // with Context at some point. virtual void GetAdditionalParameters(base::DictionaryValue* parameters); - // Returns full name of JS method based on screen and method - // names. - std::string FullMethodPath(const std::string& method) const; - - // Call a JavaScript method. + // Shortcut for calling JS methods on WebUI side. void CallJS(const std::string& method); template <typename A1> @@ -158,38 +154,6 @@ ::login::MakeValue(arg3), ::login::MakeValue(arg4)); } - // Shortcut for calling JS methods on WebUI side. - void CallJSWithPrefix(const std::string& method); - - template <typename A1> - void CallJSWithPrefix(const std::string& method, const A1& arg1) { - CallJS(FullMethodPath(method), arg1); - } - - template <typename A1, typename A2> - void CallJSWithPrefix(const std::string& method, - const A1& arg1, - const A2& arg2) { - CallJS(FullMethodPath(method), arg1, arg2); - } - - template <typename A1, typename A2, typename A3> - void CallJSWithPrefix(const std::string& method, - const A1& arg1, - const A2& arg2, - const A3& arg3) { - CallJS(FullMethodPath(method), arg1, arg2, arg3); - } - - template <typename A1, typename A2, typename A3, typename A4> - void CallJSWithPrefix(const std::string& method, - const A1& arg1, - const A2& arg2, - const A3& arg3, - const A4& arg4) { - CallJS(FullMethodPath(method), arg1, arg2, arg3, arg4); - } - template <typename... Args> void CallJSOrDefer(const std::string& function_name, const Args&... args) { DCHECK(js_calls_container_); @@ -266,6 +230,9 @@ CallJS(function_name, *args...); } + // Returns full name of JS method based on screen and method names. + std::string FullMethodPath(const std::string& method) const; + // Handles user action. void HandleUserAction(const std::string& action_id);
diff --git a/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.cc index 475a236..946f9882 100644 --- a/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.cc
@@ -44,17 +44,16 @@ void DemoSetupScreenHandler::OnSetupFailed( const DemoSetupController::DemoSetupError& error) { // TODO(wzang): Consider customization for RecoveryMethod::kReboot as well. - CallJSWithPrefix( - "onSetupFailed", - base::JoinString({error.GetLocalizedErrorMessage(), - error.GetLocalizedRecoveryMessage()}, - base::UTF8ToUTF16(" ")), - error.recovery_method() == - DemoSetupController::DemoSetupError::RecoveryMethod::kPowerwash); + CallJS("login.DemoSetupScreen.onSetupFailed", + base::JoinString({error.GetLocalizedErrorMessage(), + error.GetLocalizedRecoveryMessage()}, + base::UTF8ToUTF16(" ")), + error.recovery_method() == + DemoSetupController::DemoSetupError::RecoveryMethod::kPowerwash); } void DemoSetupScreenHandler::OnSetupSucceeded() { - CallJSWithPrefix("onSetupSucceeded"); + CallJS("login.DemoSetupScreen.onSetupSucceeded"); } void DemoSetupScreenHandler::Initialize() {}
diff --git a/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.cc index 17260ec..117719f 100644 --- a/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.cc
@@ -34,10 +34,9 @@ } if (delegate_) { - CallJSWithPrefix("setSerialNumberAndEnrollmentDomain", - delegate_->GetSerialNumber(), - delegate_->GetEnrollmentDomain()); - CallJSWithPrefix("setMessage", delegate_->GetMessage()); + CallJS("login.DeviceDisabledScreen.setSerialNumberAndEnrollmentDomain", + delegate_->GetSerialNumber(), delegate_->GetEnrollmentDomain()); + CallJS("login.DeviceDisabledScreen.setMessage", delegate_->GetMessage()); } ShowScreen(kScreenId); } @@ -54,7 +53,7 @@ void DeviceDisabledScreenHandler::UpdateMessage(const std::string& message) { if (page_is_ready()) - CallJSWithPrefix("setMessage", message); + CallJS("login.DeviceDisabledScreen.setMessage", message); } void DeviceDisabledScreenHandler::DeclareLocalizedValues(
diff --git a/chrome/browser/ui/webui/chromeos/login/discover/modules/discover_module_launch_help_app.cc b/chrome/browser/ui/webui/chromeos/login/discover/modules/discover_module_launch_help_app.cc index d628b071..54ddfb4 100644 --- a/chrome/browser/ui/webui/chromeos/login/discover/modules/discover_module_launch_help_app.cc +++ b/chrome/browser/ui/webui/chromeos/login/discover/modules/discover_module_launch_help_app.cc
@@ -45,7 +45,7 @@ void DiscoverModuleLaunchHelpAppHandler::Initialize() {} void DiscoverModuleLaunchHelpAppHandler::RegisterMessages() { - AddCallback(FullMethodPath("handleLaunchHelpApp"), + AddCallback("discover.launch-help-app.handleLaunchHelpApp", &DiscoverModuleLaunchHelpAppHandler::HandleLaunchHelpApp); }
diff --git a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc index f2d75b5b..89bff4f 100644 --- a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
@@ -87,7 +87,7 @@ const base::string16& network_id) {} void NetworkScreenHandler::SetOfflineDemoModeEnabled(bool enabled) { - CallJSWithPrefix("setOfflineDemoModeEnabled", enabled); + CallJS("login.NetworkScreen.setOfflineDemoModeEnabled", enabled); } void NetworkScreenHandler::DeclareLocalizedValues(
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc b/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc index ab90e90..9eeb51f 100644 --- a/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc +++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h" #include "ash/public/interfaces/constants.mojom.h" +#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/shell_test_api.test-mojom.h" #include "chrome/browser/chromeos/login/login_manager_test.h" #include "chrome/browser/chromeos/login/startup_utils.h"
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc index 6aea49cf..973084a 100644 --- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc +++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
@@ -10,6 +10,7 @@ #include "base/path_service.h" #include "base/strings/string_util.h" #include "base/threading/thread_restrictions.h" +#include "chrome/browser/extensions/activity_log/activity_log.h" #include "chrome/browser/extensions/api/developer_private/developer_private_api.h" #include "chrome/browser/extensions/chrome_test_extension_loader.h" #include "chrome/browser/extensions/unpacked_installer.h" @@ -219,6 +220,31 @@ } } +IN_PROC_BROWSER_TEST_F(ExtensionSettingsUIBrowserTest, + ActivityLogInactiveWithoutSwitch) { + // Navigate to chrome://extensions which is a whitelisted URL for the + // chrome.activityLogPrivate API. + GURL extensions_url("chrome://extensions"); + ui_test_utils::NavigateToURL(browser(), extensions_url); + content::WebContents* page_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_TRUE(page_contents); + + // Attempt to add an event listener for the + // activityLogPrivate.onExtensionActivity event. + ASSERT_TRUE(content::ExecuteScript(page_contents, R"( + let activityLogListener = () => {}; + chrome.activityLogPrivate.onExtensionActivity.addListener( + activityLogListener); + )")); + + // Activity log will be inactive as the command line switch is not present and + // no whitelisted extensions for activityLogPrivate are enabled. + extensions::ActivityLog* activity_log = + extensions::ActivityLog::GetInstance(browser()->profile()); + ASSERT_FALSE(activity_log->is_active()); +} + class ExtensionsActivityLogTest : public ExtensionSettingsUIBrowserTest { protected: // Enable command line flags for test.
diff --git a/chrome/browser/ui/webui/management_ui.cc b/chrome/browser/ui/webui/management_ui.cc index 7e6b3d1..9820ea7 100644 --- a/chrome/browser/ui/webui/management_ui.cc +++ b/chrome/browser/ui/webui/management_ui.cc
@@ -12,6 +12,7 @@ #include "chrome/grit/browser_resources.h" #include "components/strings/grit/components_strings.h" #include "content/public/browser/web_ui.h" +#include "extensions/buildflags/buildflags.h" namespace { @@ -21,6 +22,8 @@ source->AddLocalizedString("title", IDS_MANAGEMENT_TITLE); source->AddLocalizedString("deviceReporting", IDS_MANAGEMENT_DEVICE_REPORTING); + source->AddLocalizedString("browserReporting", + IDS_MANAGEMENT_BROWSER_REPORTING); source->AddLocalizedString("deviceConfiguration", IDS_MANAGEMENT_DEVICE_CONFIGURATION); source->AddLocalizedString("extensionReporting", @@ -47,6 +50,31 @@ source->AddLocalizedString("managementDesktopMonitoringNotice", IDS_MANAGEMENT_DESKTOP_MONITORING_NOTICE); +#if BUILDFLAG(ENABLE_EXTENSIONS) + source->AddLocalizedString(kManagementExtensionReportMachineName, + IDS_MANAGEMENT_EXTENSION_REPORT_MACHINE_NAME); + source->AddLocalizedString( + kManagementExtensionReportMachineNameAddress, + IDS_MANAGEMENT_EXTENSION_REPORT_MACHINE_NAME_ADDRESS); + source->AddLocalizedString(kManagementExtensionReportUsername, + IDS_MANAGEMENT_EXTENSION_REPORT_USERNAME); + source->AddLocalizedString(kManagementExtensionReportVersion, + IDS_MANAGEMENT_EXTENSION_REPORT_VERSION); + source->AddLocalizedString(kManagementExtensionReportPolicies, + IDS_MANAGEMENT_EXTENSION_REPORT_POLICIES); + source->AddLocalizedString( + kManagementExtensionReportExtensionsPlugin, + IDS_MANAGEMENT_EXTENSION_REPORT_EXTENSIONS_PLUGINS); + source->AddLocalizedString( + kManagementExtensionReportSafeBrowsingWarnings, + IDS_MANAGEMENT_EXTENSION_REPORT_SAFE_BROWSING_WARNINGS); + source->AddLocalizedString(kManagementExtensionReportPerfCrash, + IDS_MANAGEMENT_EXTENSION_REPORT_PERF_CRASH); + source->AddLocalizedString( + kManagementExtensionReportWebsiteUsageStatistics, + IDS_MANAGEMENT_EXTENSION_REPORT_WEBSITE_USAGE_STATISTICS); +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + #if defined(OS_CHROMEOS) source->AddLocalizedString("managementTrustRootsConfigured", IDS_MANAGEMENT_TRUST_ROOTS_CONFIGURED);
diff --git a/chrome/browser/ui/webui/management_ui_handler.cc b/chrome/browser/ui/webui/management_ui_handler.cc index 0a2f512..d52ad27 100644 --- a/chrome/browser/ui/webui/management_ui_handler.cc +++ b/chrome/browser/ui/webui/management_ui_handler.cc
@@ -20,7 +20,6 @@ #include "chrome/browser/profiles/profile.h" #include "components/strings/grit/components_strings.h" #include "content/public/browser/web_contents.h" -#include "extensions/buildflags/buildflags.h" #include "ui/base/l10n/l10n_util.h" #if defined(OS_CHROMEOS) @@ -35,13 +34,37 @@ #endif // defined(OS_CHROMEOS) #if BUILDFLAG(ENABLE_EXTENSIONS) +#include "chrome/browser/policy/profile_policy_connector.h" +#include "chrome/browser/policy/profile_policy_connector_factory.h" #include "chrome/common/extensions/permissions/chrome_permission_message_provider.h" +#include "components/policy/core/common/policy_map.h" +#include "components/policy/core/common/policy_namespace.h" +#include "components/policy/core/common/policy_service.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" #include "extensions/common/extension_set.h" #include "extensions/common/manifest.h" #include "extensions/common/permissions/permission_message_provider.h" #include "extensions/common/permissions/permissions_data.h" + +const char kManagementExtensionReportMachineName[] = + "managementExtensionReportMachineName"; +const char kManagementExtensionReportMachineNameAddress[] = + "managementExtensionReportMachineNameAddress"; +const char kManagementExtensionReportUsername[] = + "managementExtensionReportUsername"; +const char kManagementExtensionReportVersion[] = + "managementExtensionReportVersion"; +const char kManagementExtensionReportPolicies[] = + "managementExtensionReportPolicies"; +const char kManagementExtensionReportExtensionsPlugin[] = + "managementExtensionReportExtensionsPlugin"; +const char kManagementExtensionReportSafeBrowsingWarnings[] = + "managementExtensionReportSafeBrowsingWarnings"; +const char kManagementExtensionReportPerfCrash[] = + "managementExtensionReportPerfCrash"; +const char kManagementExtensionReportWebsiteUsageStatistics[] = + "managementExtensionReportTimePerSite"; #endif // BUILDFLAG(ENABLE_EXTENSIONS) const char kManagementLogUploadEnabled[] = "managementLogUploadEnabled"; @@ -213,6 +236,21 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) +const char kOnPremReportingExtensionStableId[] = + "emahakmocgideepebncgnmlmliepgpgb"; +const char kOnPremReportingExtensionBetaId[] = + "kigjhoekjcpdfjpimbdjegmgecmlicaf"; +const char kCloudReportingExtensionId[] = "empjldejiginopiohodkdoklcjklbaa"; +const char kPolicyKeyReportMachineIdData[] = "report_machine_id_data"; +const char kPolicyKeyReportUserIdData[] = "report_user_id_data"; +const char kPolicyKeyReportVersionData[] = "report_version_data"; +const char kPolicyKeyReportPolicyData[] = "report_policy_data"; +const char kPolicyKeyReportExtensionsData[] = "report_extensions_data"; +const char kPolicyKeyReportSafeBrowsingData[] = "report_safe_browsing_data"; +const char kPolicyKeyReportSystemTelemetryData[] = + "report_system_telemetry_data"; +const char kPolicyKeyReportUserBrowsingData[] = "report_user_browsing_data"; + std::vector<base::Value> GetPermissionsForExtension( scoped_refptr<const extensions::Extension> extension) { std::vector<base::Value> permission_messages; @@ -294,6 +332,10 @@ base::BindRepeating(&ManagementUIHandler::HandleGetReportingInfo, base::Unretained(this))); web_ui()->RegisterMessageCallback( + "getBrowserReportingInfo", + base::BindRepeating(&ManagementUIHandler::HandleGetBrowserReportingInfo, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "getExtensions", base::BindRepeating(&ManagementUIHandler::HandleGetExtensions, base::Unretained(this))); @@ -405,6 +447,20 @@ report_sources); } +void ManagementUIHandler::HandleGetBrowserReportingInfo( + const base::ListValue* args) { + base::Value report_sources(base::Value::Type::LIST); + AllowJavascript(); + +// Only browsers with extensions enabled report status. +#if BUILDFLAG(ENABLE_EXTENSIONS) + AddExtensionReportingInfo(&report_sources); +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + + ResolveJavascriptCallback(args->GetList()[0] /* callback_id */, + report_sources); +} + void ManagementUIHandler::HandleGetExtensions(const base::ListValue* args) { AllowJavascript(); #if BUILDFLAG(ENABLE_EXTENSIONS) @@ -440,3 +496,83 @@ ResolveJavascriptCallback(args->GetList()[0] /* callback_id */, trust_roots_configured); } + +#if BUILDFLAG(ENABLE_EXTENSIONS) +void ManagementUIHandler::AddExtensionReportingInfo( + base::Value* report_sources) { + std::unordered_set<std::string> messages; + + const extensions::Extension* cloud_reporting_extension = + extensions::ExtensionRegistry::Get(Profile::FromWebUI(web_ui())) + ->GetExtensionById(kCloudReportingExtensionId, + extensions::ExtensionRegistry::ENABLED); + + if (cloud_reporting_extension != nullptr) { + messages.insert(kManagementExtensionReportMachineName); + messages.insert(kManagementExtensionReportUsername); + messages.insert(kManagementExtensionReportVersion); + messages.insert(kManagementExtensionReportPolicies); + messages.insert(kManagementExtensionReportExtensionsPlugin); + messages.insert(kManagementExtensionReportSafeBrowsingWarnings); + } + + policy::PolicyNamespace on_prem_reporting_extension_stable_policy_namespace = + policy::PolicyNamespace(policy::POLICY_DOMAIN_EXTENSIONS, + kOnPremReportingExtensionStableId); + policy::PolicyNamespace on_prem_reporting_extension_beta_policy_namespace = + policy::PolicyNamespace(policy::POLICY_DOMAIN_EXTENSIONS, + kOnPremReportingExtensionBetaId); + + const policy::PolicyService* policyService = + policy::ProfilePolicyConnectorFactory::GetForBrowserContext( + Profile::FromWebUI(web_ui())) + ->policy_service(); + + const policy::PolicyMap& on_prem_reporting_extension_stable_policy_map = + policyService->GetPolicies( + on_prem_reporting_extension_stable_policy_namespace); + const policy::PolicyMap& on_prem_reporting_extension_beta_policy_map = + policyService->GetPolicies( + on_prem_reporting_extension_beta_policy_namespace); + + const policy::PolicyMap* policy_maps[] = { + &on_prem_reporting_extension_stable_policy_map, + &on_prem_reporting_extension_beta_policy_map}; + + static const struct { + const char* policy_key; + const char* message; + } policy_keys_messages[] = { + {kPolicyKeyReportMachineIdData, + kManagementExtensionReportMachineNameAddress}, + {kPolicyKeyReportUserIdData, kManagementExtensionReportUsername}, + {kPolicyKeyReportVersionData, kManagementExtensionReportVersion}, + {kPolicyKeyReportPolicyData, kManagementExtensionReportPolicies}, + {kPolicyKeyReportExtensionsData, + kManagementExtensionReportExtensionsPlugin}, + {kPolicyKeyReportSafeBrowsingData, + kManagementExtensionReportSafeBrowsingWarnings}, + {kPolicyKeyReportSystemTelemetryData, + kManagementExtensionReportPerfCrash}, + {kPolicyKeyReportUserBrowsingData, + kManagementExtensionReportWebsiteUsageStatistics}}; + + for (const auto* policy_map : policy_maps) { + for (const auto& policy_key_message : policy_keys_messages) { + const base::Value* policy_value = + policy_map->GetValue(policy_key_message.policy_key); + if (policy_value && policy_value->is_bool() && policy_value->GetBool()) + messages.insert(policy_key_message.message); + } + } + + if (messages.find(kManagementExtensionReportMachineNameAddress) != + messages.end()) { + messages.erase(kManagementExtensionReportMachineName); + } + + for (const auto& message : messages) { + report_sources->GetList().push_back(base::Value(message)); + } +} +#endif // BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/ui/webui/management_ui_handler.h b/chrome/browser/ui/webui/management_ui_handler.h index ae85569..0f70364 100644 --- a/chrome/browser/ui/webui/management_ui_handler.h +++ b/chrome/browser/ui/webui/management_ui_handler.h
@@ -10,6 +10,7 @@ #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" #include "content/public/browser/web_ui_message_handler.h" +#include "extensions/buildflags/buildflags.h" // Constants defining the IDs for the localized strings sent to the page as // load time data. @@ -19,6 +20,18 @@ extern const char kManagementReportNetworkInterfaces[]; extern const char kManagementReportUsers[]; +#if BUILDFLAG(ENABLE_EXTENSIONS) +extern const char kManagementExtensionReportMachineName[]; +extern const char kManagementExtensionReportMachineNameAddress[]; +extern const char kManagementExtensionReportUsername[]; +extern const char kManagementExtensionReportVersion[]; +extern const char kManagementExtensionReportPolicies[]; +extern const char kManagementExtensionReportExtensionsPlugin[]; +extern const char kManagementExtensionReportSafeBrowsingWarnings[]; +extern const char kManagementExtensionReportPerfCrash[]; +extern const char kManagementExtensionReportWebsiteUsageStatistics[]; +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + namespace base { class ListValue; } // namespace base @@ -47,10 +60,16 @@ void HandleGetReportingInfo(const base::ListValue* args); + void HandleGetBrowserReportingInfo(const base::ListValue* args); + void HandleGetExtensions(const base::ListValue* args); void HandleGetLocalTrustRootsInfo(const base::ListValue* args); +#if BUILDFLAG(ENABLE_EXTENSIONS) + void AddExtensionReportingInfo(base::Value* report_sources); +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + DISALLOW_COPY_AND_ASSIGN(ManagementUIHandler); };
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc index e7a3a9f..4f0138f 100644 --- a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc
@@ -392,9 +392,7 @@ dict.SetInteger(kLidClosedBehaviorKey, lid_closed_behavior); dict.SetBoolean(kLidClosedControlledKey, lid_closed_controlled); dict.SetBoolean(kHasLidKey, has_lid); - CallJavascriptFunction("cr.webUIListenerCallback", - base::Value(kPowerManagementSettingsChangedName), - dict); + FireWebUIListener(kPowerManagementSettingsChangedName, dict); last_idle_behavior_ = idle_behavior; last_idle_controlled_ = idle_controlled;
diff --git a/chrome/browser/ui/webui/settings/font_handler.cc b/chrome/browser/ui/webui/settings/font_handler.cc index ffb8f495..1406eb7a 100644 --- a/chrome/browser/ui/webui/settings/font_handler.cc +++ b/chrome/browser/ui/webui/settings/font_handler.cc
@@ -108,10 +108,8 @@ } void FontHandler::NotifyAdvancedFontSettingsAvailability() { - CallJavascriptFunction( - "cr.webUIListenerCallback", - base::Value("advanced-font-settings-installed"), - base::Value(GetAdvancedFontSettingsExtension() != nullptr)); + FireWebUIListener("advanced-font-settings-installed", + base::Value(GetAdvancedFontSettingsExtension() != nullptr)); } void FontHandler::OnExtensionLoaded(content::BrowserContext*,
diff --git a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc index 9af3e6b..145aa95 100644 --- a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc +++ b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc
@@ -339,8 +339,8 @@ void ClearBrowsingDataHandler::UpdateSyncState() { identity::IdentityManager* identity_manager = IdentityManagerFactory::GetForProfile(profile_); - CallJavascriptFunction( - "cr.webUIListenerCallback", base::Value("update-sync-state"), + FireWebUIListener( + "update-sync-state", base::Value(identity_manager && identity_manager->HasPrimaryAccount()), base::Value(sync_service_ && sync_service_->IsSyncFeatureActive() && sync_service_->GetActiveDataTypes().Has( @@ -383,9 +383,8 @@ void ClearBrowsingDataHandler::UpdateCounterText( std::unique_ptr<browsing_data::BrowsingDataCounter::Result> result) { - CallJavascriptFunction( - "cr.webUIListenerCallback", base::Value("update-counter-text"), - base::Value(result->source()->GetPrefName()), + FireWebUIListener( + "update-counter-text", base::Value(result->source()->GetPrefName()), base::Value(browsing_data_counter_utils::GetChromeCounterTextFromResult( result.get(), profile_))); }
diff --git a/chrome/browser/ui/webui/settings/settings_import_data_handler.cc b/chrome/browser/ui/webui/settings/settings_import_data_handler.cc index 32deebd..f546887 100644 --- a/chrome/browser/ui/webui/settings/settings_import_data_handler.cc +++ b/chrome/browser/ui/webui/settings/settings_import_data_handler.cc
@@ -209,10 +209,9 @@ importer_host_->set_observer(NULL); importer_host_ = NULL; - CallJavascriptFunction( - "cr.webUIListenerCallback", base::Value("import-data-status-changed"), - base::Value(import_did_succeed_ ? kImportStatusSucceeded - : kImportStatusFailed)); + FireWebUIListener("import-data-status-changed", + base::Value(import_did_succeed_ ? kImportStatusSucceeded + : kImportStatusFailed)); } void ImportDataHandler::FileSelected(const base::FilePath& path,
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc index 0da5b990..fb90a10 100644 --- a/chrome/browser/ui/webui/settings/site_settings_handler.cc +++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -312,7 +312,6 @@ } void SiteSettingsHandler::RegisterMessages() { - EnsureCookiesTreeModelCreated(); web_ui()->RegisterMessageCallback( "fetchUsageTotal", @@ -465,38 +464,26 @@ #endif } -void SiteSettingsHandler::OnGetUsageInfo( - const storage::UsageInfoEntries& entries) { +void SiteSettingsHandler::OnGetUsageInfo() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - for (const auto& entry : entries) { - if (entry.usage <= 0) continue; - if (entry.host == usage_host_) { - CallJavascriptFunction("settings.WebsiteUsagePrivateApi.returnUsageTotal", - base::Value(entry.host), - base::Value(ui::FormatBytes(entry.usage)), - base::Value(static_cast<int>(entry.type))); + // Site Details Page does not display the number of cookies for the origin. + const CookieTreeNode* root = cookies_tree_model_->GetRoot(); + for (int i = 0; i < root->child_count(); ++i) { + const CookieTreeNode* site = root->GetChild(i); + std::string title = base::UTF16ToUTF8(site->GetTitle()); + if (title == usage_host_) { + CallJavascriptFunction( + "settings.WebsiteUsagePrivateApi.returnUsageTotal", + base::Value(usage_host_), + base::Value(ui::FormatBytes(site->InclusiveSize()))); return; } } } -void SiteSettingsHandler::OnStorageCleared(base::OnceClosure callback, - blink::mojom::QuotaStatusCode code) { - if (code == blink::mojom::QuotaStatusCode::kOk) { - std::move(callback).Run(); - } -} - -void SiteSettingsHandler::OnUsageCleared() { - CallJavascriptFunction("settings.WebsiteUsagePrivateApi.onUsageCleared", - base::Value(clearing_origin_)); -} - #if defined(OS_CHROMEOS) void SiteSettingsHandler::OnPrefEnableDrmChanged() { - CallJavascriptFunction("cr.webUIListenerCallback", - base::Value("prefEnableDrmChanged")); + FireWebUIListener("prefEnableDrmChanged"); } #endif @@ -509,15 +496,12 @@ return; if (primary_pattern.ToString().empty()) { - CallJavascriptFunction( - "cr.webUIListenerCallback", - base::Value("contentSettingCategoryChanged"), - base::Value( - site_settings::ContentSettingsTypeToGroupName(content_type))); + FireWebUIListener("contentSettingCategoryChanged", + base::Value(site_settings::ContentSettingsTypeToGroupName( + content_type))); } else { - CallJavascriptFunction( - "cr.webUIListenerCallback", - base::Value("contentSettingSitePermissionChanged"), + FireWebUIListener( + "contentSettingSitePermissionChanged", base::Value( site_settings::ContentSettingsTypeToGroupName(content_type)), base::Value(primary_pattern.ToString()), @@ -591,47 +575,37 @@ void SiteSettingsHandler::HandleFetchUsageTotal( const base::ListValue* args) { AllowJavascript(); - CHECK_EQ(1U, args->GetSize()); std::string host; CHECK(args->GetString(0, &host)); usage_host_ = host; - scoped_refptr<StorageInfoFetcher> storage_info_fetcher - = new StorageInfoFetcher(profile_); - storage_info_fetcher->FetchStorageInfo( - base::Bind(&SiteSettingsHandler::OnGetUsageInfo, base::Unretained(this))); + update_site_details_ = true; + + if (cookies_tree_model_ && !send_sites_list_) { + cookies_tree_model_->RemoveCookiesTreeObserver(this); + cookies_tree_model_.reset(); + } + EnsureCookiesTreeModelCreated(/*omit_cookies=*/true); } void SiteSettingsHandler::HandleClearUsage( const base::ListValue* args) { - CHECK_EQ(2U, args->GetSize()); + CHECK_EQ(1U, args->GetSize()); std::string origin; CHECK(args->GetString(0, &origin)); - double storage_type; - CHECK(args->GetDouble(1, &storage_type)); GURL url(origin); - if (url.is_valid()) { - clearing_origin_ = origin; - - // Call OnUsageCleared when StorageInfoFetcher::ClearStorage and - // BrowsingDataLocalStorageHelper::DeleteOrigin are done. - base::RepeatingClosure barrier = base::BarrierClosure( - 2, base::BindOnce(&SiteSettingsHandler::OnUsageCleared, - base::Unretained(this))); - - // Start by clearing the storage data asynchronously. - scoped_refptr<StorageInfoFetcher> storage_info_fetcher - = new StorageInfoFetcher(profile_); - storage_info_fetcher->ClearStorage( - url.host(), - static_cast<blink::mojom::StorageType>(static_cast<int>(storage_type)), - base::BindRepeating(&SiteSettingsHandler::OnStorageCleared, - base::Unretained(this), barrier)); - - // Also clear the *local* storage data. - GetLocalStorageHelper()->DeleteOrigin(url, barrier); + if (!url.is_valid()) + return; + AllowJavascript(); + CookieTreeNode* parent = cookies_tree_model_->GetRoot(); + for (int i = 0; i < parent->child_count(); ++i) { + CookieTreeNode* node = parent->GetChild(i); + if (origin == node->GetDetailedInfo().origin.GetURL().spec()) { + cookies_tree_model_->DeleteCookieNode(node); + return; + } } } @@ -818,7 +792,7 @@ ConvertSiteGroupMapToListValue(all_sites_map_, origin_permission_set_, &result, profile); - should_send_list_ = true; + send_sites_list_ = true; ResolveJavascriptCallback(*callback_id, result); } @@ -1419,10 +1393,11 @@ profile_->GetPrefs()->SetBoolean(prefs::kBlockAutoplayEnabled, value); } -void SiteSettingsHandler::EnsureCookiesTreeModelCreated() { - if (cookies_tree_model_.get()) +void SiteSettingsHandler::EnsureCookiesTreeModelCreated(bool omit_cookies) { + if (cookies_tree_model_) return; - cookies_tree_model_ = CookiesTreeModel::CreateForProfile(profile_); + cookies_tree_model_ = + CookiesTreeModel::CreateForProfile(profile_, omit_cookies); cookies_tree_model_->AddCookiesTreeObserver(this); } @@ -1458,12 +1433,15 @@ ui::TreeModelNode* node) {} void SiteSettingsHandler::TreeModelEndBatch(CookiesTreeModel* model) { - if (!should_send_list_) - return; - should_send_list_ = false; // The WebUI may have shut down before we get the data. - if (IsJavascriptAllowed()) + if (!IsJavascriptAllowed()) + return; + if (send_sites_list_) OnStorageFetched(); + if (update_site_details_) + OnGetUsageInfo(); + send_sites_list_ = false; + update_site_details_ = false; } void SiteSettingsHandler::GetOriginStorage(
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.h b/chrome/browser/ui/webui/settings/site_settings_handler.h index f763dcd..1336fea3 100644 --- a/chrome/browser/ui/webui/settings/site_settings_handler.h +++ b/chrome/browser/ui/webui/settings/site_settings_handler.h
@@ -52,10 +52,7 @@ void OnJavascriptDisallowed() override; // Usage info. - void OnGetUsageInfo(const storage::UsageInfoEntries& entries); - void OnStorageCleared(base::OnceClosure callback, - blink::mojom::QuotaStatusCode code); - void OnUsageCleared(); + void OnGetUsageInfo(); // CookiesTreeModel::Observer: // TODO(https://crbug.com/835712): Listen for backend data changes and notify @@ -130,7 +127,7 @@ HandleClearEtldPlus1DataAndCookies); // Creates the CookiesTreeModel if necessary. - void EnsureCookiesTreeModelCreated(); + void EnsureCookiesTreeModelCreated(bool omit_cookies = false); // Add this class as an observer for content settings and chooser contexts. void ObserveSources(); @@ -275,7 +272,7 @@ std::unique_ptr<CookiesTreeModel> cookies_tree_model_; // Whether to send all sites list on cookie tree model update. - bool should_send_list_ = false; + bool send_sites_list_ = false; // Populated every time the user reloads the All Sites page. std::map<std::string, std::set<std::string>> all_sites_map_; @@ -283,6 +280,9 @@ // Store the origins that has permission settings. std::set<std::string> origin_permission_set_; + // Whether to send site detail data on cookie tree model update. + bool update_site_details_ = false; + DISALLOW_COPY_AND_ASSIGN(SiteSettingsHandler); };
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc b/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc index 441694da..23b7fff 100644 --- a/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc +++ b/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc
@@ -12,7 +12,6 @@ #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/consent_auditor/consent_auditor_factory.h" #include "chrome/browser/profiles/profile_avatar_icon_util.h" -#include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" @@ -23,12 +22,10 @@ #include "chrome/common/webui_url_constants.h" #include "components/consent_auditor/consent_auditor.h" #include "components/signin/core/browser/account_info.h" -#include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/avatar_icon_util.h" #include "components/unified_consent/feature.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" -#include "services/identity/public/cpp/identity_manager.h" #include "url/gurl.h" const int kProfileImageSize = 128; @@ -50,7 +47,7 @@ SyncConfirmationHandler::~SyncConfirmationHandler() { BrowserList::RemoveObserver(this); - AccountTrackerServiceFactory::GetForProfile(profile_)->RemoveObserver(this); + identity_manager_->RemoveObserver(this); // Abort signin and prevent sync from starting if none of the actions on the // sync confirmation dialog are taken by the user. @@ -105,14 +102,11 @@ void SyncConfirmationHandler::HandleAccountImageRequest( const base::ListValue* args) { - std::string account_id = identity_manager_->GetPrimaryAccountId(); - AccountInfo account_info = - AccountTrackerServiceFactory::GetForProfile(profile_)->GetAccountInfo( - account_id); + AccountInfo account_info = identity_manager_->GetPrimaryAccountInfo(); // Fire the "account-image-changed" listener from |SetUserImageURL()|. // Note: If the account info is not available yet in the - // AccountTrackerService, i.e. account_info is empty, the listener will be + // IdentityManager, i.e. account_info is empty, the listener will be // fired again through |OnAccountUpdated()|. SetUserImageURL(account_info.picture_url); } @@ -196,7 +190,7 @@ if (info.account_id != identity_manager_->GetPrimaryAccountId()) return; - AccountTrackerServiceFactory::GetForProfile(profile_)->RemoveObserver(this); + identity_manager_->RemoveObserver(this); SetUserImageURL(info.picture_url); } @@ -226,19 +220,16 @@ if (!browser_) return; - std::string account_id = identity_manager_->GetPrimaryAccountId(); - if (account_id.empty()) { + if (!identity_manager_->HasPrimaryAccount()) { // No account is signed in, so there is nothing to be displayed in the sync // confirmation dialog. return; } - AccountTrackerService* account_tracker = - AccountTrackerServiceFactory::GetForProfile(profile_); - AccountInfo account_info = account_tracker->GetAccountInfo(account_id); + AccountInfo account_info = identity_manager_->GetPrimaryAccountInfo(); if (!account_info.IsValid()) { SetUserImageURL(kNoPictureURLFound); - account_tracker->AddObserver(this); + identity_manager_->AddObserver(this); } else { SetUserImageURL(account_info.picture_url); }
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_handler.h b/chrome/browser/ui/webui/signin/sync_confirmation_handler.h index 4d1f0b40..d4e6017 100644 --- a/chrome/browser/ui/webui/signin/sync_confirmation_handler.h +++ b/chrome/browser/ui/webui/signin/sync_confirmation_handler.h
@@ -12,8 +12,8 @@ #include "chrome/browser/ui/browser_list_observer.h" #include "chrome/browser/ui/webui/signin/login_ui_service.h" #include "components/consent_auditor/consent_auditor.h" -#include "components/signin/core/browser/account_tracker_service.h" #include "content/public/browser/web_ui_message_handler.h" +#include "services/identity/public/cpp/identity_manager.h" namespace base { class ListValue; @@ -24,7 +24,7 @@ } class SyncConfirmationHandler : public content::WebUIMessageHandler, - public AccountTrackerService::Observer, + public identity::IdentityManager::Observer, public BrowserListObserver { public: // Creates a SyncConfirmationHandler for the |browser|. All strings in the @@ -39,7 +39,7 @@ // content::WebUIMessageHandler: void RegisterMessages() override; - // AccountTrackerService::Observer: + // identity::IdentityManager::Observer: void OnAccountUpdated(const AccountInfo& info) override; // BrowserListObserver:
diff --git a/chrome/browser/ui/webui/version_handler_chromeos.cc b/chrome/browser/ui/webui/version_handler_chromeos.cc index c877fabe..501e27d 100644 --- a/chrome/browser/ui/webui/version_handler_chromeos.cc +++ b/chrome/browser/ui/webui/version_handler_chromeos.cc
@@ -6,7 +6,10 @@ #include "base/bind.h" #include "base/task/post_task.h" +#include "chrome/common/channel_info.h" +#include "components/version_info/channel.h" #include "content/public/browser/web_ui.h" +#include "ui/base/ui_base_features.h" VersionHandlerChromeOS::VersionHandlerChromeOS() : weak_factory_(this) {} @@ -37,7 +40,15 @@ } void VersionHandlerChromeOS::OnVersion(const std::string& version) { - base::Value arg(version); + std::string os_version = version; + // Put a string in about:version so it's easy to copy/paste into bug reports, + // similar to the OS label on the login/lock screen in canary and dev. + // String does not need to be localized since it is a feature name. + if (chrome::GetChannel() <= version_info::Channel::DEV && + ::features::IsSingleProcessMash()) { + os_version += " SingleProcessMash"; + } + base::Value arg(os_version); web_ui()->CallJavascriptFunctionUnsafe("returnOsVersion", arg); }
diff --git a/chrome/browser/vr/elements/text.cc b/chrome/browser/vr/elements/text.cc index 02a18e4..7e4ef66 100644 --- a/chrome/browser/vr/elements/text.cc +++ b/chrome/browser/vr/elements/text.cc
@@ -78,8 +78,9 @@ } const int font_style = font_list.GetFontStyle(); - render_text->SetStyle(gfx::ITALIC, (font_style & gfx::Font::ITALIC) != 0); - render_text->SetStyle(gfx::UNDERLINE, + render_text->SetStyle(gfx::TEXT_STYLE_ITALIC, + (font_style & gfx::Font::ITALIC) != 0); + render_text->SetStyle(gfx::TEXT_STYLE_UNDERLINE, (font_style & gfx::Font::UNDERLINE) != 0); render_text->SetWeight(font_list.GetFontWeight()); }
diff --git a/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc b/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc index 83f0ab56..4a38af1 100644 --- a/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc +++ b/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/installable/fake_installable_manager.h" #include "chrome/browser/installable/installable_data.h" #include "chrome/browser/installable/installable_manager.h" +#include "chrome/common/chrome_render_frame.mojom-test-utils.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" #include "content/public/browser/navigation_entry.h"
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_mac.h b/chrome/browser/web_applications/components/web_app_shortcut_mac.h index 1414b77..83f321318 100644 --- a/chrome/browser/web_applications/components/web_app_shortcut_mac.h +++ b/chrome/browser/web_applications/components/web_app_shortcut_mac.h
@@ -26,20 +26,26 @@ namespace web_app { enum class LaunchShimUpdateBehavior { - NO_UPDATE, - UPDATE_IF_INSTALLED, - RECREATE, + DO_NOT_RECREATE, + RECREATE_IF_INSTALLED, + RECREATE_UNCONDITIONALLY, }; // Callback type for LaunchShim. If |shim_process| is valid then the // app shim was launched. -using LaunchShimCallback = base::OnceCallback<void(base::Process shim_process)>; +using ShimLaunchedCallback = + base::OnceCallback<void(base::Process shim_process)>; + +// Callback on termination takes no arguments. +using ShimTerminatedCallback = base::OnceClosure; // Launch the shim specified by |shortcut_info|. Update the shim prior to launch -// if requested. Return in |callback| the pid that was launched (or an invalid -// pid if none was launched). +// if requested. Return in |launched_callback| the pid that was launched (or an +// invalid pid if none was launched). If |launched_callback| returns a valid +// pid, then |terminated_callback| will be called when that process terminates. void LaunchShim(LaunchShimUpdateBehavior update_behavior, - LaunchShimCallback callback, + ShimLaunchedCallback launched_callback, + ShimTerminatedCallback terminated_callback, std::unique_ptr<web_app::ShortcutInfo> shortcut_info); std::unique_ptr<web_app::ShortcutInfo> RecordAppShimErrorAndBuildShortcutInfo( @@ -86,18 +92,15 @@ // services, sorted by preference. std::vector<base::FilePath> GetAppBundlesById() const; - // The full path to the app bundle under the profile folder. - base::FilePath GetInternalShortcutPath() const; - bool CreateShortcuts(ShortcutCreationReason creation_reason, ShortcutLocations creation_locations); void DeleteShortcuts(); // Recreate the shortcuts where they are found on disk and in the profile - // path. If |recreate_if_needed| is true, then recreate the shortcuts if no + // path. If |create_if_needed| is true, then create the shortcuts if no // matching shortcuts are found on disk. Populate |updated_paths| with the // paths that were updated. - bool UpdateShortcuts(bool recreate_if_needed, + bool UpdateShortcuts(bool create_if_needed, std::vector<base::FilePath>* updated_paths); // Show the bundle we just generated in the Finder.
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_mac.mm b/chrome/browser/web_applications/components/web_app_shortcut_mac.mm index 6751a33..91173e4 100644 --- a/chrome/browser/web_applications/components/web_app_shortcut_mac.mm +++ b/chrome/browser/web_applications/components/web_app_shortcut_mac.mm
@@ -192,7 +192,8 @@ } void LaunchShimOnFileThread(web_app::LaunchShimUpdateBehavior update_behavior, - web_app::LaunchShimCallback callback, + web_app::ShimLaunchedCallback launched_callback, + web_app::ShimTerminatedCallback terminated_callback, const web_app::ShortcutInfo& shortcut_info) { base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); @@ -204,22 +205,21 @@ bool launched_after_rebuild = false; std::vector<base::FilePath> shim_paths; switch (update_behavior) { - case web_app::LaunchShimUpdateBehavior::NO_UPDATE: - // Attempt to locate the shim's path using LaunchServices, and as a last - // resort use the copy in the web app's |app_data_dir_|, in case the user - // deleted all other copies. + case web_app::LaunchShimUpdateBehavior::DO_NOT_RECREATE: + // Attempt to locate the shim's path using LaunchServices. shim_paths = shortcut_creator.GetAppBundlesById(); - shim_paths.push_back(shortcut_creator.GetInternalShortcutPath()); break; - case web_app::LaunchShimUpdateBehavior::UPDATE_IF_INSTALLED: + case web_app::LaunchShimUpdateBehavior::RECREATE_IF_INSTALLED: // Only attempt to launch shims that were updated. launched_after_rebuild = true; - shortcut_creator.UpdateShortcuts(false, &shim_paths); + shortcut_creator.UpdateShortcuts(false /* create_if_needed */, + &shim_paths); break; - case web_app::LaunchShimUpdateBehavior::RECREATE: + case web_app::LaunchShimUpdateBehavior::RECREATE_UNCONDITIONALLY: // Likewise, only attempt to launch shims that were updated. launched_after_rebuild = true; - shortcut_creator.UpdateShortcuts(true, &shim_paths); + shortcut_creator.UpdateShortcuts(true /* create_if_needed */, + &shim_paths); break; } @@ -241,14 +241,14 @@ if (process.IsValid()) { base::PostTaskWithTraits( FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(std::move(callback), std::move(process))); + base::BindOnce(std::move(launched_callback), std::move(process))); return; } } base::PostTaskWithTraits( FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(std::move(callback), base::Process())); + base::BindOnce(std::move(launched_callback), base::Process())); } base::FilePath GetAppLoaderPath() { @@ -522,6 +522,9 @@ if (applications_dir.empty()) return base::FilePath(); + if (g_app_shims_allow_update_and_launch_in_tests) + return app_data_dir_.Append(GetShortcutBasename()); + if (!avoid_conflicts) return applications_dir.Append(GetShortcutBasename()); @@ -540,10 +543,6 @@ return applications_dir.Append(GetFallbackBasename()); } -base::FilePath WebAppShortcutCreator::GetInternalShortcutPath() const { - return app_data_dir_.Append(GetShortcutBasename()); -} - base::FilePath WebAppShortcutCreator::GetShortcutBasename( int copy_number) const { // For profile-less shortcuts, use the fallback naming scheme to avoid change. @@ -652,6 +651,8 @@ bool WebAppShortcutCreator::CreateShortcuts( ShortcutCreationReason creation_reason, ShortcutLocations creation_locations) { + DCHECK_NE(creation_locations.applications_menu_location, + APP_MENU_LOCATION_HIDDEN); const base::FilePath applications_dir = GetApplicationsDirname(); if (applications_dir.empty() || !base::DirectoryExists(applications_dir.DirName())) { @@ -665,56 +666,13 @@ if (!once) LOG(ERROR) << "Failed to localize " << applications_dir.value(); - // If non-nil, this path is added to the OSX Dock after creating shortcuts. - NSString* path_to_add_to_dock = nil; - std::vector<base::FilePath> app_paths; - - bool shortcut_visible = - creation_locations.applications_menu_location != APP_MENU_LOCATION_HIDDEN; - if (shortcut_visible) { - app_paths.push_back( - GetApplicationsShortcutPath(true /* avoid_conflicts */)); - } - - // The app list shim is not tied to a particular profile, so omit the copy - // placed under the profile path. For shims, this copy is used when the - // version under Applications is removed, and not needed for app list because - // setting LSUIElement means there is no Dock "running" status to show. - const bool is_app_list = info_->extension_id == app_mode::kAppListModeId; - if (is_app_list) { - path_to_add_to_dock = base::SysUTF8ToNSString( - applications_dir.Append(GetShortcutBasename()).AsUTF8Unsafe()); - } else { - app_paths.push_back(GetInternalShortcutPath()); - } - - DCHECK(!app_paths.empty()); + app_paths.push_back(GetApplicationsShortcutPath(true /* avoid_conflicts */)); std::vector<base::FilePath> updated_app_paths; size_t success_count = CreateShortcutsAt(app_paths, &updated_app_paths); - if (success_count == 0) - return false; - - if (!is_app_list) - UpdateInternalBundleIdentifier(); - if (success_count != app_paths.size()) return false; - if (creation_locations.in_quick_launch_bar && path_to_add_to_dock && - shortcut_visible) { - switch (dock::AddIcon(path_to_add_to_dock, nil)) { - case dock::IconAddFailure: - // If adding the icon failed, instead reveal the Finder window. - RevealAppShimInFinder(); - break; - case dock::IconAddSuccess: - case dock::IconAlreadyPresent: - break; - } - return true; - } - if (creation_reason == SHORTCUT_CREATION_BY_USER) RevealAppShimInFinder(); @@ -737,16 +695,10 @@ // directory still has its .DS_Store and .localized files. if (deleted_instance_in_apps_dir && base::IsDirectoryEmpty(apps_dir)) base::DeleteFile(apps_dir, false); - - // Delete the internal one (and its parent directory if it is empty -- this - // actually does happen often, because the path is rarely viewed in Finder). - base::DeleteFile(GetInternalShortcutPath(), true); - if (base::IsDirectoryEmpty(app_data_dir_)) - base::DeleteFile(app_data_dir_, false); } bool WebAppShortcutCreator::UpdateShortcuts( - bool recreate_if_needed, + bool create_if_needed, std::vector<base::FilePath>* updated_paths) { DCHECK(updated_paths && updated_paths->empty()); @@ -762,27 +714,14 @@ // by the user). app_paths = GetAppBundlesById(); - // If that path does not exist, consider creating a new entry in - // ~/Applications. - if (app_paths.empty()) { - // Check to see if there exists a copy in the profile directory. If one - // doesn't, but other shortcuts do exist, it should be re-created. - // Otherwise, take its absence as a signal that a shortcut has never been - // created. - bool profile_copy_exists = base::PathExists(GetInternalShortcutPath()); - if (recreate_if_needed || (profile_copy_exists && info_->from_bookmark)) { - // The bookmark app shortcut has been deleted by the user. Restore it, - // as the Mac UI for bookmark apps creates the expectation that the app - // will be added to Applications. - app_paths.push_back( - GetApplicationsShortcutPath(true /* avoid_conflicts */)); - } + // If that path does not exist, create a new entry in ~/Applications if + // requested. + if (app_paths.empty() && create_if_needed) { + app_paths.push_back( + GetApplicationsShortcutPath(true /* avoid_conflicts */)); } - // Update or create the copy under the profile directory only if there are - // other paths being updated. if (app_paths.empty()) return false; - app_paths.push_back(GetInternalShortcutPath()); } else { // If a test has set g_app_shims_allow_update_and_launch_in_tests, it means // it relies on UpdateShortcuts() to create shortcuts. (Tests can't rely on @@ -790,12 +729,10 @@ // the UI thread). So, allow shortcuts to be created for this case, even if // none currently exist. TODO(tapted): Remove this when tests are properly // mocked. - app_paths.push_back(GetInternalShortcutPath()); + app_paths.push_back(app_data_dir_.Append(GetShortcutBasename())); } size_t success_count = CreateShortcutsAt(app_paths, updated_paths); - if (success_count) - UpdateInternalBundleIdentifier(); return success_count == app_paths.size(); } @@ -920,32 +857,14 @@ return WriteIconsToFile(valid_icons, resources_path.Append("app.icns")); } -bool WebAppShortcutCreator::UpdateInternalBundleIdentifier() const { - NSString* plist_path = GetPlistPath(GetInternalShortcutPath()); - NSMutableDictionary* plist = ReadPlist(plist_path); - - [plist setObject:base::SysUTF8ToNSString(GetInternalBundleIdentifier()) - forKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)]; - return [plist writeToFile:plist_path atomically:YES]; -} - std::vector<base::FilePath> WebAppShortcutCreator::GetAppBundlesByIdUnsorted() const { base::ScopedCFTypeRef<CFStringRef> bundle_id_cf( base::SysUTF8ToCFStringRef(GetBundleIdentifier())); // Retrieve the URLs found by LaunchServices. - base::scoped_nsobject<NSArray> urls; - if (@available(macOS 10.10, *)) { - urls.reset(base::mac::CFToNSCast( - LSCopyApplicationURLsForBundleIdentifier(bundle_id_cf.get(), nullptr))); - } else { - base::ScopedCFTypeRef<CFURLRef> cf_url; - LSFindApplicationForInfo(kLSUnknownCreator, bundle_id_cf.get(), NULL, NULL, - cf_url.InitializeInto()); - if (cf_url) - urls.reset([@[ base::mac::CFToNSCast(cf_url) ] retain]); - } + base::scoped_nsobject<NSArray> urls(base::mac::CFToNSCast( + LSCopyApplicationURLsForBundleIdentifier(bundle_id_cf.get(), nullptr))); // Store only those results corresponding to this user data dir. std::vector<base::FilePath> paths; @@ -1033,18 +952,20 @@ } void LaunchShim(LaunchShimUpdateBehavior update_behavior, - LaunchShimCallback callback, + ShimLaunchedCallback launched_callback, + ShimTerminatedCallback terminated_callback, std::unique_ptr<web_app::ShortcutInfo> shortcut_info) { if (web_app::AppShimLaunchDisabled()) { base::PostTaskWithTraits( FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(std::move(callback), base::Process())); + base::BindOnce(std::move(launched_callback), base::Process())); return; } web_app::internals::PostShortcutIOTask( base::BindOnce(&LaunchShimOnFileThread, update_behavior, - std::move(callback)), + std::move(launched_callback), + std::move(terminated_callback)), std::move(shortcut_info)); } @@ -1079,7 +1000,8 @@ web_app::WebAppShortcutCreator shortcut_creator(app_data_path, &shortcut_info); std::vector<base::FilePath> updated_shim_paths; - shortcut_creator.UpdateShortcuts(false, &updated_shim_paths); + shortcut_creator.UpdateShortcuts(false /* create_if_needed */, + &updated_shim_paths); } void DeleteAllShortcutsForProfile(const base::FilePath& profile_path) {
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm b/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm index 5e839e6..4e368eb 100644 --- a/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm +++ b/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm
@@ -253,10 +253,7 @@ EXPECT_FALSE(base::PathExists(shim_path_)); EXPECT_TRUE(base::PathExists(other_shim_path.Append("Contents"))); - // The list of updated paths is the paths found by bundle, plus the internal - // path. - EXPECT_EQ(bundle_by_id_paths.size() + 1, updated_paths.size()); - updated_paths.pop_back(); + // The list of updated paths is the paths found by bundle. EXPECT_EQ(bundle_by_id_paths, updated_paths); // Also test case where GetAppBundlesByIdUnsorted fails. @@ -283,7 +280,7 @@ // The default shim path is created along with the internal path. updated_paths.clear(); EXPECT_TRUE(shortcut_creator.UpdateShortcuts(true, &updated_paths)); - EXPECT_EQ(2u, updated_paths.size()); + EXPECT_EQ(1u, updated_paths.size()); EXPECT_EQ(shim_path_, updated_paths[0]); EXPECT_TRUE(base::PathExists(shim_path_)); EXPECT_FALSE(base::PathExists(other_shim_path.Append("Contents"))); @@ -345,7 +342,6 @@ EXPECT_TRUE(shortcut_creator.CreateShortcuts(SHORTCUT_CREATION_AUTOMATED, web_app::ShortcutLocations())); - EXPECT_TRUE(base::PathExists(internal_shim_path_)); EXPECT_TRUE(base::PathExists(shim_path_)); // Create an extra shim in another folder. It should be deleted since its @@ -366,7 +362,6 @@ EXPECT_TRUE( base::PathService::Override(chrome::DIR_USER_DATA, app_data_dir_)); shortcut_creator.DeleteShortcuts(); - EXPECT_FALSE(base::PathExists(internal_shim_path_)); EXPECT_TRUE(base::PathExists(shim_path_)); EXPECT_FALSE(base::PathExists(other_shim_path)); }
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm b/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm index f555819..8aef06b 100644 --- a/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm +++ b/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm
@@ -90,11 +90,13 @@ shortcut_info->extension_id, extensions::ExtensionRegistry::ENABLED); if (!extension || !extension->is_platform_app()) return; - base::OnceCallback<void(base::Process)> launch_callback = base::DoNothing(); + base::OnceCallback<void(base::Process)> launched_callback = base::DoNothing(); + base::OnceClosure terminated_callback = base::DoNothing(); web_app::GetShortcutInfoForApp( extension, profile, - base::BindOnce(&LaunchShim, LaunchShimUpdateBehavior::UPDATE_IF_INSTALLED, - std::move(launch_callback))); + base::BindOnce( + &LaunchShim, LaunchShimUpdateBehavior::RECREATE_IF_INSTALLED, + std::move(launched_callback), std::move(terminated_callback))); } bool MaybeRebuildShortcut(const base::CommandLine& command_line) {
diff --git a/chrome/build/chrome.x64.orderfile.sha1 b/chrome/build/chrome.x64.orderfile.sha1 index a88abad..aeb1889 100644 --- a/chrome/build/chrome.x64.orderfile.sha1 +++ b/chrome/build/chrome.x64.orderfile.sha1
@@ -1 +1 @@ -5acb808c8a55ce204641ae4aa32bb85d4e128370 \ No newline at end of file +adb9236e1790fac59da12940ad1e690d81a739d7 \ No newline at end of file
diff --git a/chrome/build/chrome.x86.orderfile.sha1 b/chrome/build/chrome.x86.orderfile.sha1 index c631311..e1283cd 100644 --- a/chrome/build/chrome.x86.orderfile.sha1 +++ b/chrome/build/chrome.x86.orderfile.sha1
@@ -1 +1 @@ -706611f57960570147dc4a86ad3a386146d3783c \ No newline at end of file +0bcbabbd2097ce719af3c840c2aad712b8e416ec \ No newline at end of file
diff --git a/chrome/build/chrome_child.x64.orderfile.sha1 b/chrome/build/chrome_child.x64.orderfile.sha1 index 76ef9df3..58fc005 100644 --- a/chrome/build/chrome_child.x64.orderfile.sha1 +++ b/chrome/build/chrome_child.x64.orderfile.sha1
@@ -1 +1 @@ -812a701e2c9b558038c7452a88aac048227159d2 \ No newline at end of file +d729c88ce5bd4104a6149d1fad2a88b337303bb1 \ No newline at end of file
diff --git a/chrome/build/chrome_child.x86.orderfile.sha1 b/chrome/build/chrome_child.x86.orderfile.sha1 index bf8157f..83784d6 100644 --- a/chrome/build/chrome_child.x86.orderfile.sha1 +++ b/chrome/build/chrome_child.x86.orderfile.sha1
@@ -1 +1 @@ -49956c0413aa694c4270c946372ec69454365b0e \ No newline at end of file +47d95ad50f3ca8387263a5d6f02117eb31cca3a0 \ No newline at end of file
diff --git a/chrome/common/extensions/api/autofill_private.idl b/chrome/common/extensions/api/autofill_private.idl index b41477f7..6aca340 100644 --- a/chrome/common/extensions/api/autofill_private.idl +++ b/chrome/common/extensions/api/autofill_private.idl
@@ -228,6 +228,14 @@ // |callback|: Callback which will be called with the list of credit cards. static void getCreditCardList(GetCreditCardListCallback callback); + // Gets the list of local credit cards. + // |callback|: Callback which will be called with the list of credit cards. + static void getLocalCreditCardList(GetCreditCardListCallback callback); + + // Gets the list of server credit cards. + // |callback|: Callback which will be called with the list of credit cards. + static void getServerCreditCardList(GetCreditCardListCallback callback); + // Clears the data associated with a wallet card which was saved // locally so that the saved copy is masked (e.g., "Card ending // in 1234"). @@ -251,5 +259,15 @@ // been added, removed, or changed. // |entries| The updated list of entries. static void onCreditCardListChanged(CreditCardEntry[] entries); + + // Fired when the local credit card list has changed, meaning that an entry + // has been added, removed, or changed. + // |entries| The updated list of entries. + static void onLocalCreditCardListChanged(CreditCardEntry[] entries); + + // Fired when the server credit card list has changed, meaning that an entry + // has been added, removed, or changed. + // |entries| The updated list of entries. + static void onServerCreditCardListChanged(CreditCardEntry[] entries); }; };
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl index 180bca8..38e2d40 100644 --- a/chrome/common/extensions/api/file_manager_private.idl +++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -448,6 +448,10 @@ // Icons for the volume. IconSet iconSet; + + // Drive label of the volume. Removable partitions that belong to the + // same physical removable device share the same drive label. + DOMString? driveLabel; }; // Payload data for mount event.
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_contentsecuritypolicy_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_contentsecuritypolicy_unittest.cc index 4915458bf..680a8ca 100644 --- a/chrome/common/extensions/manifest_tests/extension_manifests_contentsecuritypolicy_unittest.cc +++ b/chrome/common/extensions/manifest_tests/extension_manifests_contentsecuritypolicy_unittest.cc
@@ -17,15 +17,16 @@ TEST_F(ContentSecurityPolicyManifestTest, InsecureContentSecurityPolicy) { Testcase testcases[] = { + Testcase("insecure_contentsecuritypolicy_1.json", + ErrorUtils::FormatErrorMessage( + errors::kInvalidCSPInsecureValueIgnored, + keys::kContentSecurityPolicy, "http://example.com", + "script-src")), Testcase( - "insecure_contentsecuritypolicy_1.json", - ErrorUtils::FormatErrorMessage(errors::kInvalidCSPInsecureValue, - keys::kContentSecurityPolicy, - "http://example.com", "script-src")), - Testcase("insecure_contentsecuritypolicy_2.json", - ErrorUtils::FormatErrorMessage(errors::kInvalidCSPInsecureValue, - keys::kContentSecurityPolicy, - "'unsafe-inline'", "script-src")), + "insecure_contentsecuritypolicy_2.json", + ErrorUtils::FormatErrorMessage( + errors::kInvalidCSPInsecureValueIgnored, + keys::kContentSecurityPolicy, "'unsafe-inline'", "script-src")), Testcase("insecure_contentsecuritypolicy_3.json", ErrorUtils::FormatErrorMessage( errors::kInvalidCSPMissingSecureSrc,
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc index 57e0f5f..15d29da 100644 --- a/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc +++ b/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
@@ -100,7 +100,7 @@ // But even allowlisted ones must specify a secure policy. LoadAndExpectWarning( "init_platform_app_csp_insecure.json", - ErrorUtils::FormatErrorMessage(errors::kInvalidCSPInsecureValue, + ErrorUtils::FormatErrorMessage(errors::kInvalidCSPInsecureValueIgnored, keys::kPlatformAppContentSecurityPolicy, "http://www.google.com", "default-src")); }
diff --git a/chrome/common/importer/firefox_importer_utils_mac.mm b/chrome/common/importer/firefox_importer_utils_mac.mm index ac9cf4122..1152a56 100644 --- a/chrome/common/importer/firefox_importer_utils_mac.mm +++ b/chrome/common/importer/firefox_importer_utils_mac.mm
@@ -25,17 +25,17 @@ } base::FilePath GetFirefoxDylibPath() { - CFURLRef appURL = nil; - if (LSFindApplicationForInfo(kLSUnknownCreator, - CFSTR("org.mozilla.firefox"), - NULL, - NULL, - &appURL) != noErr) { + base::ScopedCFTypeRef<CFErrorRef> out_err; + base::ScopedCFTypeRef<CFArrayRef> app_urls( + LSCopyApplicationURLsForBundleIdentifier(CFSTR("org.mozilla.firefox"), + out_err.InitializeInto())); + if (out_err || CFArrayGetCount(app_urls) == 0) { return base::FilePath(); } - NSBundle *ff_bundle = - [NSBundle bundleWithPath:[base::mac::CFToNSCast(appURL) path]]; - CFRelease(appURL); + CFURLRef app_url = + base::mac::CFCastStrict<CFURLRef>(CFArrayGetValueAtIndex(app_urls, 0)); + NSBundle* ff_bundle = + [NSBundle bundleWithPath:[base::mac::CFToNSCast(app_url) path]]; NSString *ff_library_path = [[ff_bundle executablePath] stringByDeletingLastPathComponent]; char buf[MAXPATHLEN];
diff --git a/chrome/common/mac/service_management.mm b/chrome/common/mac/service_management.mm index 52dbdd6..5861c7c 100644 --- a/chrome/common/mac/service_management.mm +++ b/chrome/common/mac/service_management.mm
@@ -17,6 +17,11 @@ #include "base/macros.h" #include "base/strings/sys_string_conversions.h" +// This entire file is written in terms of the launch_data_t API, which is +// deprecated with no replacement, so just ignore the warnings for now. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + namespace { class ScopedLaunchData { @@ -260,3 +265,5 @@ } // namespace services } // namespace mac + +#pragma clang diagnostic pop
diff --git a/chrome/renderer/autofill/fake_password_generation_driver.cc b/chrome/renderer/autofill/fake_password_generation_driver.cc new file mode 100644 index 0000000..e631be1 --- /dev/null +++ b/chrome/renderer/autofill/fake_password_generation_driver.cc
@@ -0,0 +1,40 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/autofill/fake_password_generation_driver.h" + +#include <utility> + +FakePasswordGenerationDriver::FakePasswordGenerationDriver() : binding_(this) {} + +FakePasswordGenerationDriver::~FakePasswordGenerationDriver() = default; + +void FakePasswordGenerationDriver::BindRequest( + autofill::mojom::PasswordGenerationDriverAssociatedRequest request) { + binding_.Bind(std::move(request)); +} + +void FakePasswordGenerationDriver::Flush() { + if (binding_.is_bound()) + binding_.FlushForTesting(); +} + +// autofill::mojom::PasswordManagerClient: +void FakePasswordGenerationDriver::AutomaticGenerationStatusChanged( + bool available, + const base::Optional< + autofill::password_generation::PasswordGenerationUIData>& ui_data) { + if (available) { + called_automatic_generation_status_changed_true_ = true; + } +} + +void FakePasswordGenerationDriver::GenerationAvailableForForm( + const autofill::PasswordForm& form) { + called_generation_available_for_form_ = true; +} + +void FakePasswordGenerationDriver::PasswordGenerationRejectedByTyping() { + called_password_generation_rejected_by_typing_ = true; +}
diff --git a/chrome/renderer/autofill/fake_password_manager_client.h b/chrome/renderer/autofill/fake_password_generation_driver.h similarity index 70% rename from chrome/renderer/autofill/fake_password_manager_client.h rename to chrome/renderer/autofill/fake_password_generation_driver.h index abb8244b..5fe3b66 100644 --- a/chrome/renderer/autofill/fake_password_manager_client.h +++ b/chrome/renderer/autofill/fake_password_generation_driver.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_RENDERER_AUTOFILL_FAKE_PASSWORD_MANAGER_CLIENT_H_ -#define CHROME_RENDERER_AUTOFILL_FAKE_PASSWORD_MANAGER_CLIENT_H_ +#ifndef CHROME_RENDERER_AUTOFILL_FAKE_PASSWORD_GENERATION_DRIVER_H_ +#define CHROME_RENDERER_AUTOFILL_FAKE_PASSWORD_GENERATION_DRIVER_H_ #include <string> #include <vector> @@ -16,15 +16,15 @@ #include "mojo/public/cpp/bindings/associated_binding.h" #include "testing/gmock/include/gmock/gmock.h" -class FakePasswordManagerClient - : public autofill::mojom::PasswordManagerClient { +class FakePasswordGenerationDriver + : public autofill::mojom::PasswordGenerationDriver { public: - FakePasswordManagerClient(); + FakePasswordGenerationDriver(); - ~FakePasswordManagerClient() override; + ~FakePasswordGenerationDriver() override; void BindRequest( - autofill::mojom::PasswordManagerClientAssociatedRequest request); + autofill::mojom::PasswordGenerationDriverAssociatedRequest request); void Flush(); @@ -32,10 +32,6 @@ return called_automatic_generation_status_changed_true_; } - bool called_show_manual_pw_generation_popup() const { - return called_show_manual_pw_generation_popup_; - } - bool called_generation_available_for_form() const { return called_generation_available_for_form_; } @@ -48,10 +44,6 @@ called_automatic_generation_status_changed_true_ = false; } - void reset_called_show_manual_pw_generation_popup() { - called_show_manual_pw_generation_popup_ = false; - } - void reset_called_generation_available_for_form() { called_generation_available_for_form_ = false; } @@ -61,7 +53,7 @@ } // TODO(crbug.com/851021): move all the methods to GMock. - // autofill::mojom::PasswordManagerClient: + // autofill::mojom::PasswordGenerationDriver: MOCK_METHOD1(PresaveGeneratedPassword, void(const autofill::PasswordForm& password_form)); MOCK_METHOD1(PasswordNoLongerGenerated, @@ -78,10 +70,6 @@ autofill::password_generation::PasswordGenerationUIData>& ui_data) override; - void ShowManualPasswordGenerationPopup( - const autofill::password_generation::PasswordGenerationUIData& ui_data) - override; - void GenerationAvailableForForm(const autofill::PasswordForm& form) override; void PasswordGenerationRejectedByTyping() override; @@ -89,18 +77,15 @@ // Records whether AutomaticGenerationStatusChanged(true) gets called. bool called_automatic_generation_status_changed_true_ = false; - // Records whether ShowPasswordGenerationPopup() gets called. - bool called_show_manual_pw_generation_popup_ = false; - // Records whether GenerationAvailableForForm() gets called. bool called_generation_available_for_form_ = false; // Records whether PasswordGenerationRejecteByTyping() gets called. bool called_password_generation_rejected_by_typing_ = false; - mojo::AssociatedBinding<autofill::mojom::PasswordManagerClient> binding_; + mojo::AssociatedBinding<autofill::mojom::PasswordGenerationDriver> binding_; - DISALLOW_COPY_AND_ASSIGN(FakePasswordManagerClient); + DISALLOW_COPY_AND_ASSIGN(FakePasswordGenerationDriver); }; -#endif // CHROME_RENDERER_AUTOFILL_FAKE_PASSWORD_MANAGER_CLIENT_H_ +#endif // CHROME_RENDERER_AUTOFILL_FAKE_PASSWORD_GENERATION_DRIVER_H_
diff --git a/chrome/renderer/autofill/fake_password_manager_client.cc b/chrome/renderer/autofill/fake_password_manager_client.cc deleted file mode 100644 index b50727e..0000000 --- a/chrome/renderer/autofill/fake_password_manager_client.cc +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/renderer/autofill/fake_password_manager_client.h" - -FakePasswordManagerClient::FakePasswordManagerClient() : binding_(this) {} - -FakePasswordManagerClient::~FakePasswordManagerClient() = default; - -void FakePasswordManagerClient::BindRequest( - autofill::mojom::PasswordManagerClientAssociatedRequest request) { - binding_.Bind(std::move(request)); -} - -void FakePasswordManagerClient::Flush() { - if (binding_.is_bound()) - binding_.FlushForTesting(); -} - -// autofill::mojom::PasswordManagerClient: -void FakePasswordManagerClient::AutomaticGenerationStatusChanged( - bool available, - const base::Optional< - autofill::password_generation::PasswordGenerationUIData>& ui_data) { - if (available) { - called_automatic_generation_status_changed_true_ = true; - } -} - -void FakePasswordManagerClient::ShowManualPasswordGenerationPopup( - const autofill::password_generation::PasswordGenerationUIData& ui_data) { - called_show_manual_pw_generation_popup_ = true; -} - -void FakePasswordManagerClient::GenerationAvailableForForm( - const autofill::PasswordForm& form) { - called_generation_available_for_form_ = true; -} - -void FakePasswordManagerClient::PasswordGenerationRejectedByTyping() { - called_password_generation_rejected_by_typing_ = true; -}
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc index 7930000..8bd79c6 100644 --- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc +++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -14,7 +14,7 @@ #include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "chrome/renderer/autofill/fake_mojo_password_manager_driver.h" -#include "chrome/renderer/autofill/fake_password_manager_client.h" +#include "chrome/renderer/autofill/fake_password_generation_driver.h" #include "chrome/renderer/autofill/password_generation_test_utils.h" #include "chrome/test/base/chrome_render_view_test.h" #include "components/autofill/content/renderer/autofill_agent.h" @@ -121,7 +121,8 @@ "</body>"; const char kSignupFormHTML[] = - "<FORM name='LoginTestForm' action='http://www.bidule.com'>" + "<FORM id='LoginTestForm' name='LoginTestForm' " + " action='http://www.bidule.com'>" " <INPUT type='text' id='random_info'/>" " <INPUT type='password' id='new_password'/>" " <INPUT type='password' id='confirm_password'/>" @@ -296,7 +297,7 @@ view_->GetMainRenderFrame() ->GetRemoteAssociatedInterfaces() ->OverrideBinderForTesting( - mojom::PasswordManagerClient::Name_, + mojom::PasswordGenerationDriver::Name_, base::BindRepeating([](mojo::ScopedInterfaceEndpointHandle handle) { handle.reset(); })); @@ -362,7 +363,7 @@ blink::AssociatedInterfaceProvider* remote_associated_interfaces = view_->GetMainRenderFrame()->GetRemoteAssociatedInterfaces(); remote_associated_interfaces->OverrideBinderForTesting( - mojom::PasswordManagerClient::Name_, + mojom::PasswordGenerationDriver::Name_, base::BindRepeating( &PasswordAutofillAgentTest::BindPasswordManagerClient, base::Unretained(this))); @@ -683,7 +684,7 @@ void BindPasswordManagerClient(mojo::ScopedInterfaceEndpointHandle handle) { fake_pw_client_.BindRequest( - mojom::PasswordManagerClientAssociatedRequest(std::move(handle))); + mojom::PasswordGenerationDriverAssociatedRequest(std::move(handle))); } void SaveAndSubmitForm() { SaveAndSubmitForm(username_element_.Form()); } @@ -719,7 +720,7 @@ } FakeMojoPasswordManagerDriver fake_driver_; - FakePasswordManagerClient fake_pw_client_; + FakePasswordGenerationDriver fake_pw_client_; base::string16 username1_; base::string16 username2_; @@ -833,15 +834,7 @@ // Fill username and password fields when username field contains a prefilled // value that matches the list of known possible prefilled values usually used // as placeholders. -// TODO(crbug.com/855383): Leaks under ASAN. -#if defined(ADDRESS_SANITIZER) -#define MAYBE_AutocompleteForPrefilledUsernameValue \ - DISABLED_AutocompleteForPrefilledUsernameValue -#else -#define MAYBE_AutocompleteForPrefilledUsernameValue \ - AutocompleteForPrefilledUsernameValue -#endif -TEST_F(PasswordAutofillAgentTest, MAYBE_AutocompleteForPrefilledUsernameValue) { +TEST_F(PasswordAutofillAgentTest, AutocompleteForPrefilledUsernameValue) { // Set the username element to a value from the prefilled values list. // Comparison should be insensitive to leading and trailing whitespaces. username_element_.SetValue( @@ -925,6 +918,10 @@ fill_data_.password_field.unique_renderer_id = FormFieldData::kNotSetFormControlRendererId; + WebFormElement form_element = + document.GetElementById("LoginTestForm").To<WebFormElement>(); + fill_data_.form_renderer_id = form_element.UniqueRendererFormId(); + SimulateOnFillPasswordForm(fill_data_); histogram_tester_.ExpectTotalCount( "PasswordManager.FirstRendererFillingResult", 0); @@ -1298,13 +1295,7 @@ // Tests that a password will only be filled as a suggested and will not be // accessible by the DOM until a user gesture has occurred. -// TODO(crbug.com/855383): Leaks under ASAN. -#if defined(ADDRESS_SANITIZER) -#define MAYBE_GestureRequiredTest DISABLED_GestureRequiredTest -#else -#define MAYBE_GestureRequiredTest GestureRequiredTest -#endif -TEST_F(PasswordAutofillAgentTest, MAYBE_GestureRequiredTest) { +TEST_F(PasswordAutofillAgentTest, GestureRequiredTest) { // Trigger the initial autocomplete. SimulateOnFillPasswordForm(fill_data_); @@ -1332,16 +1323,8 @@ // Verifies that password autofill triggers events in JavaScript for forms that // are filled on page load. -// TODO(crbug.com/855383): Leaks under ASAN. -#if defined(ADDRESS_SANITIZER) -#define MAYBE_PasswordAutofillTriggersOnChangeEventsOnLoad \ - DISABLED_PasswordAutofillTriggersOnChangeEventsOnLoad -#else -#define MAYBE_PasswordAutofillTriggersOnChangeEventsOnLoad \ - PasswordAutofillTriggersOnChangeEventsOnLoad -#endif TEST_F(PasswordAutofillAgentTest, - MAYBE_PasswordAutofillTriggersOnChangeEventsOnLoad) { + PasswordAutofillTriggersOnChangeEventsOnLoad) { std::vector<base::string16> username_event_checkers; std::vector<base::string16> password_event_checkers; std::string events_registration_script = @@ -1753,14 +1736,7 @@ } // Tests that |FillIntoFocusedField| properly fills user-provided credentials. -// TODO(crbug.com/855383): Leaks under ASAN. -#if defined(ADDRESS_SANITIZER) -#define MAYBE_FillIntoFocusedWritableTextField \ - DISABLED_FillIntoFocusedWritableTextField -#else -#define MAYBE_FillIntoFocusedWritableTextField FillIntoFocusedWritableTextField -#endif -TEST_F(PasswordAutofillAgentTest, MAYBE_FillIntoFocusedWritableTextField) { +TEST_F(PasswordAutofillAgentTest, FillIntoFocusedWritableTextField) { // Neither field should be autocompleted. CheckTextFieldsDOMState(std::string(), false, std::string(), false); @@ -3302,9 +3278,8 @@ // Tests that password manager sees both autofill assisted and user entered // data on saving that is triggered by form submission. -// TODO(crbug.com/855383): Leaks under ASAN. // Disabled on Win due to https://crbug.com/835865. -#if defined(ADDRESS_SANITIZER) || defined(OS_WIN) +#if defined(OS_WIN) #define MAYBE_UsernameChangedAfterPasswordInput_FormSubmitted \ DISABLED_UsernameChangedAfterPasswordInput_FormSubmitted #else @@ -3330,14 +3305,7 @@ // Tests that a suggestion dropdown is shown on a password field even if a // username field is present. -// TODO(crbug.com/855383): Leaks under ASAN. -#if defined(ADDRESS_SANITIZER) -#define MAYBE_SuggestPasswordFieldSignInForm \ - DISABLED_SuggestPasswordFieldSignInForm -#else -#define MAYBE_SuggestPasswordFieldSignInForm SuggestPasswordFieldSignInForm -#endif -TEST_F(PasswordAutofillAgentTest, MAYBE_SuggestPasswordFieldSignInForm) { +TEST_F(PasswordAutofillAgentTest, SuggestPasswordFieldSignInForm) { // Simulate the browser sending back the login info. SimulateOnFillPasswordForm(fill_data_);
diff --git a/chrome/renderer/autofill/password_generation_agent_browsertest.cc b/chrome/renderer/autofill/password_generation_agent_browsertest.cc index d642bc1..2b87880 100644 --- a/chrome/renderer/autofill/password_generation_agent_browsertest.cc +++ b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
@@ -12,7 +12,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "chrome/renderer/autofill/fake_mojo_password_manager_driver.h" -#include "chrome/renderer/autofill/fake_password_manager_client.h" +#include "chrome/renderer/autofill/fake_password_generation_driver.h" #include "chrome/renderer/autofill/password_generation_test_utils.h" #include "chrome/test/base/chrome_render_view_test.h" #include "components/autofill/content/renderer/autofill_agent.h" @@ -45,7 +45,7 @@ class PasswordGenerationAgentTest : public ChromeRenderViewTest { public: - PasswordGenerationAgentTest() {} + PasswordGenerationAgentTest() = default; void RegisterMainFrameRemoteInterfaces() override { // Because the test cases only involve the main frame in this test, @@ -53,7 +53,7 @@ blink::AssociatedInterfaceProvider* remote_associated_interfaces = view_->GetMainRenderFrame()->GetRemoteAssociatedInterfaces(); remote_associated_interfaces->OverrideBinderForTesting( - mojom::PasswordManagerClient::Name_, + mojom::PasswordGenerationDriver::Name_, base::BindRepeating( &PasswordGenerationAgentTest::BindPasswordManagerClient, base::Unretained(this))); @@ -76,7 +76,7 @@ view_->GetMainRenderFrame() ->GetRemoteAssociatedInterfaces() ->OverrideBinderForTesting( - mojom::PasswordManagerClient::Name_, + mojom::PasswordGenerationDriver::Name_, base::BindRepeating([](mojo::ScopedInterfaceEndpointHandle handle) { handle.reset(); })); @@ -124,13 +124,6 @@ fake_pw_client_.reset_called_automatic_generation_status_changed_true(); } - void ExpectManualGenerationAvailable(const char* element_id, bool available) { - FocusField(element_id); - base::RunLoop().RunUntilIdle(); - ASSERT_EQ(available, GetCalledShowManualPasswordGenerationPopup()); - fake_pw_client_.reset_called_show_manual_pw_generation_popup(); - } - void ExpectFormClassifierVoteReceived( bool received, const base::string16& expected_generation_element) { @@ -151,14 +144,18 @@ return fake_pw_client_.called_automatic_generation_status_changed_true(); } - bool GetCalledShowManualPasswordGenerationPopup() { - fake_pw_client_.Flush(); - return fake_pw_client_.called_show_manual_pw_generation_popup(); - } - - void SelectGenerationFallbackInContextMenu(const char* element_id) { - SimulateElementRightClick(element_id); - password_generation_->UserTriggeredGeneratePassword(); + void SelectGenerationFallbackAndExpect(bool available) { + if (available) { + EXPECT_CALL(*this, UserTriggeredGeneratePasswordReply( + testing::Ne(base::nullopt))); + } else { + EXPECT_CALL(*this, UserTriggeredGeneratePasswordReply( + testing::Eq(base::nullopt))); + } + password_generation_->UserTriggeredGeneratePassword(base::BindOnce( + &PasswordGenerationAgentTest::UserTriggeredGeneratePasswordReply, + base::Unretained(this))); + testing::Mock::VerifyAndClearExpectations(this); } void BindPasswordManagerDriver(mojo::ScopedInterfaceEndpointHandle handle) { @@ -168,11 +165,16 @@ void BindPasswordManagerClient(mojo::ScopedInterfaceEndpointHandle handle) { fake_pw_client_.BindRequest( - mojom::PasswordManagerClientAssociatedRequest(std::move(handle))); + mojom::PasswordGenerationDriverAssociatedRequest(std::move(handle))); } + // Callback for UserTriggeredGeneratePassword. + MOCK_METHOD1(UserTriggeredGeneratePasswordReply, + void(const base::Optional< + autofill::password_generation::PasswordGenerationUIData>&)); + FakeMojoPasswordManagerDriver fake_driver_; - FakePasswordManagerClient fake_pw_client_; + FakePasswordGenerationDriver fake_pw_client_; private: DISALLOW_COPY_AND_ASSIGN(PasswordGenerationAgentTest); @@ -838,20 +840,17 @@ TEST_F(PasswordGenerationAgentTest, ManualGenerationInFormTest) { LoadHTMLWithUserGesture(kAccountCreationFormHTML); - SelectGenerationFallbackInContextMenu("first_password"); - ExpectManualGenerationAvailable("first_password", true); - ExpectManualGenerationAvailable("second_password", false); + SimulateElementRightClick("first_password"); + SelectGenerationFallbackAndExpect(true); // Re-focusing a password field for which manual generation was requested - // should not re-trigger generation, manual or automatic. - ExpectManualGenerationAvailable("first_password", false); + // should not re-trigger generation. ExpectAutomaticGenerationAvailable("first_password", false); } TEST_F(PasswordGenerationAgentTest, ManualGenerationNoFormTest) { LoadHTMLWithUserGesture(kAccountCreationNoForm); - SelectGenerationFallbackInContextMenu("first_password"); - ExpectManualGenerationAvailable("first_password", true); - ExpectManualGenerationAvailable("second_password", false); + SimulateElementRightClick("first_password"); + SelectGenerationFallbackAndExpect(true); } TEST_F(PasswordGenerationAgentTest, ManualGenerationDoesntSuppressAutomatic) { @@ -862,7 +861,7 @@ ExpectAutomaticGenerationAvailable("first_password", true); // The browser may show a standard password dropdown with the "Generate" // option. In this case manual generation is triggered. - password_generation_->UserTriggeredGeneratePassword(); + SelectGenerationFallbackAndExpect(true); // Move the focus away to somewhere. FocusField("address"); @@ -875,10 +874,9 @@ LoadHTMLWithUserGesture(kAccountCreationNoIds); ExecuteJavaScriptForTests( "document.getElementsByClassName('first_password')[0].focus();"); - password_generation_->UserTriggeredGeneratePassword(); // TODO(crbug/866444): generation doesn't work properly on the password field // without name and id. Temporarily it's disabled. - EXPECT_FALSE(GetCalledShowManualPasswordGenerationPopup()); + SelectGenerationFallbackAndExpect(false); } TEST_F(PasswordGenerationAgentTest, PresavingGeneratedPassword) { @@ -893,8 +891,8 @@ LoadHTMLWithUserGesture(test_case.form); // To be able to work with input elements outside <form>'s, use manual // generation. - SelectGenerationFallbackInContextMenu(test_case.generation_element); - ExpectManualGenerationAvailable(test_case.generation_element, true); + SimulateElementRightClick(test_case.generation_element); + SelectGenerationFallbackAndExpect(true); base::string16 password = base::ASCIIToUTF16("random_password"); EXPECT_CALL(fake_pw_client_, @@ -932,8 +930,8 @@ TEST_F(PasswordGenerationAgentTest, FallbackForSaving) { LoadHTMLWithUserGesture(kAccountCreationFormHTML); - SelectGenerationFallbackInContextMenu("first_password"); - ExpectManualGenerationAvailable("first_password", true); + SimulateElementRightClick("first_password"); + SelectGenerationFallbackAndExpect(true); EXPECT_EQ(0, fake_driver_.called_show_manual_fallback_for_saving_count()); base::string16 password = base::ASCIIToUTF16("random_password"); EXPECT_CALL(fake_pw_client_, @@ -1074,7 +1072,8 @@ ASSERT_FALSE(element.IsNull()); WebInputElement first_password_element = element.To<WebInputElement>(); EXPECT_TRUE(first_password_element.Value().IsNull()); - SelectGenerationFallbackInContextMenu("first_password"); + SimulateElementRightClick("first_password"); + SelectGenerationFallbackAndExpect(true); EXPECT_TRUE(first_password_element.Value().IsNull()); } @@ -1082,7 +1081,7 @@ // Checks the fallback doesn't cause a crash just in case no password element // had focus so far. LoadHTMLWithUserGesture(kAccountCreationFormHTML); - password_generation_->UserTriggeredGeneratePassword(); + SelectGenerationFallbackAndExpect(false); } TEST_F(PasswordGenerationAgentTest, AutofillToGenerationField) {
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 5ed13cd..9136ab5 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -82,7 +82,6 @@ #include "components/network_hints/renderer/prescient_networking_dispatcher.h" #include "components/pdf/renderer/pepper_pdf_host.h" #include "components/safe_browsing/renderer/threat_dom_details.h" -#include "components/services/heap_profiling/public/cpp/allocator_shim.h" #include "components/spellcheck/spellcheck_buildflags.h" #include "components/startup_metric_utils/common/startup_metric.mojom.h" #include "components/subresource_filter/content/renderer/subresource_filter_agent.h"
diff --git a/chrome/service/BUILD.gn b/chrome/service/BUILD.gn index 9745733..6f72490 100644 --- a/chrome/service/BUILD.gn +++ b/chrome/service/BUILD.gn
@@ -57,7 +57,6 @@ configs += [ "//build/config/compiler:wexit_time_destructors" ] deps = [ - ":service_process_catalog_source", "//base", "//chrome:strings", "//chrome/common", @@ -66,6 +65,7 @@ "//components/data_use_measurement/core", "//components/network_session_configurator/browser", "//components/printing/common", + "//content/public/app:service_manifests", "//google_apis", "//jingle:notifier", "//mojo/public/cpp/platform", @@ -91,15 +91,3 @@ ] } } - -catalog("service_process_catalog") { - embedded_services = [ - "//content/public/app:browser_manifest", - "//content/public/app:utility_manifest", - ] -} - -catalog_cpp_source("service_process_catalog_source") { - catalog = ":service_process_catalog" - generated_function_name = "CreateServiceProcessCatalog" -}
diff --git a/chrome/service/DEPS b/chrome/service/DEPS index 305a137..49a6a972 100644 --- a/chrome/service/DEPS +++ b/chrome/service/DEPS
@@ -7,6 +7,7 @@ "+components/network_session_configurator/common", "+components/prefs", "+components/version_info", + "+content/public/app", "+mojo/core/embedder", "+services/network/public/cpp", "+sandbox/win/src",
diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc index e1d80f3a..fba3089 100644 --- a/chrome/service/service_utility_process_host.cc +++ b/chrome/service/service_utility_process_host.cc
@@ -29,8 +29,9 @@ #include "base/win/win_util.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_utility_printing_messages.h" -#include "chrome/service/service_process_catalog_source.h" #include "chrome/services/printing/public/mojom/pdf_to_emf_converter.mojom.h" +#include "content/public/app/content_browser_manifest.h" +#include "content/public/app/content_utility_manifest.h" #include "content/public/common/child_process_host.h" #include "content/public/common/connection_filter.h" #include "content/public/common/content_switches.h" @@ -359,9 +360,11 @@ // instances: this process, which masquerades as "content_browser"; and the // child process, which exists ostensibly as the only instance of // "content_utility". This is all set up here. + std::vector<service_manager::Manifest> manifests{ + content::GetContentBrowserManifest(), + content::GetContentUtilityManifest()}; service_manager_ = std::make_unique<service_manager::ServiceManager>( - std::make_unique<NullServiceProcessLauncherFactory>(), - CreateServiceProcessCatalog()); + std::make_unique<NullServiceProcessLauncherFactory>(), manifests); service_manager::mojom::ServicePtr browser_proxy; service_manager_connection_ = content::ServiceManagerConnection::Create(
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index f9d8c50..545cdb5 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -7,6 +7,7 @@ import("//build/config/crypto.gni") import("//build/config/features.gni") import("//build/config/ui.gni") +import("//build/util/version.gni") import("//chrome/chrome_repack_locales.gni") import("//chrome/common/features.gni") import("//chromeos/assistant/assistant.gni") @@ -370,14 +371,13 @@ "//third_party/webgl/", "//content/test/gpu/run_gpu_integration_test.py", - # For pixel_test - "//media/test/data/bear.mp4", - "//media/test/data/bear-vp9.webm", + # For pixel_test and trace_test "//media/test/data/four-colors.mp4", "//media/test/data/four-colors-aspect-4x3.mp4", "//media/test/data/four-colors-rot-90.mp4", "//media/test/data/four-colors-rot-180.mp4", "//media/test/data/four-colors-rot-270.mp4", + "//media/test/data/four-colors-vp9.webm", ] # For pixel_test and maps_pixel_test. Because this links to a CIPD @@ -462,7 +462,10 @@ data = [] - defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + defines = [ + "HAS_OUT_OF_PROC_TEST_RUNNER", + "CHROME_VERSION_MAJOR=" + chrome_version_major, + ] if (is_win) { data += [ "$root_out_dir/chrome_200_percent.pak" ] @@ -542,6 +545,7 @@ "../browser/apps/platform_apps/platform_app_navigation_redirector_browsertest.cc", "../browser/apps/platform_apps/service_worker_browsertest.cc", "../browser/autocomplete/autocomplete_browsertest.cc", + "../browser/autofill/autofill_autocomplete_browsertest.cc", "../browser/autofill/autofill_browsertest.cc", "../browser/autofill/autofill_metrics_browsertest.cc", "../browser/autofill/autofill_provider_browsertest.cc", @@ -999,8 +1003,8 @@ "../renderer/autofill/autofill_renderer_browsertest.cc", "../renderer/autofill/fake_mojo_password_manager_driver.cc", "../renderer/autofill/fake_mojo_password_manager_driver.h", - "../renderer/autofill/fake_password_manager_client.cc", - "../renderer/autofill/fake_password_manager_client.h", + "../renderer/autofill/fake_password_generation_driver.cc", + "../renderer/autofill/fake_password_generation_driver.h", "../renderer/autofill/form_autocomplete_browsertest.cc", "../renderer/autofill/form_autofill_browsertest.cc", "../renderer/autofill/form_control_click_detection_browsertest.cc", @@ -1534,6 +1538,7 @@ "../browser/ui/views/autofill/autofill_popup_base_view_browsertest.cc", "../browser/ui/views/autofill/card_unmask_prompt_view_tester_views.cc", "../browser/ui/views/autofill/card_unmask_prompt_view_tester_views.h", + "../browser/ui/views/autofill/local_card_migration_browsertest.cc", "../browser/ui/views/autofill/save_card_bubble_views_browsertest.cc", "../browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc", "../browser/ui/views/autofill/save_card_bubble_views_browsertest_base.h",
diff --git a/chrome/test/android/chrome_public_test_support/AndroidManifest.xml b/chrome/test/android/chrome_public_test_support/AndroidManifest.xml index 00473fa..bac5256 100644 --- a/chrome/test/android/chrome_public_test_support/AndroidManifest.xml +++ b/chrome/test/android/chrome_public_test_support/AndroidManifest.xml
@@ -5,7 +5,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="org.chromium.chrome.tests.support"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="22" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="22" /> <uses-permission android:name="android.permission.INTERNET" /> <application> <service android:name="org.chromium.chrome.browser.media.TestMediaRouteProviderService"
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index f114285e..3316479 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc
@@ -369,6 +369,12 @@ set_is_guest_profile(guest_session_); + ProfileManager* profile_manager = g_browser_process->profile_manager(); + if (profile_manager) { + set_is_system_profile(profile_path_ == + profile_manager->GetSystemProfilePath()); + } + BrowserContext::Initialize(this, profile_path_); #if defined(OS_ANDROID)
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h index 412b409..dc026c6 100644 --- a/chrome/test/base/testing_profile.h +++ b/chrome/test/base/testing_profile.h
@@ -246,7 +246,9 @@ const base::FilePath& partition_path) override; #endif // !defined(OS_ANDROID) scoped_refptr<base::SequencedTaskRunner> GetIOTaskRunner() override; - bool IsOffTheRecord() const override; + // Do not override IsOffTheRecord to turn a normal profile into an incognito + // profile dynamically. + bool IsOffTheRecord() const final; content::DownloadManagerDelegate* GetDownloadManagerDelegate() override; content::ResourceContext* GetResourceContext() override; content::BrowserPluginGuestManager* GetGuestManager() override;
diff --git a/chrome/test/base/testing_profile_manager.cc b/chrome/test/base/testing_profile_manager.cc index df57dbc..b74f489 100644 --- a/chrome/test/base/testing_profile_manager.cc +++ b/chrome/test/base/testing_profile_manager.cc
@@ -145,7 +145,9 @@ profile->set_profile_name(kGuestProfileName); // Set up a profile with an off the record profile. - TestingProfile::Builder().BuildIncognito(profile); + TestingProfile::Builder off_the_record_builder; + off_the_record_builder.SetGuestSession(); + off_the_record_builder.BuildIncognito(profile); profile_manager_->AddProfile(profile); // Takes ownership. profile_manager_->SetNonPersonalProfilePrefs(profile);
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations index df1b790..2ab5348 100644 --- a/chrome/test/chromedriver/test/test_expectations +++ b/chrome/test/chromedriver/test/test_expectations
@@ -40,18 +40,6 @@ _OS_NEGATIVE_FILTER['linux'] = [ ] _OS_NEGATIVE_FILTER['mac'] = [ - # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2664 - 'WindowTest.canFullscreenTheWindow', - 'WindowTest.testSetsTheSizeOfTheCurrentWindowFromIframe', - 'WindowTest.testSetsTheSizeOfTheCurrentWindowFromFrame', - 'WindowTest.canFullscreenTheWindowFromFrame', - 'WindowTest.canFullscreenTheWindowFromIframe', - 'WindowTest.testSetsTheSizeOfTheCurrentWindow', - 'BasicMouseInterfaceTest.testMovingMouseByRelativeOffset', - # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2748 - 'WindowTest.testCanMaximizeTheWindowFromFrame', - 'WindowTest.testCanMaximizeTheWindowFromIframe', - 'WindowTest.testCanMaximizeTheWindow', ] _SPECIFIC_OS_REVISION_NEGATIVE_FILTER = {}
diff --git a/chrome/test/data/autofill/autocomplete_simple_form.html b/chrome/test/data/autofill/autocomplete_simple_form.html new file mode 100644 index 0000000..d5cb460 --- /dev/null +++ b/chrome/test/data/autofill/autocomplete_simple_form.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"> +<!-- Autocomplete generic test form. --> +<html> + <head> + <title>Autocomplete Test Form</title> + </head> + <body> + <h3>Autocomplete Test Form</h3> + <form name="testform" method="post" id="testform"> + <p> + <label>First Name:</label> + <input type="text" id="n300" /> + <br /> + <input type="submit" value="send" /> + <input type="reset" /> + </p> + </form> + </body> +</html>
diff --git a/chrome/test/data/background_fetch/background_fetch.js b/chrome/test/data/background_fetch/background_fetch.js index 29324a3..8d1cf591 100644 --- a/chrome/test/data/background_fetch/background_fetch.js +++ b/chrome/test/data/background_fetch/background_fetch.js
@@ -9,7 +9,7 @@ { src: '/notifications/icon.png', sizes: '100x100', - type: 'image/png' + type: 'image/png', } ]; @@ -34,6 +34,25 @@ }).catch(sendErrorToTest); } +// Starts a Background Fetch with multiple files. +function StartFetchWithMultipleFiles() { + navigator.serviceWorker.ready.then(swRegistration => { + const options = { + icons: kIcon, + title: 'multi-file Background Fetch', + }; + + const requests = Array(100) + .fill('/background_fetch/types_of_cheese.txt') + .map((req, idx) => `${req}?idx=${idx}`); + + return swRegistration.backgroundFetch.fetch( + kBackgroundFetchId, requests, options); + }).then(bgFetchRegistration => { + sendResultToTest('ok'); + }).catch(sendErrorToTest); +} + // Starts a Background Fetch request for a single to-be-downloaded file, with // downloadTotal greater than the actual size. function StartSingleFileDownloadWithBiggerThanActualDownloadTotal() { @@ -90,6 +109,7 @@ const expectedResponses = [ 'backgroundfetchsuccess', 'backgroundfetchfail', + 'backgroundfetchabort', 'permissionerror', 'ok', ];
diff --git a/chrome/test/data/background_fetch/sw.js b/chrome/test/data/background_fetch/sw.js index f9d87160..6aa3e10 100644 --- a/chrome/test/data/background_fetch/sw.js +++ b/chrome/test/data/background_fetch/sw.js
@@ -8,7 +8,7 @@ // Posts |msg| to background_fetch.js. function postToWindowClients(msg) { - clients.matchAll({ type: 'window' }).then(clientWindows => { + return clients.matchAll({ type: 'window' }).then(clientWindows => { for (const client of clientWindows) client.postMessage(msg); }); } @@ -35,6 +35,10 @@ () => postToWindowClients(e.type))); }); +self.addEventListener('backgroundfetchabort', e => { + e.waitUntil(postToWindowClients(e.type)); +}); + self.addEventListener('backgroundfetchclick', e => { e.waitUntil(clients.openWindow( '/background_fetch/background_fetch.html?clickevent'));
diff --git a/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js b/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js index 8285360..2417079 100644 --- a/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js +++ b/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js
@@ -19,7 +19,8 @@ source: 'device', profile: {profileId: '', displayName: '', isCurrentProfile: true}, diskFileSystemType: 'exfat', - iconSet: {} + iconSet: {}, + driveLabel: 'drive_label1' }; var expectedVolume2 = { @@ -40,7 +41,8 @@ source: 'device', profile: {profileId: '', displayName: '', isCurrentProfile: true}, diskFileSystemType: 'exfat', - iconSet: {} + iconSet: {}, + driveLabel: 'drive_label2' }; var expectedVolume3 = { @@ -59,7 +61,8 @@ source: 'device', profile: {profileId: '', displayName: '', isCurrentProfile: true}, diskFileSystemType: 'exfat', - iconSet: {} + iconSet: {}, + driveLabel: 'drive_label3' }; var expectedDownloadsVolume = { @@ -74,7 +77,8 @@ source: 'system', profile: {profileId: '', displayName: '', isCurrentProfile: true}, diskFileSystemType: '', - iconSet: {} + iconSet: {}, + driveLabel: '' }; var expectedArchiveVolume = { @@ -90,7 +94,8 @@ source: 'file', profile: {profileId: '', displayName: '', isCurrentProfile: true}, diskFileSystemType: '', - iconSet: {} + iconSet: {}, + driveLabel: '' }; var expectedProvidedVolume = { @@ -111,7 +116,8 @@ iconSet: { icon16x16Url: 'chrome://resources/testing-provider-id-16.jpg', icon32x32Url: 'chrome://resources/testing-provider-id-32.jpg' - } + }, + driveLabel: '' }; // List of expected mount points.
diff --git a/chrome/test/data/local_ntp/local_ntp_browsertest.html b/chrome/test/data/local_ntp/local_ntp_browsertest.html index d4ac102..04300dc8 100644 --- a/chrome/test/data/local_ntp/local_ntp_browsertest.html +++ b/chrome/test/data/local_ntp/local_ntp_browsertest.html
@@ -94,7 +94,7 @@ <div id="custom-bg-attr"></div> </div> - <dialog div id="edit-bg-dialog"> + <dialog div id="edit-bg-dialog" class="customize-dialog"> <div id="edit-bg-menu"> <div id="edit-bg-title"></div> <div id="edit-bg-default-wallpapers" class="bg-option" tabindex="0">
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index beeb5ba7..4af0267 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -3418,12 +3418,19 @@ }, { "share_url": "\\\\server\\share", "mode": "drop_down" + }, { + "share_url": "smb://server/share", + "mode": "pre_mount" + }, { + "share_url": "\\\\server\\share", + "mode": "pre_mount" }] }, "pref_mappings": [ { "pref": "network_file_shares.preconfigured_shares" } ] }, + "ScreenBrightnessPercent": { "os": ["chromeos"], "test_policy": {
diff --git a/chrome/test/data/webui/print_preview/cloud_print_interface_stub.js b/chrome/test/data/webui/print_preview/cloud_print_interface_stub.js index 5989fa1..d09904e 100644 --- a/chrome/test/data/webui/print_preview/cloud_print_interface_stub.js +++ b/chrome/test/data/webui/print_preview/cloud_print_interface_stub.js
@@ -78,6 +78,16 @@ this.eventTarget_.dispatchEvent(new CustomEvent( cloudprint.CloudPrintInterfaceEventType.PRINTER_DONE, {detail: printer})); + } else { + this.eventTarget_.dispatchEvent(new CustomEvent( + cloudprint.CloudPrintInterfaceEventType.PRINTER_FAILED, { + detail: { + origin: origin, + destinationId: printerId, + status: 200, + message: 'Unknown printer', + }, + })); } } }
diff --git a/chrome/test/data/webui/print_preview/destination_select_test.js b/chrome/test/data/webui/print_preview/destination_select_test.js index 7bfaa68..62b3102 100644 --- a/chrome/test/data/webui/print_preview/destination_select_test.js +++ b/chrome/test/data/webui/print_preview/destination_select_test.js
@@ -13,6 +13,7 @@ SystemDefaultPrinterPolicy: 'system default printer policy', KioskModeSelectsFirstPrinter: 'kiosk mode selects first printer', NoPrintersShowsError: 'no printers shows error', + UnreachableRecentCloudPrinter: 'unreachable recent cloud printer', }; const suiteName = 'DestinationSelectTests'; @@ -56,9 +57,12 @@ nativeLayer.setInitialSettings(initialSettings); nativeLayer.setLocalDestinations(localDestinations); print_preview.NativeLayer.setInstance(nativeLayer); + const cloudPrintInterface = new print_preview.CloudPrintInterfaceStub(); + cloudprint.setCloudPrintInterfaceForTesting(cloudPrintInterface); PolymerTest.clearBody(); page = document.createElement('print-preview-app'); document.body.appendChild(page); + cr.webUIListenerCallback('use-cloud-print', 'cloudprint url', false); return nativeLayer.whenCalled('getInitialSettings').then(() => { page.destinationStore_.addEventListener( @@ -87,6 +91,7 @@ // Check that the throbber is hidden and the dropdown is shown. assertTrue(destinationSettings.$$('.throbber-container').hidden); assertFalse(destinationSelect.hidden); + assertFalse(destinationSelect.disabled); const options = destinationSelect.shadowRoot.querySelectorAll('option'); const selectedOption = @@ -304,6 +309,30 @@ assertEquals('noDestinations', selected.value); }); }); + + /** + * Tests that if the user has a recent destination that triggers a cloud + * print error this does not disable the dialog. + */ + test(assert(TestNames.UnreachableRecentCloudPrinter), function() { + const cloudPrinter = + print_preview_test_utils.createDestinationWithCertificateStatus( + 'BarDevice', 'BarName', false); + const recentDestination = + print_preview.makeRecentDestination(cloudPrinter); + initialSettings.serializedAppStateStr = JSON.stringify({ + version: 2, + recentDestinations: [recentDestination], + }); + + return setInitialSettings().then(function(args) { + assertEquals(print_preview_new.State.READY, page.state); + assertEquals('FooDevice', args.destinationId); + assertEquals(print_preview.PrinterType.LOCAL, args.type); + assertEquals('FooDevice', page.destination_.id); + return assertPrinterDisplay('FooName'); + }); + }); }); return {
diff --git a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js index 4c5a1f5..ef78621 100644 --- a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js +++ b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
@@ -592,6 +592,7 @@ return super.extraLibraries.concat([ '../settings/test_util.js', '../test_browser_proxy.js', + 'cloud_print_interface_stub.js', 'native_layer_stub.js', 'print_preview_test_utils.js', 'destination_select_test.js', @@ -654,6 +655,13 @@ }); GEN('#endif'); +TEST_F( + 'PrintPreviewDestinationSelectTest', 'UnreachableRecentCloudPrinter', + function() { + this.runMochaTest( + destination_select_test.TestNames.UnreachableRecentCloudPrinter); + }); + PrintPreviewDestinationDialogTest = class extends NewPrintPreviewTest { /** @override */ get browsePreload() {
diff --git a/chrome/test/data/webui/settings/all_sites_tests.js b/chrome/test/data/webui/settings/all_sites_tests.js index ca79780..38e40ea 100644 --- a/chrome/test/data/webui/settings/all_sites_tests.js +++ b/chrome/test/data/webui/settings/all_sites_tests.js
@@ -323,9 +323,9 @@ assertEquals(fooEtldPlus1, siteEntries[0].siteGroup.etldPlus1); assertEquals(2, siteEntries[0].siteGroup.origins.length); + assertEquals(fooOrigin, siteEntries[0].siteGroup.origins[0].origin); assertEquals( - 'https://foo.com', siteEntries[0].siteGroup.origins[0].origin); - assertEquals(fooOrigin, siteEntries[0].siteGroup.origins[1].origin); + 'https://foo.com', siteEntries[0].siteGroup.origins[1].origin); assertEquals(addEtldPlus1, siteEntries[3].siteGroup.etldPlus1); assertEquals(1, siteEntries[3].siteGroup.origins.length);
diff --git a/chrome/test/data/webui/settings/google_assistant_page_test.js b/chrome/test/data/webui/settings/google_assistant_page_test.js index d1158f6..5958ac2 100644 --- a/chrome/test/data/webui/settings/google_assistant_page_test.js +++ b/chrome/test/data/webui/settings/google_assistant_page_test.js
@@ -8,23 +8,11 @@ class TestGoogleAssistantBrowserProxy extends TestBrowserProxy { constructor() { super([ - 'setGoogleAssistantEnabled', - 'setGoogleAssistantContextEnabled', 'showGoogleAssistantSettings', ]); } /** @override */ - setGoogleAssistantEnabled(enabled) { - this.methodCalled('setGoogleAssistantEnabled', enabled); - } - - /** @override */ - setGoogleAssistantContextEnabled(enabled) { - this.methodCalled('setGoogleAssistantContextEnabled', enabled); - } - - /** @override */ showGoogleAssistantSettings() { this.methodCalled('showGoogleAssistantSettings'); } @@ -69,8 +57,6 @@ button.click(); Polymer.dom.flush(); assertTrue(button.checked); - return browserProxy.whenCalled('setGoogleAssistantEnabled') - .then(assertTrue); }); test('toggleAssistantContext', function() { @@ -86,8 +72,6 @@ button.click(); Polymer.dom.flush(); assertTrue(button.checked); - return browserProxy.whenCalled('setGoogleAssistantContextEnabled') - .then(assertTrue); }); test('tapOnAssistantSettings', function() {
diff --git a/chrome/updater/OWNERS b/chrome/updater/OWNERS new file mode 100644 index 0000000..5a5b03e --- /dev/null +++ b/chrome/updater/OWNERS
@@ -0,0 +1,4 @@ +borisv@chromium.org +ganesh@chromium.org +sorin@chromium.org +waffles@chromium.org
diff --git a/chrome/updater/README.md b/chrome/updater/README.md new file mode 100644 index 0000000..b55cc87 --- /dev/null +++ b/chrome/updater/README.md
@@ -0,0 +1,2 @@ +This is the code for the client updater that will soon be used by +desktop Chrome, on macOS and Windows.
diff --git a/chromecast/app/BUILD.gn b/chromecast/app/BUILD.gn index 5166e88..c18b2a8 100644 --- a/chromecast/app/BUILD.gn +++ b/chromecast/app/BUILD.gn
@@ -98,7 +98,10 @@ "//testing/gtest", ] - if (!is_fuchsia) { + if (is_fuchsia) { + sources += [ "cast_main_delegate_unittest.cc" ] + deps += [ ":app" ] + } else { deps += [ # TODO(crbug.com/753619): Enable crash reporting on Fuchsia. ":cast_crash_client",
diff --git a/chromecast/app/android/cast_jni_loader.cc b/chromecast/app/android/cast_jni_loader.cc index 705d49b..cb9350b 100644 --- a/chromecast/app/android/cast_jni_loader.cc +++ b/chromecast/app/android/cast_jni_loader.cc
@@ -23,6 +23,7 @@ return false; content::Compositor::Initialize(); - content::SetContentMainDelegate(new chromecast::shell::CastMainDelegate); + content::SetContentMainDelegate( + new chromecast::shell::CastMainDelegate(0, nullptr)); return JNI_VERSION_1_4; }
diff --git a/chromecast/app/cast_main.cc b/chromecast/app/cast_main.cc index 6c6c0b4f..682a1e21 100644 --- a/chromecast/app/cast_main.cc +++ b/chromecast/app/cast_main.cc
@@ -6,9 +6,9 @@ #include "content/public/app/content_main.h" int main(int argc, const char** argv) { - chromecast::shell::CastMainDelegate delegate; + chromecast::shell::CastMainDelegate delegate(argc, argv); content::ContentMainParams params(&delegate); - params.argc = argc; - params.argv = argv; + params.argc = delegate.argc(); + params.argv = delegate.argv(); return content::ContentMain(params); }
diff --git a/chromecast/app/cast_main_delegate.cc b/chromecast/app/cast_main_delegate.cc index 979a80b1..f3a3afa4 100644 --- a/chromecast/app/cast_main_delegate.cc +++ b/chromecast/app/cast_main_delegate.cc
@@ -10,14 +10,15 @@ #include "base/command_line.h" #include "base/cpu.h" -#include "base/files/file.h" #include "base/files/file_enumerator.h" +#include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" #include "base/metrics/field_trial.h" #include "base/no_destructor.h" #include "base/path_service.h" #include "base/posix/global_descriptors.h" +#include "base/strings/string_tokenizer.h" #include "build/build_config.h" #include "chromecast/base/cast_paths.h" #include "chromecast/base/chromecast_switches.h" @@ -44,6 +45,10 @@ #include "services/service_manager/sandbox/switches.h" #endif // defined(OS_LINUX) +#if defined(OS_FUCHSIA) +#include "base/base_paths_fuchsia.h" +#endif + namespace { #if defined(OS_LINUX) @@ -58,12 +63,43 @@ const int kMaxCrashFiles = 10; #endif // defined(OS_ANDROID) +base::FilePath GetDefaultCommandLineFile() { +#if defined(OS_FUCHSIA) + base::FilePath command_line_dir; + base::PathService::Get(base::DIR_APP_DATA, &command_line_dir); + return command_line_dir.Append("cast/castagent-command-line"); +#else + return base::FilePath(); +#endif +} + } // namespace namespace chromecast { namespace shell { -CastMainDelegate::CastMainDelegate() {} +CastMainDelegate::CastMainDelegate(int argc, const char** argv) + : CastMainDelegate(argc, argv, GetDefaultCommandLineFile()) {} + +CastMainDelegate::CastMainDelegate(int argc, + const char** argv, + base::FilePath command_line_path) + : argv_(argv, argv + argc) { +#if defined(OS_FUCHSIA) + // Read the command-line from the filesystem. + std::string command_line_str; + if (base::ReadFileToString(command_line_path, &command_line_str)) { + LOG(INFO) << "Appending command-line args from " << command_line_path; + base::StringTokenizer tokenizer(command_line_str, "\n"); + while (tokenizer.GetNext()) + argv_strs_.push_back(tokenizer.token()); + for (int i = 0; i < static_cast<int>(argv_strs_.size()); ++i) + argv_.push_back(argv_strs_[i].c_str()); + } else { + LOG(INFO) << "Unable to read command-line args from " << command_line_path; + } +#endif // defined(OS_FUCHSIA) +} CastMainDelegate::~CastMainDelegate() {}
diff --git a/chromecast/app/cast_main_delegate.h b/chromecast/app/cast_main_delegate.h index 2fd26f8..e83d3de 100644 --- a/chromecast/app/cast_main_delegate.h +++ b/chromecast/app/cast_main_delegate.h
@@ -6,7 +6,10 @@ #define CHROMECAST_APP_CAST_MAIN_DELEGATE_H_ #include <memory> +#include <string> +#include <vector> +#include "base/files/file_path.h" #include "base/macros.h" #include "build/build_config.h" #include "chromecast/common/cast_content_client.h" @@ -33,7 +36,7 @@ class CastMainDelegate : public content::ContentMainDelegate { public: - CastMainDelegate(); + CastMainDelegate(int argc, const char** argv); ~CastMainDelegate() override; // content::ContentMainDelegate implementation: @@ -51,7 +54,16 @@ content::ContentRendererClient* CreateContentRendererClient() override; content::ContentUtilityClient* CreateContentUtilityClient() override; + int argc() const { return argv_.size(); } + const char** argv() const { return const_cast<const char**>(argv_.data()); } + private: + friend class CastMainDelegateTest; + + // Used for testing. + CastMainDelegate(int argc, + const char** argv, + base::FilePath command_line_path); void InitializeResourceBundle(); std::unique_ptr<CastContentBrowserClient> browser_client_; @@ -72,6 +84,11 @@ std::unique_ptr<CastFeatureListCreator> cast_feature_list_creator_; + // Combined list of args passed through the main function, and a specified + // command-line file. + std::vector<std::string> argv_strs_; + std::vector<const char*> argv_; + DISALLOW_COPY_AND_ASSIGN(CastMainDelegate); };
diff --git a/chromecast/app/cast_main_delegate_unittest.cc b/chromecast/app/cast_main_delegate_unittest.cc new file mode 100644 index 0000000..f698a11c --- /dev/null +++ b/chromecast/app/cast_main_delegate_unittest.cc
@@ -0,0 +1,83 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <string> + +#include "base/files/file.h" +#include "base/memory/ptr_util.h" +#include "chromecast/app/cast_main_delegate.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromecast { +namespace shell { +namespace { + +const char kTestCommandLineContents[] = "--file1\n--file2\n"; +const char kTestCommandLinePath[] = "/tmp/test-command-line"; + +void WriteTestCommandLine() { + base::File command_line( + base::FilePath(kTestCommandLinePath), + base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + ASSERT_GE(command_line.Write(0, kTestCommandLineContents, + sizeof(kTestCommandLineContents) - 1), + 0); +} + +} // namespace + +class CastMainDelegateTest : public testing::Test { + public: + CastMainDelegateTest() { WriteTestCommandLine(); } + + ~CastMainDelegateTest() override {} + + // testing::Test implementation: + void SetUp() override { + test_argv_strs_.push_back("--main1"); + test_argv_strs_.push_back("--main2"); + test_argv_.push_back(test_argv_strs_[0].c_str()); + test_argv_.push_back(test_argv_strs_[1].c_str()); + } + + void CreateCastMainDelegate(int argc, + const char** argv, + std::string command_line_path) { + delegate_ = base::WrapUnique( + new CastMainDelegate(argc, argv, base::FilePath(command_line_path))); + } + + protected: + std::unique_ptr<CastMainDelegate> delegate_; + std::vector<std::string> test_argv_strs_; + std::vector<const char*> test_argv_; +}; + +TEST_F(CastMainDelegateTest, AddsArgsFromFile) { + CreateCastMainDelegate(0, nullptr, kTestCommandLinePath); + EXPECT_EQ(2, delegate_->argc()); + EXPECT_EQ("--file1", std::string(delegate_->argv()[0])); + EXPECT_EQ("--file2", std::string(delegate_->argv()[1])); +} + +TEST_F(CastMainDelegateTest, AddsArgsFromMain) { + CreateCastMainDelegate(test_argv_.size(), &test_argv_[0], ""); + EXPECT_EQ(2, delegate_->argc()); + EXPECT_EQ("--main1", std::string(delegate_->argv()[0])); + EXPECT_EQ("--main2", std::string(delegate_->argv()[1])); +} + +TEST_F(CastMainDelegateTest, MergesArgsFromFileAndMain) { + CreateCastMainDelegate(test_argv_.size(), &test_argv_[0], + kTestCommandLinePath); + EXPECT_EQ(4, delegate_->argc()); + EXPECT_EQ("--main1", std::string(delegate_->argv()[0])); + EXPECT_EQ("--main2", std::string(delegate_->argv()[1])); + EXPECT_EQ("--file1", std::string(delegate_->argv()[2])); + EXPECT_EQ("--file2", std::string(delegate_->argv()[3])); +} + +} // namespace shell +} // namespace chromecast
diff --git a/chromecast/app/cast_test_launcher.cc b/chromecast/app/cast_test_launcher.cc index 73c44ea..a2fa071 100644 --- a/chromecast/app/cast_test_launcher.cc +++ b/chromecast/app/cast_test_launcher.cc
@@ -35,7 +35,7 @@ protected: content::ContentMainDelegate* CreateContentMainDelegate() override { - return new CastMainDelegate(); + return new CastMainDelegate(0, nullptr); } private:
diff --git a/chromecast/base/chromecast_switches.cc b/chromecast/base/chromecast_switches.cc index f287db6..c64a04e 100644 --- a/chromecast/base/chromecast_switches.cc +++ b/chromecast/base/chromecast_switches.cc
@@ -32,6 +32,9 @@ // Disable features that require WiFi management. const char kNoWifi[] = "no-wifi"; +// Only connect to WLAN interfaces. +const char kRequireWlan[] = "require-wlan"; + // Pass the app id information to the renderer process, to be used for logging. // last-launched-app should be the app that just launched and is spawning the // renderer.
diff --git a/chromecast/base/chromecast_switches.h b/chromecast/base/chromecast_switches.h index 456ab1b7..40fec18d 100644 --- a/chromecast/base/chromecast_switches.h +++ b/chromecast/base/chromecast_switches.h
@@ -30,6 +30,7 @@ // Network switches extern const char kNoWifi[]; +extern const char kRequireWlan[]; // Switches to communicate app state information extern const char kLastLaunchedApp[];
diff --git a/chromecast/browser/OWNERS b/chromecast/browser/OWNERS index 2f308c9..8792275 100644 --- a/chromecast/browser/OWNERS +++ b/chromecast/browser/OWNERS
@@ -1,3 +1,5 @@ +seantopping@chromium.org + per-file cast_overlay_manifests.h=set noparent per-file cast_overlay_manifests.h=file://ipc/SECURITY_OWNERS per-file cast_overlay_manifests.cc=set noparent
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc index a84c674..194213a 100644 --- a/chromecast/browser/cast_browser_main_parts.cc +++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -77,9 +77,11 @@ #include "components/crash/content/browser/child_exit_observer_android.h" #include "components/crash/content/browser/child_process_crash_observer_android.h" #include "net/android/network_change_notifier_factory_android.h" -#else +#elif defined(OS_FUCHSIA) +#include "chromecast/net/network_change_notifier_factory_fuchsia.h" +#else // defined(OS_FUCHSIA) #include "chromecast/net/network_change_notifier_factory_cast.h" -#endif +#endif // !(defined(OS_ANDROID) || defined(OS_FUCHSIA)) #if defined(OS_FUCHSIA) #include "chromecast/net/fake_connectivity_checker.h" @@ -376,10 +378,13 @@ #if defined(OS_ANDROID) net::NetworkChangeNotifier::SetFactory( new net::NetworkChangeNotifierFactoryAndroid()); -#elif !defined(OS_FUCHSIA) +#elif defined(OS_FUCHSIA) + net::NetworkChangeNotifier::SetFactory( + new NetworkChangeNotifierFactoryFuchsia()); +#else // defined(OS_FUCHSIA) net::NetworkChangeNotifier::SetFactory( new NetworkChangeNotifierFactoryCast()); -#endif // !defined(OS_FUCHSIA) +#endif // !(defined(OS_ANDROID) || defined(OS_FUCHSIA)) } void CastBrowserMainParts::PostMainMessageLoopStart() { @@ -463,17 +468,10 @@ cast_browser_process_->SetNetLog(net_log_.get()); url_request_context_factory_->InitializeOnUIThread(net_log_.get()); -#if defined(OS_FUCHSIA) - // TODO(777973): Switch to using the real ConnectivityChecker once setup works - // properly. - LOG(WARNING) << "Using FakeConnectivityChecker."; - cast_browser_process_->SetConnectivityChecker(new FakeConnectivityChecker()); -#else cast_browser_process_->SetConnectivityChecker(ConnectivityChecker::Create( base::CreateSingleThreadTaskRunnerWithTraits( {content::BrowserThread::IO}), url_request_context_factory_->GetSystemGetter())); -#endif // defined(OS_FUCHSIA) cast_browser_process_->SetBrowserContext( std::make_unique<CastBrowserContext>(url_request_context_factory_));
diff --git a/chromecast/cast_shell_sandbox_policy b/chromecast/cast_shell_sandbox_policy index 9b79c65..2555134 100644 --- a/chromecast/cast_shell_sandbox_policy +++ b/chromecast/cast_shell_sandbox_policy
@@ -19,5 +19,6 @@ "fuchsia.ui.viewsv1.ViewManager", "fuchsia.vulkan.loader.Loader", "fuchsia.wlan.service.Wlan" - ] + ], + "system": [ "data/cast" ] }
diff --git a/chromecast/common/OWNERS b/chromecast/common/OWNERS index 08850f4..273c7a03 100644 --- a/chromecast/common/OWNERS +++ b/chromecast/common/OWNERS
@@ -1,2 +1,4 @@ +seantopping@chromium.org + per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromecast/net/BUILD.gn b/chromecast/net/BUILD.gn index ce7780b..f29155f 100644 --- a/chromecast/net/BUILD.gn +++ b/chromecast/net/BUILD.gn
@@ -35,6 +35,18 @@ "//components/proxy_config", "//net", ] + + if (is_fuchsia) { + sources += [ + "network_change_notifier_factory_fuchsia.cc", + "network_change_notifier_factory_fuchsia.h", + ] + + deps += [ + "//chromecast/base:chromecast_switches", + "//third_party/fuchsia-sdk/sdk:hardware_ethernet", + ] + } } cast_source_set("small_message_socket") {
diff --git a/chromecast/net/network_change_notifier_factory_fuchsia.cc b/chromecast/net/network_change_notifier_factory_fuchsia.cc new file mode 100644 index 0000000..b0c968b --- /dev/null +++ b/chromecast/net/network_change_notifier_factory_fuchsia.cc
@@ -0,0 +1,31 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/net/network_change_notifier_factory_fuchsia.h" + +#include <fuchsia/hardware/ethernet/cpp/fidl.h> + +#include "base/command_line.h" +#include "chromecast/base/chromecast_switches.h" +#include "net/base/network_change_notifier_fuchsia.h" + +namespace chromecast { + +net::NetworkChangeNotifier* +NetworkChangeNotifierFactoryFuchsia::CreateInstance() { + uint32_t required_features = + base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kRequireWlan) + ? fuchsia::hardware::ethernet::INFO_FEATURE_WLAN + : 0; + + // Caller assumes ownership. + return new net::NetworkChangeNotifierFuchsia(required_features); +} + +NetworkChangeNotifierFactoryFuchsia::NetworkChangeNotifierFactoryFuchsia() = + default; +NetworkChangeNotifierFactoryFuchsia::~NetworkChangeNotifierFactoryFuchsia() = + default; + +} // namespace chromecast
diff --git a/chromecast/net/network_change_notifier_factory_fuchsia.h b/chromecast/net/network_change_notifier_factory_fuchsia.h new file mode 100644 index 0000000..0cf0818 --- /dev/null +++ b/chromecast/net/network_change_notifier_factory_fuchsia.h
@@ -0,0 +1,28 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_NET_NETWORK_CHANGE_NOTIFIER_FACTORY_FUCHSIA_H_ +#define CHROMECAST_NET_NETWORK_CHANGE_NOTIFIER_FACTORY_FUCHSIA_H_ + +#include "base/macros.h" +#include "net/base/network_change_notifier_factory.h" + +namespace chromecast { + +class NetworkChangeNotifierFactoryFuchsia + : public net::NetworkChangeNotifierFactory { + public: + NetworkChangeNotifierFactoryFuchsia(); + ~NetworkChangeNotifierFactoryFuchsia() override; + + // net::NetworkChangeNotifierFactory implementation: + net::NetworkChangeNotifier* CreateInstance() override; + + private: + DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierFactoryFuchsia); +}; + +} // namespace chromecast + +#endif // CHROMECAST_NET_NETWORK_CHANGE_NOTIFIER_FACTORY_FUCHSIA_H_
diff --git a/chromecast/renderer/OWNERS b/chromecast/renderer/OWNERS new file mode 100644 index 0000000..3bdcee8 --- /dev/null +++ b/chromecast/renderer/OWNERS
@@ -0,0 +1 @@ +seantopping@chromium.org
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index ea4ac62..7ffefe76 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -11572.0.0 \ No newline at end of file +11631.0.0 \ No newline at end of file
diff --git a/chromeos/components/drivefs/drivefs_auth_unittest.cc b/chromeos/components/drivefs/drivefs_auth_unittest.cc index 911a526..c692ee1 100644 --- a/chromeos/components/drivefs/drivefs_auth_unittest.cc +++ b/chromeos/components/drivefs/drivefs_auth_unittest.cc
@@ -11,6 +11,7 @@ #include "base/test/scoped_task_environment.h" #include "base/test/simple_test_clock.h" #include "services/identity/public/mojom/constants.mojom.h" +#include "services/identity/public/mojom/identity_manager.mojom-test-utils.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/connector.h"
diff --git a/chromeos/components/drivefs/drivefs_bootstrap_unittest.cc b/chromeos/components/drivefs/drivefs_bootstrap_unittest.cc index 9a810dc..c638916 100644 --- a/chromeos/components/drivefs/drivefs_bootstrap_unittest.cc +++ b/chromeos/components/drivefs/drivefs_bootstrap_unittest.cc
@@ -8,6 +8,7 @@ #include "base/run_loop.h" #include "base/test/scoped_task_environment.h" +#include "chromeos/components/drivefs/mojom/drivefs.mojom-test-utils.h" #include "chromeos/components/drivefs/pending_connection_manager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromeos/components/drivefs/drivefs_host_unittest.cc b/chromeos/components/drivefs/drivefs_host_unittest.cc index fdded5a..a7c0306 100644 --- a/chromeos/components/drivefs/drivefs_host_unittest.cc +++ b/chromeos/components/drivefs/drivefs_host_unittest.cc
@@ -19,6 +19,7 @@ #include "base/timer/mock_timer.h" #include "chromeos/components/drivefs/drivefs_host_observer.h" #include "chromeos/components/drivefs/fake_drivefs.h" +#include "chromeos/components/drivefs/mojom/drivefs.mojom-test-utils.h" #include "chromeos/components/drivefs/pending_connection_manager.h" #include "chromeos/disks/mock_disk_mount_manager.h" #include "components/drive/drive_notification_manager.h" @@ -28,6 +29,7 @@ #include "mojo/public/cpp/bindings/binding_set.h" #include "net/base/mock_network_change_notifier.h" #include "services/identity/public/mojom/constants.mojom.h" +#include "services/identity/public/mojom/identity_manager.mojom-test-utils.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/connector.h"
diff --git a/chromeos/components/drivefs/drivefs_search_unittest.cc b/chromeos/components/drivefs/drivefs_search_unittest.cc index a33be40b..a1abd5e 100644 --- a/chromeos/components/drivefs/drivefs_search_unittest.cc +++ b/chromeos/components/drivefs/drivefs_search_unittest.cc
@@ -8,6 +8,7 @@ #include "base/test/bind_test_util.h" #include "base/test/scoped_task_environment.h" #include "base/test/simple_test_clock.h" +#include "chromeos/components/drivefs/mojom/drivefs.mojom-test-utils.h" #include "mojo/public/cpp/bindings/binding.h" #include "net/base/mock_network_change_notifier.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chromeos/dbus/fake_smb_provider_client.cc b/chromeos/dbus/fake_smb_provider_client.cc index 0e47ede2..0814d2a 100644 --- a/chromeos/dbus/fake_smb_provider_client.cc +++ b/chromeos/dbus/fake_smb_provider_client.cc
@@ -268,6 +268,14 @@ FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK)); } +void FakeSmbProviderClient::Premount(const base::FilePath& share_path, + bool ntlm_enabled, + MountCallback callback) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK, + 1 /* mount_id */)); +} + void FakeSmbProviderClient::ClearShares() { shares_.clear(); }
diff --git a/chromeos/dbus/fake_smb_provider_client.h b/chromeos/dbus/fake_smb_provider_client.h index ac2f437..4bfc0c0 100644 --- a/chromeos/dbus/fake_smb_provider_client.h +++ b/chromeos/dbus/fake_smb_provider_client.h
@@ -137,6 +137,10 @@ base::ScopedFD password_fd, StatusCallback callback) override; + void Premount(const base::FilePath& share_path, + bool ntlm_enabled, + MountCallback callback) override; + // Adds |share| to the list of shares for |server_url| in |shares_|. void AddToShares(const std::string& server_url, const std::string& share);
diff --git a/chromeos/dbus/smb_provider_client.cc b/chromeos/dbus/smb_provider_client.cc index 57a1ae7c..8d1bd5f4 100644 --- a/chromeos/dbus/smb_provider_client.cc +++ b/chromeos/dbus/smb_provider_client.cc
@@ -4,6 +4,8 @@ #include "chromeos/dbus/smb_provider_client.h" +#include <memory> + #include "base/bind.h" #include "base/bind_helpers.h" #include "base/files/file_util.h" @@ -120,6 +122,25 @@ CallDefaultMethod(&method_call, &callback); } + void Premount(const base::FilePath& share_path, + bool ntlm_enabled, + MountCallback callback) override { + smbprovider::PremountOptionsProto options; + options.set_path(share_path.value()); + + std::unique_ptr<smbprovider::MountConfigProto> config = + CreateMountConfigProto(ntlm_enabled); + options.set_allocated_mount_config(config.release()); + + dbus::MethodCall method_call(smbprovider::kSmbProviderInterface, + smbprovider::kPremountMethod); + dbus::MessageWriter writer(&method_call); + writer.AppendProtoAsArrayOfBytes(options); + + CallMethod(&method_call, &SmbProviderClientImpl::HandleMountCallback, + &callback); + } + void Unmount(int32_t mount_id, StatusCallback callback) override { smbprovider::UnmountOptionsProto options; options.set_mount_id(mount_id);
diff --git a/chromeos/dbus/smb_provider_client.h b/chromeos/dbus/smb_provider_client.h index 4cd7bb4a..11c1766 100644 --- a/chromeos/dbus/smb_provider_client.h +++ b/chromeos/dbus/smb_provider_client.h
@@ -82,6 +82,13 @@ // the list of valid mounts. Subsequent operations on |mount_id| will fail. virtual void Unmount(int32_t mount_id, StatusCallback callback) = 0; + // Calls Premount. This attempts to mount the share at |share_path|. Premount + // succeeds even if authentication fails and the user can provide the + // credentials at a later time. + virtual void Premount(const base::FilePath& share_path, + bool ntlm_enabled, + MountCallback callback) = 0; + // Calls ReadDirectory. Using the corresponding mount of |mount_id|, this // reads the directory on a given |directory_path| and passes the // DirectoryEntryList to the supplied ReadDirectoryCallback.
diff --git a/chromeos/network/BUILD.gn b/chromeos/network/BUILD.gn index 320541a..756c831 100644 --- a/chromeos/network/BUILD.gn +++ b/chromeos/network/BUILD.gn
@@ -17,6 +17,7 @@ "//chromeos/dbus", "//chromeos/login/login_state", "//components/account_id", + "//components/certificate_matching", "//components/device_event_log", "//components/onc", "//components/pref_registry", @@ -35,8 +36,6 @@ "auto_connect_handler.h", "certificate_helper.cc", "certificate_helper.h", - "certificate_pattern.cc", - "certificate_pattern.h", "client_cert_resolver.cc", "client_cert_resolver.h", "client_cert_util.cc", @@ -111,6 +110,8 @@ "onc/onc_certificate_importer.h", "onc/onc_certificate_importer_impl.cc", "onc/onc_certificate_importer_impl.h", + "onc/onc_certificate_pattern.cc", + "onc/onc_certificate_pattern.h", "onc/onc_mapper.cc", "onc/onc_mapper.h", "onc/onc_merger.cc", @@ -239,6 +240,7 @@ "network_ui_data_unittest.cc", "network_util_unittest.cc", "onc/onc_certificate_importer_impl_unittest.cc", + "onc/onc_certificate_pattern_unittest.cc", "onc/onc_merger_unittest.cc", "onc/onc_normalizer_unittest.cc", "onc/onc_parsed_certificates_unittest.cc",
diff --git a/chromeos/network/DEPS b/chromeos/network/DEPS index 9d2b2b45..085fe7ab 100644 --- a/chromeos/network/DEPS +++ b/chromeos/network/DEPS
@@ -8,6 +8,7 @@ "+chromeos/dbus", "+chromeos/login/login_state", "+components/account_id", + "+components/certificate_matching", "+components/device_event_log", "+components/onc", "+components/pref_registry",
diff --git a/chromeos/network/certificate_pattern.cc b/chromeos/network/certificate_pattern.cc deleted file mode 100644 index 15b3729c..0000000 --- a/chromeos/network/certificate_pattern.cc +++ /dev/null
@@ -1,137 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chromeos/network/certificate_pattern.h" - -#include <stddef.h> - -#include "base/logging.h" -#include "base/values.h" -#include "components/onc/onc_constants.h" - -namespace chromeos { - -namespace { - -bool GetAsListOfStrings(const base::Value& value, - std::vector<std::string>* result) { - const base::ListValue* list = NULL; - if (!value.GetAsList(&list)) - return false; - result->clear(); - result->reserve(list->GetSize()); - for (size_t i = 0; i < list->GetSize(); i++) { - std::string item; - if (!list->GetString(i, &item)) - return false; - result->push_back(item); - } - return true; -} - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// -// IssuerSubjectPattern -IssuerSubjectPattern::IssuerSubjectPattern( - const std::string& common_name, - const std::string& locality, - const std::string& organization, - const std::string& organizational_unit) - : common_name_(common_name), - locality_(locality), - organization_(organization), - organizational_unit_(organizational_unit) { -} - -IssuerSubjectPattern::IssuerSubjectPattern() = default; - -IssuerSubjectPattern::IssuerSubjectPattern(const IssuerSubjectPattern& other) = - default; - -IssuerSubjectPattern::~IssuerSubjectPattern() = default; - -bool IssuerSubjectPattern::Empty() const { - return common_name_.empty() && locality_.empty() && organization_.empty() && - organizational_unit_.empty(); -} - -void IssuerSubjectPattern::Clear() { - common_name_.clear(); - locality_.clear(); - organization_.clear(); - organizational_unit_.clear(); -} - -void IssuerSubjectPattern::ReadFromONCDictionary( - const base::DictionaryValue& dict) { - Clear(); - - dict.GetStringWithoutPathExpansion(onc::client_cert::kCommonName, - &common_name_); - dict.GetStringWithoutPathExpansion(onc::client_cert::kLocality, &locality_); - dict.GetStringWithoutPathExpansion(onc::client_cert::kOrganization, - &organization_); - dict.GetStringWithoutPathExpansion(onc::client_cert::kOrganizationalUnit, - &organizational_unit_); -} - -//////////////////////////////////////////////////////////////////////////////// -// CertificatePattern - -CertificatePattern::CertificatePattern() = default; - -CertificatePattern::CertificatePattern(const CertificatePattern& other) = - default; - -CertificatePattern::~CertificatePattern() = default; - -bool CertificatePattern::Empty() const { - return issuer_ca_pems_.empty() && issuer_.Empty() && subject_.Empty(); -} - -void CertificatePattern::Clear() { - issuer_ca_pems_.clear(); - issuer_.Clear(); - subject_.Clear(); - enrollment_uri_list_.clear(); -} - -bool CertificatePattern::ReadFromONCDictionary( - const base::DictionaryValue& dict) { - Clear(); - - const base::DictionaryValue* child_dict = NULL; - const base::ListValue* child_list = NULL; - - // All of these are optional. - if (dict.GetListWithoutPathExpansion(onc::client_cert::kIssuerCAPEMs, - &child_list) && - child_list) { - if (!GetAsListOfStrings(*child_list, &issuer_ca_pems_)) - return false; - } - if (dict.GetDictionaryWithoutPathExpansion(onc::client_cert::kIssuer, - &child_dict) && - child_dict) { - issuer_.ReadFromONCDictionary(*child_dict); - } - child_dict = NULL; - if (dict.GetDictionaryWithoutPathExpansion(onc::client_cert::kSubject, - &child_dict) && - child_dict) { - subject_.ReadFromONCDictionary(*child_dict); - } - child_list = NULL; - if (dict.GetListWithoutPathExpansion(onc::client_cert::kEnrollmentURI, - &child_list) && - child_list) { - if (!GetAsListOfStrings(*child_list, &enrollment_uri_list_)) - return false; - } - - return true; -} - -} // namespace chromeos
diff --git a/chromeos/network/certificate_pattern.h b/chromeos/network/certificate_pattern.h deleted file mode 100644 index ed471ded..0000000 --- a/chromeos/network/certificate_pattern.h +++ /dev/null
@@ -1,104 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROMEOS_NETWORK_CERTIFICATE_PATTERN_H_ -#define CHROMEOS_NETWORK_CERTIFICATE_PATTERN_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "base/component_export.h" - -namespace base { -class DictionaryValue; -} - -namespace chromeos { - -// Class to represent the DER fields of an issuer or a subject in a -// certificate and compare them. -class COMPONENT_EXPORT(CHROMEOS_NETWORK) IssuerSubjectPattern { - public: - IssuerSubjectPattern(); - IssuerSubjectPattern(const std::string& common_name, - const std::string& locality, - const std::string& organization, - const std::string& organizational_unit); - IssuerSubjectPattern(const IssuerSubjectPattern& other); - ~IssuerSubjectPattern(); - - // Returns true if all fields in the pattern are empty. - bool Empty() const; - - // Clears out all values in this pattern. - void Clear(); - - const std::string& common_name() const { - return common_name_; - } - const std::string& locality() const { - return locality_; - } - const std::string& organization() const { - return organization_; - } - const std::string& organizational_unit() const { - return organizational_unit_; - } - - // Replaces the content of this object with the values of |dictionary|. - // |dictionary| should be a valid ONC IssuerSubjectPattern dictionary. - void ReadFromONCDictionary(const base::DictionaryValue& dictionary); - - private: - std::string common_name_; - std::string locality_; - std::string organization_; - std::string organizational_unit_; -}; - -// A class to contain a certificate pattern and find existing matches to the -// pattern in the certificate database. -class COMPONENT_EXPORT(CHROMEOS_NETWORK) CertificatePattern { - public: - CertificatePattern(); - CertificatePattern(const CertificatePattern& other); - ~CertificatePattern(); - - // Returns true if this pattern has nothing set (and so would match - // all certs). Ignores enrollment_uri_; - bool Empty() const; - - const IssuerSubjectPattern& issuer() const { - return issuer_; - } - const IssuerSubjectPattern& subject() const { - return subject_; - } - const std::vector<std::string>& issuer_ca_pems() const { - return issuer_ca_pems_; - } - const std::vector<std::string>& enrollment_uri_list() const { - return enrollment_uri_list_; - } - - // Replaces the content of this object with the values of |dictionary|. - // |dictionary| should be a valid ONC CertificatePattern dictionary. Returns - // whether all required fields were present. - bool ReadFromONCDictionary(const base::DictionaryValue& dictionary); - - private: - // Clears out all the values in this pattern. - void Clear(); - - std::vector<std::string> issuer_ca_pems_; - IssuerSubjectPattern issuer_; - IssuerSubjectPattern subject_; - std::vector<std::string> enrollment_uri_list_; -}; - -} // namespace chromeos - -#endif // CHROMEOS_NETWORK_CERTIFICATE_PATTERN_H_
diff --git a/chromeos/network/client_cert_resolver.cc b/chromeos/network/client_cert_resolver.cc index 3a37bfd..886db73 100644 --- a/chromeos/network/client_cert_resolver.cc +++ b/chromeos/network/client_cert_resolver.cc
@@ -25,6 +25,7 @@ #include "chromeos/network/managed_network_configuration_handler.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_state.h" +#include "chromeos/network/onc/onc_certificate_pattern.h" #include "chromeos/network/onc/variable_expander.h" #include "components/onc/onc_constants.h" #include "crypto/scoped_nss_types.h" @@ -221,8 +222,19 @@ : cert_config(client_cert_config) {} bool operator()(const CertAndIssuer& cert_and_issuer) { - if (cert_config.client_cert_type == ::onc::client_cert::kPattern) - return MatchByPattern(cert_config.pattern, cert_and_issuer); + if (cert_config.client_cert_type == ::onc::client_cert::kPattern) { + // Allow UTF-8 inside PrintableStrings in client certificates. See + // crbug.com/770323 and crbug.com/788655. + net::X509Certificate::UnsafeCreateOptions options; + options.printable_string_is_utf8 = true; + scoped_refptr<net::X509Certificate> x509_cert = + net::x509_util::CreateX509CertificateFromCERTCertificate( + cert_and_issuer.cert.get(), {}, options); + if (!x509_cert) + return false; + return cert_config.pattern.Matches(*x509_cert, + cert_and_issuer.pem_encoded_issuer); + } if (cert_config.client_cert_type == ::onc::client_cert::kRef) { // This relies on the fact that |CertificateImporterImpl| sets the @@ -234,38 +246,6 @@ return false; } - static bool MatchByPattern(const CertificatePattern& pattern, - const CertAndIssuer& cert_and_issuer) { - if (!pattern.issuer().Empty() || !pattern.subject().Empty()) { - // Allow UTF-8 inside PrintableStrings in client certificates. See - // crbug.com/770323 and crbug.com/788655. - net::X509Certificate::UnsafeCreateOptions options; - options.printable_string_is_utf8 = true; - scoped_refptr<net::X509Certificate> x509_cert = - net::x509_util::CreateX509CertificateFromCERTCertificate( - cert_and_issuer.cert.get(), {}, options); - if (!x509_cert) - return false; - if (!pattern.issuer().Empty() && - !client_cert::CertPrincipalMatches(pattern.issuer(), - x509_cert->issuer())) { - return false; - } - if (!pattern.subject().Empty() && - !client_cert::CertPrincipalMatches(pattern.subject(), - x509_cert->subject())) { - return false; - } - } - - const std::vector<std::string>& issuer_ca_pems = pattern.issuer_ca_pems(); - if (!issuer_ca_pems.empty() && - !base::ContainsValue(issuer_ca_pems, - cert_and_issuer.pem_encoded_issuer)) { - return false; - } - return true; - } const client_cert::ClientCertConfig cert_config; };
diff --git a/chromeos/network/client_cert_util.cc b/chromeos/network/client_cert_util.cc index 07a827522..50079b7b 100644 --- a/chromeos/network/client_cert_util.cc +++ b/chromeos/network/client_cert_util.cc
@@ -10,6 +10,7 @@ #include <list> +#include "base/optional.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/values.h" @@ -34,26 +35,33 @@ // Extracts the type and descriptor (referenced GUID or client cert pattern) of // a ONC-specified client certificate specification for a network // (|dict_with_client_cert|) and stores it in |cert_config|. -void GetClientCertTypeAndDescriptor( - onc::ONCSource onc_source, - const base::DictionaryValue& dict_with_client_cert, - ClientCertConfig* cert_config) { +void GetClientCertTypeAndDescriptor(onc::ONCSource onc_source, + const base::Value& dict_with_client_cert, + ClientCertConfig* cert_config) { cert_config->onc_source = onc_source; - dict_with_client_cert.GetStringWithoutPathExpansion( - ::onc::eap::kIdentity, &cert_config->policy_identity); + const std::string* identity = + dict_with_client_cert.FindStringKey(::onc::eap::kIdentity); + if (identity) + cert_config->policy_identity = *identity; using namespace ::onc::client_cert; - dict_with_client_cert.GetStringWithoutPathExpansion( - kClientCertType, &cert_config->client_cert_type); + const std::string* client_cert_type = + dict_with_client_cert.FindStringKey(kClientCertType); + if (client_cert_type) + cert_config->client_cert_type = *client_cert_type; if (cert_config->client_cert_type == kPattern) { - const base::DictionaryValue* pattern = NULL; - dict_with_client_cert.GetDictionaryWithoutPathExpansion(kClientCertPattern, - &pattern); - if (pattern) { - bool success = cert_config->pattern.ReadFromONCDictionary(*pattern); - DCHECK(success); + const base::Value* pattern_value = dict_with_client_cert.FindKeyOfType( + kClientCertPattern, base::Value::Type::DICTIONARY); + if (pattern_value) { + base::Optional<OncCertificatePattern> pattern = + OncCertificatePattern::ReadFromONCDictionary(*pattern_value); + if (!pattern.has_value()) { + LOG(ERROR) << "ClientCertPattern invalid"; + return; + } + cert_config->pattern = pattern.value(); } } else if (cert_config->client_cert_type == kRef) { const base::Value* client_cert_ref_key = @@ -66,43 +74,6 @@ } // namespace -// Returns true only if any fields set in this pattern match exactly with -// similar fields in the principal. If organization_ or organizational_unit_ -// are set, then at least one of the organizations or units in the principal -// must match. -bool CertPrincipalMatches(const IssuerSubjectPattern& pattern, - const net::CertPrincipal& principal) { - if (!pattern.common_name().empty() && - pattern.common_name() != principal.common_name) { - return false; - } - - if (!pattern.locality().empty() && - pattern.locality() != principal.locality_name) { - return false; - } - - if (!pattern.organization().empty()) { - if (std::find(principal.organization_names.begin(), - principal.organization_names.end(), - pattern.organization()) == - principal.organization_names.end()) { - return false; - } - } - - if (!pattern.organizational_unit().empty()) { - if (std::find(principal.organization_unit_names.begin(), - principal.organization_unit_names.end(), - pattern.organizational_unit()) == - principal.organization_unit_names.end()) { - return false; - } - } - - return true; -} - std::string GetPkcs11AndSlotIdFromEapCertId(const std::string& cert_id, int* slot_id) { *slot_id = -1;
diff --git a/chromeos/network/client_cert_util.h b/chromeos/network/client_cert_util.h index e3a8103..22026eb2 100644 --- a/chromeos/network/client_cert_util.h +++ b/chromeos/network/client_cert_util.h
@@ -10,7 +10,7 @@ #include "base/component_export.h" #include "base/memory/ref_counted.h" -#include "chromeos/network/certificate_pattern.h" +#include "chromeos/network/onc/onc_certificate_pattern.h" #include "components/onc/onc_constants.h" namespace base { @@ -18,12 +18,6 @@ class DictionaryValue; } -namespace net { -struct CertPrincipal; -class X509Certificate; -typedef std::vector<scoped_refptr<X509Certificate>> CertificateList; -} - namespace chromeos { namespace client_cert { @@ -51,7 +45,7 @@ std::string client_cert_type; // If |client_cert_type| equals |kPattern|, this contains the pattern. - CertificatePattern pattern; + OncCertificatePattern pattern; // If |client_cert_type| equals |kRef|, this contains the GUID of the // referenced certificate. @@ -64,13 +58,6 @@ ::onc::ONCSource onc_source; }; -// Returns true only if any fields set in this pattern match exactly with -// similar fields in the principal. If organization_ or organizational_unit_ -// are set, then at least one of the organizations or units in the principal -// must match. -bool CertPrincipalMatches(const IssuerSubjectPattern& pattern, - const net::CertPrincipal& principal); - // Returns the PKCS11 and slot ID of |cert_id|, which is expected to be a // value of the Shill property |kEapCertIdProperty| or |kEapKeyIdProperty|, // either of format "<pkcs11_id>" or "<slot_id>:<pkcs11_id>". @@ -107,7 +94,7 @@ void SetEmptyShillProperties(const ConfigType cert_config_type, base::Value* properties); -// Determines the type of the CertificatePattern configuration, i.e. is it a +// Determines the type of the OncCertificatePattern configuration, i.e. is it a // pattern within an EAP, IPsec or OpenVPN configuration. COMPONENT_EXPORT(CHROMEOS_NETWORK) void OncToClientCertConfig(::onc::ONCSource onc_source,
diff --git a/chromeos/network/network_connection_handler.cc b/chromeos/network/network_connection_handler.cc index 66aee2b..b5889cf6 100644 --- a/chromeos/network/network_connection_handler.cc +++ b/chromeos/network/network_connection_handler.cc
@@ -14,7 +14,6 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/shill_manager_client.h" #include "chromeos/dbus/shill_service_client.h" -#include "chromeos/network/certificate_pattern.h" #include "chromeos/network/client_cert_resolver.h" #include "chromeos/network/client_cert_util.h" #include "chromeos/network/managed_network_configuration_handler.h"
diff --git a/chromeos/network/network_connection_handler_impl.cc b/chromeos/network/network_connection_handler_impl.cc index 6f57705..f64552b 100644 --- a/chromeos/network/network_connection_handler_impl.cc +++ b/chromeos/network/network_connection_handler_impl.cc
@@ -15,7 +15,6 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/shill_manager_client.h" #include "chromeos/dbus/shill_service_client.h" -#include "chromeos/network/certificate_pattern.h" #include "chromeos/network/client_cert_resolver.h" #include "chromeos/network/client_cert_util.h" #include "chromeos/network/device_state.h"
diff --git a/chromeos/network/onc/onc_certificate_pattern.cc b/chromeos/network/onc/onc_certificate_pattern.cc new file mode 100644 index 0000000..cf5ec16 --- /dev/null +++ b/chromeos/network/onc/onc_certificate_pattern.cc
@@ -0,0 +1,131 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/network/onc/onc_certificate_pattern.h" + +#include <stddef.h> + +#include <utility> + +#include "base/logging.h" +#include "base/values.h" +#include "components/onc/onc_constants.h" +#include "net/cert/x509_certificate.h" +#include "net/cert/x509_util_nss.h" + +namespace chromeos { + +namespace { + +bool GetAsListOfStrings(const base::Value& value, + std::vector<std::string>* result) { + if (!value.is_list()) + return false; + + result->clear(); + result->reserve(value.GetList().size()); + for (const auto& entry : value.GetList()) { + if (!entry.is_string()) + return false; + result->push_back(entry.GetString()); + } + + return true; +} + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// OncCertificatePattern + +OncCertificatePattern::OncCertificatePattern() = default; + +OncCertificatePattern::OncCertificatePattern( + const OncCertificatePattern& other) = default; + +OncCertificatePattern::OncCertificatePattern(OncCertificatePattern&& other) = + default; + +OncCertificatePattern::~OncCertificatePattern() = default; + +OncCertificatePattern& OncCertificatePattern::operator=( + const OncCertificatePattern& rhs) = default; +OncCertificatePattern& OncCertificatePattern::operator=( + OncCertificatePattern&& rhs) = default; + +bool OncCertificatePattern::Empty() const { + return pem_encoded_issuer_cas_.empty() && issuer_pattern_.Empty() && + subject_pattern_.Empty(); +} + +bool OncCertificatePattern::Matches( + const net::X509Certificate& certificate, + const std::string& pem_encoded_issuer_ca) const { + if (!issuer_pattern_.Empty() || !subject_pattern_.Empty()) { + if (!issuer_pattern_.Empty() && + !issuer_pattern_.Matches(certificate.issuer())) + return false; + if (!subject_pattern_.Empty() && + !subject_pattern_.Matches(certificate.subject())) + return false; + } + + if (!pem_encoded_issuer_cas_.empty() && + !base::ContainsValue(pem_encoded_issuer_cas_, pem_encoded_issuer_ca)) { + return false; + } + return true; +} + +// static +base::Optional<OncCertificatePattern> +OncCertificatePattern::ReadFromONCDictionary(const base::Value& dict) { + // All of these are optional. + const base::Value* pem_encoded_issuer_cas_value = dict.FindKeyOfType( + onc::client_cert::kIssuerCAPEMs, base::Value::Type::LIST); + std::vector<std::string> pem_encoded_issuer_cas; + if (pem_encoded_issuer_cas_value && + !GetAsListOfStrings(*pem_encoded_issuer_cas_value, + &pem_encoded_issuer_cas)) { + return base::nullopt; + } + + const base::Value* enrollment_uri_list_value = dict.FindKeyOfType( + onc::client_cert::kEnrollmentURI, base::Value::Type::LIST); + std::vector<std::string> enrollment_uri_list; + if (enrollment_uri_list_value && + !GetAsListOfStrings(*enrollment_uri_list_value, &enrollment_uri_list)) { + return base::nullopt; + } + + auto issuer_pattern = + certificate_matching::CertificatePrincipalPattern::ParseFromOptionalDict( + dict.FindKeyOfType(onc::client_cert::kIssuer, + base::Value::Type::DICTIONARY), + onc::client_cert::kCommonName, onc::client_cert::kLocality, + onc::client_cert::kOrganization, + onc::client_cert::kOrganizationalUnit); + auto subject_pattern = + certificate_matching::CertificatePrincipalPattern::ParseFromOptionalDict( + dict.FindKeyOfType(onc::client_cert::kSubject, + base::Value::Type::DICTIONARY), + onc::client_cert::kCommonName, onc::client_cert::kLocality, + onc::client_cert::kOrganization, + onc::client_cert::kOrganizationalUnit); + + return OncCertificatePattern(pem_encoded_issuer_cas, issuer_pattern, + subject_pattern, enrollment_uri_list); +} + +OncCertificatePattern::OncCertificatePattern( + std::vector<std::string> pem_encoded_issuer_cas, + certificate_matching::CertificatePrincipalPattern issuer_pattern, + certificate_matching::CertificatePrincipalPattern subject_pattern, + std::vector<std::string> enrollment_uri_list) + : pem_encoded_issuer_cas_(std::move(pem_encoded_issuer_cas)), + issuer_pattern_(std::move(issuer_pattern)), + subject_pattern_(std::move(subject_pattern)), + enrollment_uri_list_(std::move(enrollment_uri_list)) {} + +} // namespace chromeos
diff --git a/chromeos/network/onc/onc_certificate_pattern.h b/chromeos/network/onc/onc_certificate_pattern.h new file mode 100644 index 0000000..9eaca7e7 --- /dev/null +++ b/chromeos/network/onc/onc_certificate_pattern.h
@@ -0,0 +1,78 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_NETWORK_ONC_ONC_CERTIFICATE_PATTERN_H_ +#define CHROMEOS_NETWORK_ONC_ONC_CERTIFICATE_PATTERN_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/optional.h" +#include "components/certificate_matching/certificate_principal_pattern.h" + +namespace base { +class Value; +} + +namespace net { +class X509Certificate; +} + +namespace chromeos { + +// A class to contain a certificate pattern and find existing matches to the +// pattern in the certificate database. +class COMPONENT_EXPORT(CHROMEOS_NETWORK) OncCertificatePattern { + public: + OncCertificatePattern(); + OncCertificatePattern(const OncCertificatePattern& other); + OncCertificatePattern(OncCertificatePattern&& other); + ~OncCertificatePattern(); + + OncCertificatePattern& operator=(const OncCertificatePattern& rhs); + OncCertificatePattern& operator=(OncCertificatePattern&& rhs); + + // Returns true if this pattern has nothing set (and so would match all + // certs). Ignores enrollment_uri_; + bool Empty() const; + + bool Matches(const net::X509Certificate& certificate, + const std::string& pem_encoded_issuer_ca) const; + + const std::vector<std::string>& pem_encoded_issuer_cas() const { + return pem_encoded_issuer_cas_; + } + const certificate_matching::CertificatePrincipalPattern& issuer_pattern() + const { + return issuer_pattern_; + } + const certificate_matching::CertificatePrincipalPattern& subject_pattern() + const { + return subject_pattern_; + } + const std::vector<std::string>& enrollment_uri_list() const { + return enrollment_uri_list_; + } + + // Reads a |OncCertificatePattern| from an ONC dictionary. + static base::Optional<OncCertificatePattern> ReadFromONCDictionary( + const base::Value& dictionary); + + private: + OncCertificatePattern( + std::vector<std::string> pem_encoded_issuer_cas, + certificate_matching::CertificatePrincipalPattern issuer_pattern, + certificate_matching::CertificatePrincipalPattern subject_pattern, + std::vector<std::string> enrollment_uri_list_); + + std::vector<std::string> pem_encoded_issuer_cas_; + certificate_matching::CertificatePrincipalPattern issuer_pattern_; + certificate_matching::CertificatePrincipalPattern subject_pattern_; + std::vector<std::string> enrollment_uri_list_; +}; + +} // namespace chromeos + +#endif // CHROMEOS_NETWORK_ONC_ONC_CERTIFICATE_PATTERN_H_
diff --git a/chromeos/network/onc/onc_certificate_pattern_unittest.cc b/chromeos/network/onc/onc_certificate_pattern_unittest.cc new file mode 100644 index 0000000..aefd1d0 --- /dev/null +++ b/chromeos/network/onc/onc_certificate_pattern_unittest.cc
@@ -0,0 +1,182 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/network/onc/onc_certificate_pattern.h" + +#include <string> + +#include "base/json/json_reader.h" +#include "base/macros.h" +#include "base/values.h" +#include "net/cert/x509_certificate.h" +#include "net/test/cert_test_util.h" +#include "net/test/test_data_directory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { + +namespace { +constexpr char kFakePemEncodedIssuer[] = "PEM-ENCODED-ISSUER"; + +class OncCertificatePatternTest : public testing::Test { + public: + OncCertificatePatternTest() = default; + ~OncCertificatePatternTest() override = default; + + void SetUp() override { + cert_ = + net::ImportCertFromFile(net::GetTestCertsDirectory(), "client_1.pem"); + ASSERT_TRUE(cert_); + } + + void TearDown() override { cert_.reset(); } + + protected: + scoped_refptr<net::X509Certificate> cert_; + + DISALLOW_COPY_AND_ASSIGN(OncCertificatePatternTest); +}; + +} // namespace + +TEST_F(OncCertificatePatternTest, EmptyPattern) { + OncCertificatePattern pattern; + EXPECT_TRUE(pattern.Empty()); + + EXPECT_TRUE(pattern.Matches(*cert_, kFakePemEncodedIssuer)); +} + +TEST_F(OncCertificatePatternTest, ParsePatternFromOnc) { + const char* pattern_json = R"( + { + "Issuer": { + "CommonName": "Issuer CN", + "Locality": "Issuer L", + "Organization": "Issuer O", + "OrganizationalUnit": "Issuer OU", + }, + "Subject": { + "CommonName": "Subject CN", + "Locality": "Subject L", + "Organization": "Subject O", + "OrganizationalUnit": "Subject OU", + }, + "IssuerCAPEMs": [ "PEM1", "PEM2" ] + })"; + std::string error; + std::unique_ptr<base::Value> pattern_value = + base::JSONReader::ReadAndReturnError( + pattern_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error); + ASSERT_TRUE(pattern_value) << error; + + auto pattern = OncCertificatePattern::ReadFromONCDictionary(*pattern_value); + ASSERT_TRUE(pattern); + EXPECT_FALSE(pattern.value().Empty()); + + EXPECT_EQ("Issuer CN", pattern.value().issuer_pattern().common_name()); + EXPECT_EQ("Issuer L", pattern.value().issuer_pattern().locality()); + EXPECT_EQ("Issuer O", pattern.value().issuer_pattern().organization()); + EXPECT_EQ("Issuer OU", pattern.value().issuer_pattern().organization_unit()); + EXPECT_EQ("Subject CN", pattern.value().subject_pattern().common_name()); + EXPECT_EQ("Subject L", pattern.value().subject_pattern().locality()); + EXPECT_EQ("Subject O", pattern.value().subject_pattern().organization()); + EXPECT_EQ("Subject OU", + pattern.value().subject_pattern().organization_unit()); + EXPECT_THAT(pattern.value().pem_encoded_issuer_cas(), + testing::ElementsAre("PEM1", "PEM2")); +} + +TEST_F(OncCertificatePatternTest, PatternMatchingIssuer) { + // Note: We're only testing matching of "CommonName", assuming that matching + // of the other principal fields is verified by the tests for + // |certificate_matching::CertificatePrincipalPattern|. + const char* pattern_json = R"( + { + "Issuer": { + "CommonName": "B CA" + } + })"; + std::string error; + std::unique_ptr<base::Value> pattern_value = + base::JSONReader::ReadAndReturnError( + pattern_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error); + ASSERT_TRUE(pattern_value) << error; + + { + auto pattern = OncCertificatePattern::ReadFromONCDictionary(*pattern_value); + ASSERT_TRUE(pattern); + EXPECT_FALSE(pattern.value().Empty()); + + EXPECT_TRUE(pattern.value().Matches(*cert_, kFakePemEncodedIssuer)); + } + + { + base::Value* issuer = + pattern_value->FindKeyOfType("Issuer", base::Value::Type::DICTIONARY); + ASSERT_TRUE(issuer); + issuer->SetKey("CommonName", base::Value("SomeOtherCA")); + + auto pattern = OncCertificatePattern::ReadFromONCDictionary(*pattern_value); + ASSERT_TRUE(pattern); + EXPECT_FALSE(pattern.value().Matches(*cert_, kFakePemEncodedIssuer)); + } +} + +TEST_F(OncCertificatePatternTest, PatternMatchingSubject) { + // Note: We're only testing matching of "CommonName", assuming that matching + // of the other principal fields is verified by the tests for + // |certificate_matching::CertificatePrincipalPattern|. + const char* pattern_json = R"( + { + "Subject": { + "CommonName": "Client Cert A" + } + })"; + std::string error; + std::unique_ptr<base::Value> pattern_value = + base::JSONReader::ReadAndReturnError( + pattern_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error); + ASSERT_TRUE(pattern_value) << error; + + { + auto pattern = OncCertificatePattern::ReadFromONCDictionary(*pattern_value); + ASSERT_TRUE(pattern); + EXPECT_FALSE(pattern.value().Empty()); + + EXPECT_TRUE(pattern.value().Matches(*cert_, kFakePemEncodedIssuer)); + } + + { + base::Value* issuer = + pattern_value->FindKeyOfType("Subject", base::Value::Type::DICTIONARY); + ASSERT_TRUE(issuer); + issuer->SetKey("CommonName", base::Value("B CA")); + + auto pattern = OncCertificatePattern::ReadFromONCDictionary(*pattern_value); + ASSERT_TRUE(pattern); + EXPECT_FALSE(pattern.value().Matches(*cert_, kFakePemEncodedIssuer)); + } +} + +TEST_F(OncCertificatePatternTest, PatternMatchingIssuerCAPEM) { + const char* pattern_json = R"( + { + "IssuerCAPEMs": ["PEM-ENCODED-ISSUER"] + })"; + std::string error; + std::unique_ptr<base::Value> pattern_value = + base::JSONReader::ReadAndReturnError( + pattern_json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error); + ASSERT_TRUE(pattern_value) << error; + + auto pattern = OncCertificatePattern::ReadFromONCDictionary(*pattern_value); + ASSERT_TRUE(pattern); + EXPECT_FALSE(pattern.value().Empty()); + + EXPECT_TRUE(pattern.value().Matches(*cert_, kFakePemEncodedIssuer)); + EXPECT_FALSE(pattern.value().Matches(*cert_, "OtherIssuer")); +} + +} // namespace chromeos
diff --git a/chromeos/services/assistant/public/features.cc b/chromeos/services/assistant/public/features.cc index 33228a7d..39ad4d2 100644 --- a/chromeos/services/assistant/public/features.cc +++ b/chromeos/services/assistant/public/features.cc
@@ -11,10 +11,10 @@ namespace features { const base::Feature kAssistantVoiceMatch{"AssistantVoiceMatch", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kAssistantWarmerWelcomeFeature{ - "AssistantWarmerWelcome", base::FEATURE_DISABLED_BY_DEFAULT}; + "AssistantWarmerWelcome", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kAssistantAppSupport{"AssistantAppSupport", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromeos/services/device_sync/BUILD.gn b/chromeos/services/device_sync/BUILD.gn index ce651a8..b86ef30 100644 --- a/chromeos/services/device_sync/BUILD.gn +++ b/chromeos/services/device_sync/BUILD.gn
@@ -36,6 +36,10 @@ "cryptauth_key.h", "cryptauth_key_bundle.cc", "cryptauth_key_bundle.h", + "cryptauth_key_registry.cc", + "cryptauth_key_registry.h", + "cryptauth_key_registry_impl.cc", + "cryptauth_key_registry_impl.h", "device_sync_base.cc", "device_sync_base.h", "device_sync_impl.cc", @@ -149,6 +153,7 @@ "cryptauth_enrollment_manager_impl_unittest.cc", "cryptauth_gcm_manager_impl_unittest.cc", "cryptauth_key_bundle_unittest.cc", + "cryptauth_key_registry_impl_unittest.cc", "cryptauth_key_unittest.cc", "device_sync_service_unittest.cc", "remote_device_loader_unittest.cc",
diff --git a/chromeos/services/device_sync/cryptauth_key_registry.cc b/chromeos/services/device_sync/cryptauth_key_registry.cc new file mode 100644 index 0000000..448cb237 --- /dev/null +++ b/chromeos/services/device_sync/cryptauth_key_registry.cc
@@ -0,0 +1,94 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/services/device_sync/cryptauth_key_registry.h" + +namespace chromeos { + +namespace device_sync { + +CryptAuthKeyRegistry::CryptAuthKeyRegistry() = default; + +CryptAuthKeyRegistry::~CryptAuthKeyRegistry() = default; + +const CryptAuthKeyRegistry::KeyBundleMap& +CryptAuthKeyRegistry::enrolled_key_bundles() const { + return enrolled_key_bundles_; +} + +const CryptAuthKey* CryptAuthKeyRegistry::GetActiveKey( + CryptAuthKeyBundle::Name name) const { + auto it_bundle = enrolled_key_bundles_.find(name); + if (it_bundle == enrolled_key_bundles_.end()) + return nullptr; + + return it_bundle->second.GetActiveKey(); +} + +void CryptAuthKeyRegistry::AddEnrolledKey(CryptAuthKeyBundle::Name name, + const CryptAuthKey& key) { + auto it_bundle = enrolled_key_bundles_.find(name); + + // If a bundle with |name| does not already exist, create one. + if (it_bundle == enrolled_key_bundles_.end()) { + auto it_success_pair = enrolled_key_bundles_.try_emplace(name, name); + DCHECK(it_success_pair.second); + + it_bundle = it_success_pair.first; + } + + it_bundle->second.AddKey(key); + + OnKeyRegistryUpdated(); +} + +void CryptAuthKeyRegistry::SetActiveKey(CryptAuthKeyBundle::Name name, + const std::string& handle) { + auto it_bundle = enrolled_key_bundles_.find(name); + DCHECK(it_bundle != enrolled_key_bundles_.end()); + + it_bundle->second.SetActiveKey(handle); + + OnKeyRegistryUpdated(); +} + +void CryptAuthKeyRegistry::DeactivateKeys(CryptAuthKeyBundle::Name name) { + auto it_bundle = enrolled_key_bundles_.find(name); + DCHECK(it_bundle != enrolled_key_bundles_.end()); + + it_bundle->second.DeactivateKeys(); + + OnKeyRegistryUpdated(); +} + +void CryptAuthKeyRegistry::DeleteKey(CryptAuthKeyBundle::Name name, + const std::string& handle) { + auto it_bundle = enrolled_key_bundles_.find(name); + DCHECK(it_bundle != enrolled_key_bundles_.end()); + + it_bundle->second.DeleteKey(handle); + + OnKeyRegistryUpdated(); +} + +void CryptAuthKeyRegistry::SetKeyDirective( + CryptAuthKeyBundle::Name name, + const cryptauthv2::KeyDirective& key_directive) { + auto it_bundle = enrolled_key_bundles_.find(name); + + // If a bundle with |name| does not already exist, create one. + if (it_bundle == enrolled_key_bundles_.end()) { + auto it_success_pair = enrolled_key_bundles_.try_emplace(name, name); + DCHECK(it_success_pair.second); + it_bundle = it_success_pair.first; + } + + it_bundle->second.set_key_directive(key_directive); + + OnKeyRegistryUpdated(); +} + +} // namespace device_sync + +} // namespace chromeos
diff --git a/chromeos/services/device_sync/cryptauth_key_registry.h b/chromeos/services/device_sync/cryptauth_key_registry.h new file mode 100644 index 0000000..b33ca2e --- /dev/null +++ b/chromeos/services/device_sync/cryptauth_key_registry.h
@@ -0,0 +1,69 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_REGISTRY_H_ +#define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_REGISTRY_H_ + +#include "base/containers/flat_map.h" +#include "base/values.h" +#include "chromeos/services/device_sync/cryptauth_key_bundle.h" +#include "chromeos/services/device_sync/proto/cryptauth_enrollment.pb.h" + +namespace chromeos { + +namespace device_sync { + +// Stores key bundles enrolled with CryptAuth. +class CryptAuthKeyRegistry { + public: + using KeyBundleMap = + base::flat_map<CryptAuthKeyBundle::Name, CryptAuthKeyBundle>; + + virtual ~CryptAuthKeyRegistry(); + + // Returns the underlying map from the key-bundle name to the key bundle. + virtual const KeyBundleMap& enrolled_key_bundles() const; + + // Returns the key with status kActive if one exists in the key bundle with + // name |name|. + virtual const CryptAuthKey* GetActiveKey(CryptAuthKeyBundle::Name name) const; + + // Adds |key| to the key bundle with |name|. If the key being added is active, + // all other keys in the bundle will be deactivated. If the handle of the + // input key matches one in the bundle, the existing key will be overwritten. + virtual void AddEnrolledKey(CryptAuthKeyBundle::Name name, + const CryptAuthKey& key); + + // Activates the key corresponding to |handle| in the key bundle with |name| + // and deactivates the other keys the bundle. + virtual void SetActiveKey(CryptAuthKeyBundle::Name name, + const std::string& handle); + + // Sets all key statuses to kInactive in the key bundle with |name|. + virtual void DeactivateKeys(CryptAuthKeyBundle::Name name); + + // Remove the key corresponding to |handle| from the key bundle with |name|. + virtual void DeleteKey(CryptAuthKeyBundle::Name name, + const std::string& handle); + + // Set the key directive for the key bundle with |name|. + virtual void SetKeyDirective(CryptAuthKeyBundle::Name name, + const cryptauthv2::KeyDirective& key_directive); + + protected: + CryptAuthKeyRegistry(); + + // Invoked when the enrolled key bundle map changes. + virtual void OnKeyRegistryUpdated() = 0; + + KeyBundleMap enrolled_key_bundles_; + + DISALLOW_COPY_AND_ASSIGN(CryptAuthKeyRegistry); +}; + +} // namespace device_sync + +} // namespace chromeos + +#endif // CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_REGISTRY_H_
diff --git a/chromeos/services/device_sync/cryptauth_key_registry_impl.cc b/chromeos/services/device_sync/cryptauth_key_registry_impl.cc new file mode 100644 index 0000000..17c246d5 --- /dev/null +++ b/chromeos/services/device_sync/cryptauth_key_registry_impl.cc
@@ -0,0 +1,84 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/services/device_sync/cryptauth_key_registry_impl.h" + +#include "base/memory/ptr_util.h" +#include "base/no_destructor.h" +#include "chromeos/services/device_sync/pref_names.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" + +namespace chromeos { + +namespace device_sync { + +// static +CryptAuthKeyRegistryImpl::Factory* + CryptAuthKeyRegistryImpl::Factory::test_factory_ = nullptr; + +// static +CryptAuthKeyRegistryImpl::Factory* CryptAuthKeyRegistryImpl::Factory::Get() { + if (test_factory_) + return test_factory_; + + static base::NoDestructor<CryptAuthKeyRegistryImpl::Factory> factory; + return factory.get(); +} + +// static +void CryptAuthKeyRegistryImpl::Factory::SetFactoryForTesting( + Factory* test_factory) { + test_factory_ = test_factory; +} + +std::unique_ptr<CryptAuthKeyRegistry> +CryptAuthKeyRegistryImpl::Factory::BuildInstance(PrefService* pref_service) { + return base::WrapUnique(new CryptAuthKeyRegistryImpl(pref_service)); +} + +// static +void CryptAuthKeyRegistryImpl::RegisterPrefs(PrefRegistrySimple* registry) { + registry->RegisterDictionaryPref(prefs::kCryptAuthKeyRegistry); +} + +CryptAuthKeyRegistryImpl::CryptAuthKeyRegistryImpl(PrefService* pref_service) + : CryptAuthKeyRegistry(), pref_service_(pref_service) { + const base::DictionaryValue* dict = + pref_service_->GetDictionary(prefs::kCryptAuthKeyRegistry); + DCHECK(dict); + + for (const CryptAuthKeyBundle::Name& name : CryptAuthKeyBundle::AllNames()) { + const base::Value* bundle_dict = + dict->FindKey(CryptAuthKeyBundle::KeyBundleNameEnumToString(name)); + if (!bundle_dict) + continue; + + base::Optional<CryptAuthKeyBundle> bundle = + CryptAuthKeyBundle::FromDictionary(*bundle_dict); + DCHECK(bundle); + enrolled_key_bundles_.insert_or_assign(name, *bundle); + } +} + +CryptAuthKeyRegistryImpl::~CryptAuthKeyRegistryImpl() = default; + +void CryptAuthKeyRegistryImpl::OnKeyRegistryUpdated() { + pref_service_->Set(prefs::kCryptAuthKeyRegistry, AsDictionary()); +} + +base::Value CryptAuthKeyRegistryImpl::AsDictionary() const { + base::Value dict(base::Value::Type::DICTIONARY); + for (const auto& name_bundle_pair : enrolled_key_bundles_) { + dict.SetKey( + CryptAuthKeyBundle::KeyBundleNameEnumToString(name_bundle_pair.first), + name_bundle_pair.second.AsDictionary()); + } + + return dict; +} + +} // namespace device_sync + +} // namespace chromeos
diff --git a/chromeos/services/device_sync/cryptauth_key_registry_impl.h b/chromeos/services/device_sync/cryptauth_key_registry_impl.h new file mode 100644 index 0000000..32779ed31 --- /dev/null +++ b/chromeos/services/device_sync/cryptauth_key_registry_impl.h
@@ -0,0 +1,63 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_REGISTRY_IMPL_H_ +#define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_REGISTRY_IMPL_H_ + +#include "chromeos/services/device_sync/cryptauth_key_registry.h" + +#include "base/macros.h" + +class PrefRegistrySimple; +class PrefService; + +namespace chromeos { + +namespace device_sync { + +// Implementation of CryptAuthKeyRegistry that persists the key-bundle map as a +// preference. The in-memory key bundle map is populated with these persisted +// enrolled key bundles on construction, and the preference is updated whenever +// the in-memory key bundle map changes. +class CryptAuthKeyRegistryImpl : public CryptAuthKeyRegistry { + public: + class Factory { + public: + static Factory* Get(); + static void SetFactoryForTesting(Factory* test_factory); + virtual std::unique_ptr<CryptAuthKeyRegistry> BuildInstance( + PrefService* pref_service); + + private: + static Factory* test_factory_; + }; + + // Registers the prefs used by this class to the given |registry|. + static void RegisterPrefs(PrefRegistrySimple* registry); + + ~CryptAuthKeyRegistryImpl() override; + + private: + // Populates the in-memory key bundle map with the enrolled key bundles + // persisted in a pref. + CryptAuthKeyRegistryImpl(PrefService* pref_service); + + // CryptAuthKeyRegistry: + void OnKeyRegistryUpdated() override; + + // Converts the registry to a dictionary value in a form suitable for a pref. + base::Value AsDictionary() const; + + // Contains preferences that outlive the lifetime of this object and across + // process restarts. Not owned and must outlive this instance. + PrefService* pref_service_; + + DISALLOW_COPY_AND_ASSIGN(CryptAuthKeyRegistryImpl); +}; + +} // namespace device_sync + +} // namespace chromeos + +#endif // CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_REGISTRY_IMPL_H_
diff --git a/chromeos/services/device_sync/cryptauth_key_registry_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_key_registry_impl_unittest.cc new file mode 100644 index 0000000..730e554 --- /dev/null +++ b/chromeos/services/device_sync/cryptauth_key_registry_impl_unittest.cc
@@ -0,0 +1,266 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/services/device_sync/cryptauth_key_registry_impl.h" + +#include "base/stl_util.h" +#include "chromeos/services/device_sync/pref_names.h" +#include "components/prefs/testing_pref_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { + +namespace device_sync { + +class CryptAuthKeyRegistryImplTest : public testing::Test { + protected: + CryptAuthKeyRegistryImplTest() = default; + + ~CryptAuthKeyRegistryImplTest() override = default; + + void SetUp() override { + CryptAuthKeyRegistryImpl::RegisterPrefs(pref_service_.registry()); + key_registry_ = + CryptAuthKeyRegistryImpl::Factory::Get()->BuildInstance(&pref_service_); + } + + // Verify that changing the in-memory key bundle map updates the pref. + void VerifyPrefValue(const base::Value& expected_dict) { + const base::DictionaryValue* dict = + pref_service_.GetDictionary(prefs::kCryptAuthKeyRegistry); + ASSERT_TRUE(dict); + EXPECT_EQ(*dict, expected_dict); + } + + PrefService* pref_service() { return &pref_service_; } + + CryptAuthKeyRegistry* key_registry() { return key_registry_.get(); } + + private: + TestingPrefServiceSimple pref_service_; + + std::unique_ptr<CryptAuthKeyRegistry> key_registry_; + + DISALLOW_COPY_AND_ASSIGN(CryptAuthKeyRegistryImplTest); +}; + +TEST_F(CryptAuthKeyRegistryImplTest, GetActiveKey_NoActiveKey) { + CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kInactive, + cryptauthv2::KeyType::RAW256, "sym-handle"); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + sym_key); + + EXPECT_FALSE( + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair)); +} + +TEST_F(CryptAuthKeyRegistryImplTest, GetActiveKey) { + CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kInactive, + cryptauthv2::KeyType::RAW256, "sym-handle"); + CryptAuthKey asym_key("public-key", "private-key", + CryptAuthKey::Status::kActive, + cryptauthv2::KeyType::P256, "asym-handle"); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + sym_key); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + asym_key); + + const CryptAuthKey* key = + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair); + ASSERT_TRUE(key); + EXPECT_EQ(*key, asym_key); +} + +TEST_F(CryptAuthKeyRegistryImplTest, AddKey) { + CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kActive, + cryptauthv2::KeyType::RAW256, "sym-handle"); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + sym_key); + const auto& it = key_registry()->enrolled_key_bundles().find( + CryptAuthKeyBundle::Name::kUserKeyPair); + ASSERT_TRUE(it != key_registry()->enrolled_key_bundles().end()); + + const CryptAuthKey* active_key = + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair); + ASSERT_TRUE(active_key); + EXPECT_EQ(*active_key, sym_key); + + CryptAuthKeyBundle expected_bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + expected_bundle.AddKey(sym_key); + EXPECT_EQ(expected_bundle, it->second); + + base::Value expected_dict(base::Value::Type::DICTIONARY); + expected_dict.SetKey( + CryptAuthKeyBundle::KeyBundleNameEnumToString(expected_bundle.name()), + expected_bundle.AsDictionary()); + VerifyPrefValue(expected_dict); + + // Add another key to same bundle + CryptAuthKey asym_key("public-key", "private-key", + CryptAuthKey::Status::kActive, + cryptauthv2::KeyType::P256, "asym-handle"); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + asym_key); + + expected_bundle.AddKey(asym_key); + EXPECT_EQ(expected_bundle, it->second); + + active_key = + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair); + ASSERT_TRUE(active_key); + EXPECT_EQ(*active_key, asym_key); + + expected_dict.SetKey( + CryptAuthKeyBundle::KeyBundleNameEnumToString(expected_bundle.name()), + expected_bundle.AsDictionary()); + VerifyPrefValue(expected_dict); +} + +TEST_F(CryptAuthKeyRegistryImplTest, SetActiveKey) { + CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kInactive, + cryptauthv2::KeyType::RAW256, "sym-handle"); + CryptAuthKey asym_key("public-key", "private-key", + CryptAuthKey::Status::kActive, + cryptauthv2::KeyType::P256, "asym-handle"); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + sym_key); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + asym_key); + + key_registry()->SetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair, + "sym-handle"); + + const CryptAuthKey* key = + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair); + EXPECT_TRUE(key); + + sym_key.set_status(CryptAuthKey::Status::kActive); + EXPECT_EQ(*key, sym_key); + + CryptAuthKeyBundle expected_bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + expected_bundle.AddKey(sym_key); + asym_key.set_status(CryptAuthKey::Status::kInactive); + expected_bundle.AddKey(asym_key); + base::Value expected_dict(base::Value::Type::DICTIONARY); + expected_dict.SetKey( + CryptAuthKeyBundle::KeyBundleNameEnumToString(expected_bundle.name()), + expected_bundle.AsDictionary()); + VerifyPrefValue(expected_dict); +} + +TEST_F(CryptAuthKeyRegistryImplTest, DeactivateKeys) { + CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kInactive, + cryptauthv2::KeyType::RAW256, "sym-handle"); + CryptAuthKey asym_key("public-key", "private-key", + CryptAuthKey::Status::kActive, + cryptauthv2::KeyType::P256, "asym-handle"); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + sym_key); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + asym_key); + + key_registry()->DeactivateKeys(CryptAuthKeyBundle::Name::kUserKeyPair); + + EXPECT_FALSE( + key_registry()->GetActiveKey(CryptAuthKeyBundle::Name::kUserKeyPair)); + + CryptAuthKeyBundle expected_bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + expected_bundle.AddKey(sym_key); + asym_key.set_status(CryptAuthKey::Status::kInactive); + expected_bundle.AddKey(asym_key); + base::Value expected_dict(base::Value::Type::DICTIONARY); + expected_dict.SetKey( + CryptAuthKeyBundle::KeyBundleNameEnumToString(expected_bundle.name()), + expected_bundle.AsDictionary()); + VerifyPrefValue(expected_dict); +} + +TEST_F(CryptAuthKeyRegistryImplTest, DeleteKey) { + CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kInactive, + cryptauthv2::KeyType::RAW256, "sym-handle"); + CryptAuthKey asym_key("public-key", "private-key", + CryptAuthKey::Status::kActive, + cryptauthv2::KeyType::P256, "asym-handle"); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + sym_key); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + asym_key); + + key_registry()->DeleteKey(CryptAuthKeyBundle::Name::kUserKeyPair, + "sym-handle"); + + const auto& it = key_registry()->enrolled_key_bundles().find( + CryptAuthKeyBundle::Name::kUserKeyPair); + ASSERT_TRUE(it != key_registry()->enrolled_key_bundles().end()); + + EXPECT_FALSE(base::ContainsKey(it->second.handle_to_key_map(), "sym-handle")); + EXPECT_TRUE(base::ContainsKey(it->second.handle_to_key_map(), "asym-handle")); + + CryptAuthKeyBundle expected_bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + expected_bundle.AddKey(asym_key); + base::Value expected_dict(base::Value::Type::DICTIONARY); + expected_dict.SetKey( + CryptAuthKeyBundle::KeyBundleNameEnumToString(expected_bundle.name()), + expected_bundle.AsDictionary()); + VerifyPrefValue(expected_dict); +} + +TEST_F(CryptAuthKeyRegistryImplTest, SetKeyDirective) { + CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kInactive, + cryptauthv2::KeyType::RAW256, "sym-handle"); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + sym_key); + + cryptauthv2::KeyDirective key_directive; + key_directive.set_enroll_time_millis(1000); + key_registry()->SetKeyDirective(CryptAuthKeyBundle::Name::kUserKeyPair, + key_directive); + + const auto& it = key_registry()->enrolled_key_bundles().find( + CryptAuthKeyBundle::Name::kUserKeyPair); + ASSERT_TRUE(it != key_registry()->enrolled_key_bundles().end()); + + EXPECT_TRUE(it->second.key_directive()); + EXPECT_EQ(it->second.key_directive()->SerializeAsString(), + key_directive.SerializeAsString()); + + CryptAuthKeyBundle expected_bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + expected_bundle.AddKey(sym_key); + expected_bundle.set_key_directive(key_directive); + base::Value expected_dict(base::Value::Type::DICTIONARY); + expected_dict.SetKey( + CryptAuthKeyBundle::KeyBundleNameEnumToString(expected_bundle.name()), + expected_bundle.AsDictionary()); + VerifyPrefValue(expected_dict); +} + +TEST_F(CryptAuthKeyRegistryImplTest, ConstructorPopulatesBundlesUsingPref) { + CryptAuthKey sym_key("symmetric-key", CryptAuthKey::Status::kInactive, + cryptauthv2::KeyType::RAW256, "sym-handle"); + key_registry()->AddEnrolledKey(CryptAuthKeyBundle::Name::kUserKeyPair, + sym_key); + cryptauthv2::KeyDirective key_directive; + key_directive.set_enroll_time_millis(1000); + key_registry()->SetKeyDirective(CryptAuthKeyBundle::Name::kUserKeyPair, + key_directive); + + // A new registry using the same pref service that was just written. + std::unique_ptr<CryptAuthKeyRegistry> new_registry = + CryptAuthKeyRegistryImpl::Factory::Get()->BuildInstance(pref_service()); + + EXPECT_TRUE(new_registry->enrolled_key_bundles().size() == 1); + + const auto& it = new_registry->enrolled_key_bundles().find( + CryptAuthKeyBundle::Name::kUserKeyPair); + ASSERT_TRUE(it != new_registry->enrolled_key_bundles().end()); + + CryptAuthKeyBundle expected_bundle(CryptAuthKeyBundle::Name::kUserKeyPair); + expected_bundle.AddKey(sym_key); + expected_bundle.set_key_directive(key_directive); + EXPECT_EQ(it->second, expected_bundle); +} + +} // namespace device_sync + +} // namespace chromeos
diff --git a/chromeos/services/device_sync/pref_names.cc b/chromeos/services/device_sync/pref_names.cc index f8d852431..a3ab1ed 100644 --- a/chromeos/services/device_sync/pref_names.cc +++ b/chromeos/services/device_sync/pref_names.cc
@@ -55,6 +55,10 @@ // The GCM registration id used for receiving push messages from CryptAuth. const char kCryptAuthGCMRegistrationId[] = "cryptauth.gcm_registration_id"; +// The dictionary of key bundles enrolled with CryptAuth, used to populate and +// persist the CryptAuthKeyRegistry. +const char kCryptAuthKeyRegistry[] = "cryptauth.key_registry"; + } // namespace prefs } // namespace device_sync
diff --git a/chromeos/services/device_sync/pref_names.h b/chromeos/services/device_sync/pref_names.h index d6b30a9..809e65c 100644 --- a/chromeos/services/device_sync/pref_names.h +++ b/chromeos/services/device_sync/pref_names.h
@@ -21,6 +21,7 @@ extern const char kCryptAuthEnrollmentUserPublicKey[]; extern const char kCryptAuthEnrollmentUserPrivateKey[]; extern const char kCryptAuthGCMRegistrationId[]; +extern const char kCryptAuthKeyRegistry[]; } // namespace prefs
diff --git a/components/BUILD.gn b/components/BUILD.gn index 33ba09a..9e87ff4 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -85,6 +85,7 @@ "//components/bubble:unit_tests", "//components/captive_portal:unit_tests", "//components/cbor:unit_tests", + "//components/certificate_matching:unit_tests", "//components/client_update_protocol:unit_tests", "//components/cloud_devices/common:unit_tests", "//components/component_updater:unit_tests", @@ -615,7 +616,7 @@ data = [ "$root_out_dir/components_tests_resources.pak", "$root_out_dir/ui_test.pak", - "//components/subresource_filter/core/common/perftests/data", + "//components/subresource_filter/core/common/perftests/data/", ] if (is_android) {
diff --git a/components/autofill/content/common/autofill_agent.mojom b/components/autofill/content/common/autofill_agent.mojom index 04854cd7..6138f4b 100644 --- a/components/autofill/content/common/autofill_agent.mojom +++ b/components/autofill/content/common/autofill_agent.mojom
@@ -107,9 +107,9 @@ GeneratedPasswordAccepted(mojo_base.mojom.String16 generated_password); // Tells the renderer to find a focused element, and if it is a password field - // eligible for generation then to trigger generation by responding to the - // browser with the message |ShowPasswordGenerationPopup|. - UserTriggeredGeneratePassword(); + // eligible for generation then to trigger generation by returning + // non-empty PasswordGenerationUIData. + UserTriggeredGeneratePassword() => (PasswordGenerationUIData? data); // Tells the renderer that this password form is not blacklisted. A form can // be blacklisted if a user chooses "never save passwords for this site".
diff --git a/components/autofill/content/common/autofill_driver.mojom b/components/autofill/content/common/autofill_driver.mojom index 239575b3..1235cd0b 100644 --- a/components/autofill/content/common/autofill_driver.mojom +++ b/components/autofill/content/common/autofill_driver.mojom
@@ -79,7 +79,7 @@ // There is one instance of this interface per web contents in the browser // process that handles all the frames. The motivation was to make the interface -// associated with PasswordManagerClient. +// associated with PasswordGenerationDriver. interface PasswordManagerDriver { // Notification that password forms have been seen that are candidates for // filling/submitting by the password manager. @@ -141,7 +141,7 @@ // There is one instance of this interface per web contents in the browser // process. -interface PasswordManagerClient { +interface PasswordGenerationDriver { // Instructs the browser that generation is available for this particular // form. This is used for UMA stats. GenerationAvailableForForm(PasswordForm password_form); @@ -151,14 +151,6 @@ AutomaticGenerationStatusChanged( bool available, PasswordGenerationUIData? password_generation_ui_data); - // Instructs the browser to show the password generation popup for manual - // generation and provides the data necessary to display it. - // TODO(crbug.com/845458): Replace this with a method called from the browser - // when user triggers generation manually which returns a boolean signaling - // whether the state for generation could be saved or not. - ShowManualPasswordGenerationPopup( - PasswordGenerationUIData password_generation_ui_data); - // Instructs the browser to show the popup for editing a generated password. // The location should be specified in the renderers coordinate system. Form // is the form associated with the password field.
diff --git a/components/autofill/content/common/autofill_types_struct_traits.cc b/components/autofill/content/common/autofill_types_struct_traits.cc index 0a2bb00e..8ebff42 100644 --- a/components/autofill/content/common/autofill_types_struct_traits.cc +++ b/components/autofill/content/common/autofill_types_struct_traits.cc
@@ -641,7 +641,7 @@ out->is_enabled = data.is_enabled(); out->is_readonly = data.is_readonly(); - if (!data.ReadValue(&out->typed_value)) + if (!data.ReadTypedValue(&out->typed_value)) return false; if (!data.ReadOptionValues(&out->option_values))
diff --git a/components/autofill/content/common/autofill_types_struct_traits_unittest.cc b/components/autofill/content/common/autofill_types_struct_traits_unittest.cc index 35aa1af..2d2534c 100644 --- a/components/autofill/content/common/autofill_types_struct_traits_unittest.cc +++ b/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
@@ -278,6 +278,8 @@ const base::Closure& closure, const FormFieldData& passed) { EXPECT_EQ(expected, passed); + EXPECT_EQ(expected.value, passed.value); + EXPECT_EQ(expected.typed_value, passed.typed_value); closure.Run(); } @@ -368,6 +370,7 @@ input.role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION; input.text_direction = base::i18n::RIGHT_TO_LEFT; input.properties_mask = FieldPropertiesFlags::HAD_FOCUS; + input.typed_value = base::ASCIIToUTF16("TestTypedValue"); base::RunLoop loop; mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy();
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc index bc09293..c446763f 100644 --- a/components/autofill/content/renderer/form_autofill_util.cc +++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1415,11 +1415,6 @@ FormData* form, FormFieldData* field) { form->origin = GetCanonicalOriginForDocument(document); - if (!document.Body().IsNull()) { - SCOPED_UMA_HISTOGRAM_TIMER( - "PasswordManager.ButtonTitlePerformance.NoFormTag"); - form->button_titles = InferButtonTitlesForForm(document.Body()); - } if (document.GetFrame() && document.GetFrame()->Top()) { form->main_frame_origin = document.GetFrame()->Top()->GetSecurityOrigin(); } else { @@ -1796,11 +1791,6 @@ form->unique_renderer_id = form_element.UniqueRendererFormId(); form->origin = GetCanonicalOriginForDocument(frame->GetDocument()); form->action = GetCanonicalActionForForm(form_element); - { - SCOPED_UMA_HISTOGRAM_TIMER( - "PasswordManager.ButtonTitlePerformance.HasFormTag"); - form->button_titles = InferButtonTitlesForForm(form_element); - } if (frame->Top()) { form->main_frame_origin = frame->Top()->GetSecurityOrigin(); } else {
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc index 2a8faea..98d7320 100644 --- a/components/autofill/content/renderer/password_generation_agent.cc +++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -443,7 +443,7 @@ std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave()); if (presaved_form) { DCHECK_NE(base::string16(), presaved_form->password_value); - GetPasswordManagerClient()->PresaveGeneratedPassword(*presaved_form); + GetPasswordGenerationDriver()->PresaveGeneratedPassword(*presaved_form); } // Call UpdateStateForTextChange after the corresponding PasswordFormManager @@ -492,7 +492,8 @@ generation_enabled_fields_[form.new_password_renderer_id] = form; } -void PasswordGenerationAgent::UserTriggeredGeneratePassword() { +void PasswordGenerationAgent::UserTriggeredGeneratePassword( + UserTriggeredGeneratePasswordCallback callback) { if (SetUpUserTriggeredGeneration()) { LogMessage(Logger::STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP); autofill::password_generation::PasswordGenerationUIData @@ -505,11 +506,10 @@ GetTextDirectionForElement( current_generation_item_->generation_element_), current_generation_item_->form_); - // TODO(crbug.com/845458): remove it. The renderer should never invoke the - // prompt directly. - GetPasswordManagerClient()->ShowManualPasswordGenerationPopup( - password_generation_ui_data); + std::move(callback).Run(std::move(password_generation_ui_data)); current_generation_item_->generation_popup_shown_ = true; + } else { + std::move(callback).Run(base::nullopt); } } @@ -581,7 +581,7 @@ current_generation_item_.reset(new GenerationItemInfo( *automatic_generation_form_data_, automatic_generation_element_)); } - GetPasswordManagerClient()->GenerationAvailableForForm( + GetPasswordGenerationDriver()->GenerationAvailableForForm( automatic_generation_form_data_->form); return; } @@ -710,7 +710,7 @@ std::unique_ptr<PasswordForm> presaved_form( CreatePasswordFormToPresave()); if (presaved_form) - GetPasswordManagerClient()->PresaveGeneratedPassword(*presaved_form); + GetPasswordGenerationDriver()->PresaveGeneratedPassword(*presaved_form); } return false; } @@ -748,7 +748,7 @@ std::unique_ptr<PasswordForm> presaved_form( CreatePasswordFormToPresave()); if (presaved_form) { - GetPasswordManagerClient()->PresaveGeneratedPassword(*presaved_form); + GetPasswordGenerationDriver()->PresaveGeneratedPassword(*presaved_form); } } } @@ -781,19 +781,19 @@ current_generation_item_->generation_element_), current_generation_item_->form_); current_generation_item_->generation_popup_shown_ = true; - GetPasswordManagerClient()->AutomaticGenerationStatusChanged( + GetPasswordGenerationDriver()->AutomaticGenerationStatusChanged( true, password_generation_ui_data); } else { // Hide the generation popup. - GetPasswordManagerClient()->AutomaticGenerationStatusChanged(false, - base::nullopt); + GetPasswordGenerationDriver()->AutomaticGenerationStatusChanged( + false, base::nullopt); } } void PasswordGenerationAgent::ShowEditingPopup() { if (!render_frame()) return; - GetPasswordManagerClient()->ShowPasswordEditingPopup( + GetPasswordGenerationDriver()->ShowPasswordEditingPopup( render_frame()->GetRenderView()->ElementBoundsInWindow( current_generation_item_->generation_element_), *CreatePasswordFormToPresave()); @@ -801,7 +801,7 @@ } void PasswordGenerationAgent::GenerationRejectedByTyping() { - GetPasswordManagerClient()->PasswordGenerationRejectedByTyping(); + GetPasswordGenerationDriver()->PasswordGenerationRejectedByTyping(); } void PasswordGenerationAgent::PasswordNoLongerGenerated() { @@ -824,7 +824,7 @@ } std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave()); if (presaved_form) - GetPasswordManagerClient()->PasswordNoLongerGenerated(*presaved_form); + GetPasswordGenerationDriver()->PasswordNoLongerGenerated(*presaved_form); } void PasswordGenerationAgent::MaybeCreateCurrentGenerationItem( @@ -869,14 +869,14 @@ return password_agent_->GetPasswordManagerDriver(); } -const mojom::PasswordManagerClientAssociatedPtr& -PasswordGenerationAgent::GetPasswordManagerClient() { - if (!password_manager_client_) { +const mojom::PasswordGenerationDriverAssociatedPtr& +PasswordGenerationAgent::GetPasswordGenerationDriver() { + if (!password_generation_client_) { render_frame()->GetRemoteAssociatedInterfaces()->GetInterface( - &password_manager_client_); + &password_generation_client_); } - return password_manager_client_; + return password_generation_client_; } void PasswordGenerationAgent::LogMessage(Logger::StringID message_id) {
diff --git a/components/autofill/content/renderer/password_generation_agent.h b/components/autofill/content/renderer/password_generation_agent.h index 0f5a17ddd..d36ad4a7 100644 --- a/components/autofill/content/renderer/password_generation_agent.h +++ b/components/autofill/content/renderer/password_generation_agent.h
@@ -57,9 +57,10 @@ const std::vector<PasswordFormGenerationData>& forms) override; void FoundFormEligibleForGeneration( const NewPasswordFormGenerationData& form) override; - // Sets |generation_element_| to the focused password field and shows a - // generation popup at this field. - void UserTriggeredGeneratePassword() override; + // Sets |generation_element_| to the focused password field and responds back + // if the generation was triggered successfully. + void UserTriggeredGeneratePassword( + UserTriggeredGeneratePasswordCallback callback) override; // Returns true if the field being changed is one where a generated password // is being offered. Updates the state of the popup if necessary. @@ -88,7 +89,9 @@ #if defined(UNIT_TEST) // This method requests the autofill::mojom::PasswordManagerClient which binds // requests the binding if it wasn't bound yet. - void RequestPasswordManagerClientForTesting() { GetPasswordManagerClient(); } + void RequestPasswordManagerClientForTesting() { + GetPasswordGenerationDriver(); + } #endif protected: @@ -117,7 +120,8 @@ const mojom::PasswordManagerDriverAssociatedPtr& GetPasswordManagerDriver(); - const mojom::PasswordManagerClientAssociatedPtr& GetPasswordManagerClient(); + const mojom::PasswordGenerationDriverAssociatedPtr& + GetPasswordGenerationDriver(); // Helper function that will try and populate |password_elements_| and // |possible_account_creation_form_|. @@ -222,7 +226,7 @@ // in password fields are updated. PasswordAutofillAgent* password_agent_; - mojom::PasswordManagerClientAssociatedPtr password_manager_client_; + mojom::PasswordGenerationDriverAssociatedPtr password_generation_client_; mojo::AssociatedBinding<mojom::PasswordGenerationAgent> binding_;
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn index 9520b25..46afe629 100644 --- a/components/autofill/core/browser/BUILD.gn +++ b/components/autofill/core/browser/BUILD.gn
@@ -65,6 +65,8 @@ "autofill_metadata.h", "autofill_metrics.cc", "autofill_metrics.h", + "autofill_observer.cc", + "autofill_observer.h", "autofill_popup_delegate.h", "autofill_profile.cc", "autofill_profile.h", @@ -80,6 +82,8 @@ "autofill_provider.h", "autofill_scanner.cc", "autofill_scanner.h", + "autofill_subject.cc", + "autofill_subject.h", "autofill_type.cc", "autofill_type.h", "autofill_wallet_data_type_controller.cc", @@ -127,6 +131,8 @@ "legal_message_line.h", "local_card_migration_manager.cc", "local_card_migration_manager.h", + "local_card_migration_strike_database.cc", + "local_card_migration_strike_database.h", "name_field.cc", "name_field.h", "password_requirements_spec_fetcher.h", @@ -346,6 +352,8 @@ "suggestion_test_helpers.h", "test_address_normalizer.cc", "test_address_normalizer.h", + "test_autofill_async_observer.cc", + "test_autofill_async_observer.h", "test_autofill_client.cc", "test_autofill_client.h", "test_autofill_clock.cc", @@ -375,6 +383,8 @@ "test_legacy_strike_database.h", "test_local_card_migration_manager.cc", "test_local_card_migration_manager.h", + "test_local_card_migration_strike_database.cc", + "test_local_card_migration_strike_database.h", "test_personal_data_manager.cc", "test_personal_data_manager.h", "test_region_data_loader.cc", @@ -492,6 +502,7 @@ "autofill_profile_unittest.cc", "autofill_profile_validation_util_unittest.cc", "autofill_profile_validator_unittest.cc", + "autofill_subject_unittest.cc", "autofill_type_unittest.cc", "autofill_wallet_data_type_controller_unittest.cc", "contact_info_unittest.cc", @@ -509,6 +520,7 @@ "legacy_strike_database_unittest.cc", "legal_message_line_unittest.cc", "local_card_migration_manager_unittest.cc", + "local_card_migration_strike_database_unittest.cc", "name_field_unittest.cc", "password_generator_fips181_unittest.cc", "password_generator_unittest.cc",
diff --git a/components/autofill/core/browser/autocomplete_history_manager.cc b/components/autofill/core/browser/autocomplete_history_manager.cc index a5cacb6..d15eb19 100644 --- a/components/autofill/core/browser/autocomplete_history_manager.cc +++ b/components/autofill/core/browser/autocomplete_history_manager.cc
@@ -24,6 +24,8 @@ #include "components/prefs/pref_service.h" #include "components/version_info/version_info.h" +using NotificationType = autofill::AutofillObserver::NotificationType; + namespace autofill { namespace { @@ -173,8 +175,10 @@ void AutocompleteHistoryManager::OnWillSubmitForm( const FormData& form, bool is_autocomplete_enabled) { - if (!is_autocomplete_enabled || is_off_the_record_) + if (!is_autocomplete_enabled || is_off_the_record_) { + Notify(NotificationType::AutocompleteFormSkipped); return; + } // We put the following restriction on stored FormFields: // - non-empty name @@ -197,8 +201,11 @@ } } - if (!values.empty() && profile_database_.get()) + if (!values.empty() && profile_database_.get()) { profile_database_->AddFormFields(values); + + Notify(NotificationType::AutocompleteFormSubmitted); + } } void AutocompleteHistoryManager::OnRemoveAutocompleteEntry( @@ -334,6 +341,8 @@ // Cleanup was successful, update the latest run milestone. pref_service_->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, CHROME_VERSION_MAJOR); + + Notify(NotificationType::AutocompleteCleanupDone); } void AutocompleteHistoryManager::CancelAllPendingQueries() {
diff --git a/components/autofill/core/browser/autocomplete_history_manager.h b/components/autofill/core/browser/autocomplete_history_manager.h index 7de99bd..3f5536d 100644 --- a/components/autofill/core/browser/autocomplete_history_manager.h +++ b/components/autofill/core/browser/autocomplete_history_manager.h
@@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "components/autofill/core/browser/autofill_subject.h" #include "components/autofill/core/browser/suggestion.h" #include "components/autofill/core/browser/webdata/autofill_entry.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" @@ -26,7 +27,8 @@ // from the renderers and the storing and retrieving of form data // through WebDataServiceBase. class AutocompleteHistoryManager : public KeyedService, - public WebDataServiceConsumer { + public WebDataServiceConsumer, + public AutofillSubject { public: // Interface to be implemented by classes that want to fetch autocomplete // suggestions.
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h index 5b3f98d..cb53a600 100644 --- a/components/autofill/core/browser/autofill_client.h +++ b/components/autofill/core/browser/autofill_client.h
@@ -219,11 +219,12 @@ virtual void ShowLocalCardMigrationDialog( base::OnceClosure show_migration_dialog_closure) = 0; - // Shows a dialog with the given |legal_message|. Runs + // Shows a dialog with the given |legal_message| and the |user_email|. Runs // |start_migrating_cards_callback| if the user would like the selected cards // in the |migratable_credit_cards| to be uploaded to cloud. virtual void ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) = 0;
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc index 517b204..466e4f1f 100644 --- a/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -3007,8 +3007,7 @@ histogram_tester.ExpectUniqueSample("Autofill.AddressSuggestionsCount", 2, 1); } else { - EXPECT_EQ(nullptr, base::StatisticsRecorder::FindHistogram( - "Autofill.AddressSuggestionsCount")); + histogram_tester.ExpectTotalCount("Autofill.AddressSuggestionsCount", 0); } } }
diff --git a/components/autofill/core/browser/autofill_observer.cc b/components/autofill/core/browser/autofill_observer.cc new file mode 100644 index 0000000..43030e4 --- /dev/null +++ b/components/autofill/core/browser/autofill_observer.cc
@@ -0,0 +1,16 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/autofill_observer.h" + +#include "base/run_loop.h" + +namespace autofill { + +AutofillObserver::AutofillObserver(NotificationType notification_type, + bool detach_on_notify) + : notification_type_(notification_type), + detach_on_notify_(detach_on_notify) {} + +} // namespace autofill
diff --git a/components/autofill/core/browser/autofill_observer.h b/components/autofill/core/browser/autofill_observer.h new file mode 100644 index 0000000..ea32c66 --- /dev/null +++ b/components/autofill/core/browser/autofill_observer.h
@@ -0,0 +1,38 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_OBSERVER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_OBSERVER_H_ + +#include "base/observer_list_types.h" + +namespace autofill { + +class AutofillObserver : public base::CheckedObserver { + public: + enum NotificationType { + AutocompleteFormSubmitted, + AutocompleteFormSkipped, + AutocompleteCleanupDone + }; + + // |notification_type| is the notification type that this observer observes. + // |detach_on_notify| will let the AutofillSubject know that this + // observer only wants to watch for the first notification of that type. + AutofillObserver(NotificationType notification_type, bool detach_on_notify); + + // Invoked by the watched AutofillSubject. + virtual void OnNotify() = 0; + + NotificationType notification_type() { return notification_type_; } + bool detach_on_notify() { return detach_on_notify_; } + + private: + NotificationType notification_type_; + bool detach_on_notify_; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_OBSERVER_H_
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc index 4d1e041..750b4bb 100644 --- a/components/autofill/core/browser/autofill_profile.cc +++ b/components/autofill/core/browser/autofill_profile.cc
@@ -457,6 +457,13 @@ UseDateEqualsInSeconds(&profile) && EqualsSansGuid(profile); } +bool AutofillProfile::EqualsForUpdatePurposes( + const AutofillProfile& profile) const { + return use_count() == profile.use_count() && + UseDateEqualsInSeconds(&profile) && + language_code() == profile.language_code() && Compare(profile) == 0; +} + bool AutofillProfile::EqualsForClientValidationPurpose( const AutofillProfile& profile) const { for (ServerFieldType type : kSupportedTypesByClientForValidation) {
diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h index 1a4b56c..3d051f90 100644 --- a/components/autofill/core/browser/autofill_profile.h +++ b/components/autofill/core/browser/autofill_profile.h
@@ -126,6 +126,8 @@ // differences in usage stats. bool EqualsForSyncPurposes(const AutofillProfile& profile) const; + bool EqualsForUpdatePurposes(const AutofillProfile& profile) const; + // Compares the values of kSupportedTypesByClientForValidation fields. bool EqualsForClientValidationPurpose(const AutofillProfile& profile) const;
diff --git a/components/autofill/core/browser/autofill_subject.cc b/components/autofill/core/browser/autofill_subject.cc new file mode 100644 index 0000000..d6796107 --- /dev/null +++ b/components/autofill/core/browser/autofill_subject.cc
@@ -0,0 +1,54 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/autofill_subject.h" + +#include <vector> + +#include "base/callback_forward.h" +#include "base/observer_list.h" +#include "components/autofill/core/browser/autofill_observer.h" + +using NotificationType = autofill::AutofillObserver::NotificationType; + +namespace autofill { + +AutofillSubject::AutofillSubject() = default; +AutofillSubject::~AutofillSubject() = default; + +void AutofillSubject::Attach(AutofillObserver* observer) { + observers_map_[observer->notification_type()].AddObserver(observer); +} + +void AutofillSubject::Detach(AutofillObserver* observer) { + auto it = observers_map_.find(observer->notification_type()); + if (it == observers_map_.end()) { + return; + } + it->second.RemoveObserver(observer); +} + +void AutofillSubject::Notify(NotificationType notification_type) { + auto it = observers_map_.find(notification_type); + if (it == observers_map_.end()) { + return; + } + + std::vector<AutofillObserver*> observers_to_remove; + for (AutofillObserver& observer : it->second) { + if (notification_type == observer.notification_type()) { + observer.OnNotify(); + + if (observer.detach_on_notify()) { + observers_to_remove.push_back(&observer); + } + } + } + + for (AutofillObserver* observer : observers_to_remove) { + it->second.RemoveObserver(observer); + } +} + +} // namespace autofill
diff --git a/components/autofill/core/browser/autofill_subject.h b/components/autofill/core/browser/autofill_subject.h new file mode 100644 index 0000000..2e4f222fa --- /dev/null +++ b/components/autofill/core/browser/autofill_subject.h
@@ -0,0 +1,38 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SUBJECT_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SUBJECT_H_ + +#include <map> + +#include "base/observer_list.h" +#include "components/autofill/core/browser/autofill_observer.h" + +using NotificationType = autofill::AutofillObserver::NotificationType; + +namespace autofill { + +// Subject that can emit notifications of specific types to observers that were +// opted-in. +class AutofillSubject { + public: + AutofillSubject(); + ~AutofillSubject(); + + void Attach(AutofillObserver* observer); + void Detach(AutofillObserver* observer); + + // Will notify observers that are watching for the same |notification_type|. + // This function is O(n^2) in case all observers are auto-detaching. + void Notify(NotificationType notification_type); + + private: + std::map<NotificationType, base::ObserverList<AutofillObserver>> + observers_map_; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SUBJECT_H_
diff --git a/components/autofill/core/browser/autofill_subject_unittest.cc b/components/autofill/core/browser/autofill_subject_unittest.cc new file mode 100644 index 0000000..f1c8eca7 --- /dev/null +++ b/components/autofill/core/browser/autofill_subject_unittest.cc
@@ -0,0 +1,140 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/autofill_subject.h" + +#include "components/autofill/core/browser/autofill_observer.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using NotificationType = autofill::AutofillObserver::NotificationType; + +namespace autofill { + +namespace { + +class TestAutofillObserver : public AutofillObserver { + public: + TestAutofillObserver(NotificationType notification_type, + bool detach_on_notify) + : AutofillObserver(notification_type, detach_on_notify) {} + + void OnNotify() override { was_notified_ = true; } + + void Reset() { was_notified_ = false; } + + bool IsActive() { return IsInObserverList(); } + + bool was_notified() { return was_notified_; } + + private: + bool was_notified_ = false; +}; + +} // namespace + +class AutofillSubjectTest : public testing::Test { + public: + AutofillSubjectTest() : subject_() {} + + protected: + AutofillSubject subject_; +}; + +// Tests that a basic notification works. +TEST_F(AutofillSubjectTest, Simple_Notification_NoAutoDetach) { + TestAutofillObserver observer(NotificationType::AutocompleteFormSubmitted, + /*detach_on_notify=*/false); + + subject_.Attach(&observer); + + EXPECT_TRUE(observer.IsActive()); + + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_TRUE(observer.was_notified()); + + // Still active. + EXPECT_TRUE(observer.IsActive()); + + subject_.Detach(&observer); + + observer.Reset(); + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_FALSE(observer.was_notified()); + EXPECT_FALSE(observer.IsActive()); +} + +// Tests that a basic notification with auto-detach works. +TEST_F(AutofillSubjectTest, Simple_Notification_WithAutoDetach) { + TestAutofillObserver observer(NotificationType::AutocompleteFormSubmitted, + /*detach_on_notify=*/true); + + subject_.Attach(&observer); + + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_TRUE(observer.was_notified()); + EXPECT_FALSE(observer.IsActive()); + + observer.Reset(); + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_FALSE(observer.was_notified()); + EXPECT_FALSE(observer.IsActive()); +} + +// Tests that NotificationType properly isolates notifications. +TEST_F(AutofillSubjectTest, MultipleObservers_SimpleNotification) { + TestAutofillObserver submit_observer( + NotificationType::AutocompleteFormSubmitted, + /*detach_on_notify=*/false); + TestAutofillObserver cleanup_observer( + NotificationType::AutocompleteCleanupDone, + /*detach_on_notify=*/false); + + subject_.Attach(&submit_observer); + subject_.Attach(&cleanup_observer); + + subject_.Notify(NotificationType::AutocompleteCleanupDone); + + EXPECT_FALSE(submit_observer.was_notified()); + EXPECT_TRUE(cleanup_observer.was_notified()); +} + +// Tests that auto-detach doesn't detach all observers. +TEST_F(AutofillSubjectTest, + MultipleObservers_SimpleNotification_OneAutoDetach) { + TestAutofillObserver detach_submit_observer( + NotificationType::AutocompleteFormSubmitted, + /*detach_on_notify=*/true); + TestAutofillObserver stay_submit_observer( + NotificationType::AutocompleteFormSubmitted, + /*detach_on_notify=*/false); + + subject_.Attach(&detach_submit_observer); + subject_.Attach(&stay_submit_observer); + + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_TRUE(detach_submit_observer.was_notified()); + EXPECT_TRUE(stay_submit_observer.was_notified()); + + EXPECT_FALSE(detach_submit_observer.IsActive()); + EXPECT_TRUE(stay_submit_observer.IsActive()); + + detach_submit_observer.Reset(); + stay_submit_observer.Reset(); + + subject_.Notify(NotificationType::AutocompleteFormSubmitted); + + EXPECT_FALSE(detach_submit_observer.was_notified()); + EXPECT_TRUE(stay_submit_observer.was_notified()); + + EXPECT_FALSE(detach_submit_observer.IsActive()); + EXPECT_TRUE(stay_submit_observer.IsActive()); +} + +} // namespace autofill
diff --git a/components/autofill/core/browser/credit_card.h b/components/autofill/core/browser/credit_card.h index 761815b7..deff636 100644 --- a/components/autofill/core/browser/credit_card.h +++ b/components/autofill/core/browser/credit_card.h
@@ -48,8 +48,8 @@ // convert to a FULL_SERVER_CARD. MASKED_SERVER_CARD, - // A card from the Wallet server with full information. This card is not - // locally editable. + // A card from the Wallet server with full information store locally. This + // card is not locally editable. FULL_SERVER_CARD, };
diff --git a/components/autofill/core/browser/credit_card_save_manager.h b/components/autofill/core/browser/credit_card_save_manager.h index e9ac73d2..9677680 100644 --- a/components/autofill/core/browser/credit_card_save_manager.h +++ b/components/autofill/core/browser/credit_card_save_manager.h
@@ -124,6 +124,7 @@ private: friend class CreditCardSaveManagerTest; friend class CreditCardSaveManagerTestObserverBridge; + friend class LocalCardMigrationBrowserTest; friend class TestCreditCardSaveManager; friend class SaveCardBubbleViewsBrowserTestBase;
diff --git a/components/autofill/core/browser/credit_card_save_strike_database.cc b/components/autofill/core/browser/credit_card_save_strike_database.cc index d2f0380..5df822f3 100644 --- a/components/autofill/core/browser/credit_card_save_strike_database.cc +++ b/components/autofill/core/browser/credit_card_save_strike_database.cc
@@ -29,4 +29,8 @@ return (long long)1000000 * 60 * 60 * 24 * 180; } +bool CreditCardSaveStrikeDatabase::UniqueIdsRequired() { + return true; +} + } // namespace autofill
diff --git a/components/autofill/core/browser/credit_card_save_strike_database.h b/components/autofill/core/browser/credit_card_save_strike_database.h index 7ce7dbb9..5376822 100644 --- a/components/autofill/core/browser/credit_card_save_strike_database.h +++ b/components/autofill/core/browser/credit_card_save_strike_database.h
@@ -22,6 +22,7 @@ std::string GetProjectPrefix() override; int GetMaxStrikesLimit() override; long long GetExpiryTimeMicros() override; + bool UniqueIdsRequired() override; }; } // namespace autofill
diff --git a/components/autofill/core/browser/form_data_importer.h b/components/autofill/core/browser/form_data_importer.h index 412cf02..37b8d06 100644 --- a/components/autofill/core/browser/form_data_importer.h +++ b/components/autofill/core/browser/form_data_importer.h
@@ -145,6 +145,7 @@ friend class AutofillMergeTest; friend class FormDataImporterTest; friend class FormDataImporterTestBase; + friend class LocalCardMigrationBrowserTest; friend class SaveCardBubbleViewsBrowserTestBase; friend class SaveCardInfobarEGTestHelper; FRIEND_TEST_ALL_PREFIXES(AutofillMergeTest, MergeProfiles);
diff --git a/components/autofill/core/browser/form_data_importer_unittest.cc b/components/autofill/core/browser/form_data_importer_unittest.cc index 865c90a..8e297de 100644 --- a/components/autofill/core/browser/form_data_importer_unittest.cc +++ b/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -170,8 +170,19 @@ // Helper methods that simply forward the call to the private member (to avoid // having to friend every test that needs to access the private // PersonalDataManager::ImportAddressProfile or ImportCreditCard). - bool ImportAddressProfiles(const FormStructure& form) { - return form_data_importer_->ImportAddressProfiles(form); + void ImportAddressProfiles(bool extraction_successful, + const FormStructure& form) { + if (!extraction_successful) { + EXPECT_FALSE(form_data_importer_->ImportAddressProfiles(form)); + return; + } + + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1); + EXPECT_TRUE(form_data_importer_->ImportAddressProfiles(form)); + run_loop.Run(); } bool ImportCreditCard(const FormStructure& form, @@ -300,9 +311,7 @@ form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -339,7 +348,7 @@ form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure); ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size()); } @@ -370,9 +379,7 @@ form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size()); } @@ -403,7 +410,7 @@ form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure); ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size()); } @@ -425,7 +432,7 @@ form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure); ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size()); ASSERT_EQ(0U, personal_data_manager_->GetCreditCards().size()); @@ -453,9 +460,7 @@ form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size()); } @@ -482,9 +487,7 @@ form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size()); } @@ -506,9 +509,7 @@ form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); ASSERT_EQ(1U, personal_data_manager_->GetProfiles().size()); } @@ -548,9 +549,7 @@ form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr, @@ -589,9 +588,7 @@ form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -631,9 +628,7 @@ FormStructure form_structure1(form1); form_structure1.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure1)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure1); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -669,9 +664,7 @@ FormStructure form_structure2(form2); form_structure2.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure2)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure2); AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected2, "John", nullptr, "Adams", "second@gmail.com", @@ -728,9 +721,7 @@ FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -804,9 +795,7 @@ // Still able to do the import. FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -888,9 +877,7 @@ FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); // Only two are saved. AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); @@ -944,9 +931,7 @@ FormStructure form_structure1(form1); form_structure1.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure1)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure1); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -992,9 +977,7 @@ FormStructure form_structure2(form2); form_structure2.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure2)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure2); const std::vector<AutofillProfile*>& results2 = personal_data_manager_->GetProfiles(); @@ -1031,9 +1014,7 @@ FormStructure form_structure1(form1); form_structure1.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure1)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure1); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr, @@ -1069,9 +1050,7 @@ FormStructure form_structure2(form2); form_structure2.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure2)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure2); const std::vector<AutofillProfile*>& results2 = personal_data_manager_->GetProfiles(); @@ -1115,9 +1094,7 @@ FormStructure form_structure1(form1); form_structure1.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure1)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure1); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -1155,9 +1132,7 @@ FormStructure form_structure2(form2); form_structure2.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure2)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure2); const std::vector<AutofillProfile*>& results2 = personal_data_manager_->GetProfiles(); @@ -1193,7 +1168,7 @@ FormStructure form_structure1(form1); form_structure1.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure1)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure1); // Since no refresh is expected, reload the data from the database to make // sure no changes were written out. @@ -1216,10 +1191,12 @@ "Hollywood", "CA", "91601", "US", "12345678910"); EXPECT_TRUE(profile.IsVerified()); - // Add the profile to the database. + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1); personal_data_manager_->AddProfile(profile); - - WaitForOnPersonalDataChanged(); + run_loop.Run(); // Simulate a form submission with conflicting info. FormData form; @@ -1247,10 +1224,7 @@ FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - // Wait for the refresh, which in this case is a no-op. - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); // Expect that no new profile is saved. const std::vector<AutofillProfile*>& results = @@ -1268,10 +1242,7 @@ FormStructure form_structure2(form); form_structure2.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure2)); - - // Wait for the refresh, which in this case is a no-op. - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure2); // Expect that no new profile is saved. const std::vector<AutofillProfile*>& results2 = @@ -1310,7 +1281,7 @@ FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure); // Since no refresh is expected, reload the data from the database to make // sure no changes were written out. @@ -1351,9 +1322,7 @@ FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_TRUE(ImportAddressProfiles(form_structure)); - - WaitForOnPersonalDataChanged(); + ImportAddressProfiles(/*extraction_success=*/true, form_structure); AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin); test::SetProfileInfo(&expected, "George", nullptr, "Washington", @@ -1400,7 +1369,7 @@ FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); - EXPECT_FALSE(ImportAddressProfiles(form_structure)); + ImportAddressProfiles(/*extraction_success=*/false, form_structure); // Since no refresh is expected, reload the data from the database to make // sure no changes were written out. @@ -2580,11 +2549,19 @@ FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); std::unique_ptr<CreditCard> imported_credit_card; + + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillRepeatedly(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(testing::AnyNumber()); // Still returns true because the credit card import was successful. EXPECT_TRUE(form_data_importer_->ImportFormData( form_structure, /*profile_autofill_enabled=*/true, /*credit_card_autofill_enabled=*/true, /*should_return_local_card=*/false, &imported_credit_card)); + run_loop.Run(); + ASSERT_TRUE(imported_credit_card); personal_data_manager_->OnAcceptedLocalCreditCardSave(*imported_credit_card);
diff --git a/components/autofill/core/browser/local_card_migration_manager.cc b/components/autofill/core/browser/local_card_migration_manager.cc index 2b1c5ae..bc9634e 100644 --- a/components/autofill/core/browser/local_card_migration_manager.cc +++ b/components/autofill/core/browser/local_card_migration_manager.cc
@@ -88,6 +88,9 @@ return; migration_request_ = payments::PaymentsClient::MigrationRequestDetails(); + if (observer_for_testing_) + observer_for_testing_->OnDecideToRequestLocalCardMigration(); + payments_client_->GetUploadDetails( std::vector<AutofillProfile>(), GetDetectedValues(), /*active_experiments=*/std::vector<const char*>(), app_locale_, @@ -145,15 +148,25 @@ bool migration_experiment_enabled = features::GetLocalCardMigrationExperimentalFlag() != features::LocalCardMigrationExperimentalFlag::kMigrationDisabled; - bool credit_card_upload_enabled = ::autofill::IsCreditCardUploadEnabled( - client_->GetPrefs(), client_->GetSyncService(), - client_->GetIdentityManager()->GetPrimaryAccountInfo().email); + + // If |observer_for_testing_| is set, assume we are in a browsertest and + // credit card upload should be enabled by default. Cannot get around this as + // Chrome OS testing requires an unsupported email domain (i.e. + // stub-user@example.com). + bool credit_card_upload_enabled = + observer_for_testing_ || + ::autofill::IsCreditCardUploadEnabled( + client_->GetPrefs(), client_->GetSyncService(), + client_->GetIdentityManager()->GetPrimaryAccountInfo().email); + bool has_google_payments_account = (payments::GetBillingCustomerId(personal_data_manager_, payments_client_->GetPrefService()) != 0); + bool sync_feature_enabled = (personal_data_manager_->GetSyncSigninState() == AutofillSyncSigninState::kSignedInAndSyncFeature); + return migration_experiment_enabled && credit_card_upload_enabled && has_google_payments_account && sync_feature_enabled; } @@ -163,6 +176,9 @@ AutofillClient::PaymentsRpcResult result, const base::string16& context_token, std::unique_ptr<base::Value> legal_message) { + if (observer_for_testing_) + observer_for_testing_->OnReceivedGetUploadDetailsResponse(); + if (result == AutofillClient::SUCCESS) { migration_request_.context_token = context_token; legal_message_ = base::DictionaryValue::From(std::move(legal_message)); @@ -196,6 +212,9 @@ AutofillClient::PaymentsRpcResult result, std::unique_ptr<std::unordered_map<std::string, std::string>> save_result, const std::string& display_text) { + if (observer_for_testing_) + observer_for_testing_->OnReceivedMigrateCardsResponse(); + if (!save_result) return; @@ -254,6 +273,9 @@ // Send the migration request. Will call payments_client to create a new // PaymentsRequest. Also create a new callback function OnDidMigrateLocalCards. void LocalCardMigrationManager::SendMigrateLocalCardsRequest() { + if (observer_for_testing_) + observer_for_testing_->OnSentMigrateCardsRequest(); + migration_request_.app_locale = app_locale_; migration_request_.billing_customer_number = payments::GetBillingCustomerId( personal_data_manager_, payments_client_->GetPrefService()); @@ -273,7 +295,9 @@ local_card_migration_origin_, AutofillMetrics::MAIN_DIALOG_SHOWN); // Pops up a larger, modal dialog showing the local cards to be uploaded. client_->ConfirmMigrateLocalCardToCloud( - std::move(legal_message_), migratable_credit_cards_, + std::move(legal_message_), + client_->GetIdentityManager()->GetPrimaryAccountInfo().email, + migratable_credit_cards_, base::BindOnce( &LocalCardMigrationManager::OnUserAcceptedMainMigrationDialog, weak_ptr_factory_.GetWeakPtr()));
diff --git a/components/autofill/core/browser/local_card_migration_manager.h b/components/autofill/core/browser/local_card_migration_manager.h index 06e5ce5..dc2fa329 100644 --- a/components/autofill/core/browser/local_card_migration_manager.h +++ b/components/autofill/core/browser/local_card_migration_manager.h
@@ -43,7 +43,7 @@ FAILURE_ON_UPLOAD, }; - MigratableCreditCard(const CreditCard& credit_card); + explicit MigratableCreditCard(const CreditCard& credit_card); ~MigratableCreditCard(); CreditCard credit_card() const { return credit_card_; } @@ -66,6 +66,16 @@ // Owned by FormDataImporter. class LocalCardMigrationManager { public: + // An observer class used by browsertests that gets notified whenever + // particular actions occur. + class ObserverForTest { + public: + virtual void OnDecideToRequestLocalCardMigration() = 0; + virtual void OnReceivedGetUploadDetailsResponse() = 0; + virtual void OnSentMigrateCardsRequest() = 0; + virtual void OnReceivedMigrateCardsResponse() = 0; + }; + // The parameters should outlive the LocalCardMigrationManager. LocalCardMigrationManager(AutofillClient* client, payments::PaymentsClient* payments_client, @@ -141,6 +151,7 @@ payments::PaymentsClient* payments_client_; private: + friend class LocalCardMigrationBrowserTest; FRIEND_TEST_ALL_PREFIXES(LocalCardMigrationManagerTest, MigrateCreditCard_MigrationPermanentFailure); FRIEND_TEST_ALL_PREFIXES(LocalCardMigrationManagerTest, @@ -161,6 +172,11 @@ // Finalizes the migration request and calls PaymentsClient. void SendMigrateLocalCardsRequest(); + // For testing. + void SetEventObserverForTesting(ObserverForTest* observer) { + observer_for_testing_ = observer; + } + std::unique_ptr<base::DictionaryValue> legal_message_; std::string app_locale_; @@ -187,6 +203,9 @@ // Record the triggering source of the local card migration. AutofillMetrics::LocalCardMigrationOrigin local_card_migration_origin_; + // Initialized only during tests. + ObserverForTest* observer_for_testing_ = nullptr; + base::WeakPtrFactory<LocalCardMigrationManager> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(LocalCardMigrationManager);
diff --git a/components/autofill/core/browser/local_card_migration_strike_database.cc b/components/autofill/core/browser/local_card_migration_strike_database.cc new file mode 100644 index 0000000..6125d44 --- /dev/null +++ b/components/autofill/core/browser/local_card_migration_strike_database.cc
@@ -0,0 +1,36 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/local_card_migration_strike_database.h" + +#include "components/autofill/core/browser/proto/strike_data.pb.h" + +namespace autofill { + +LocalCardMigrationStrikeDatabase::LocalCardMigrationStrikeDatabase( + StrikeDatabase* strike_database) + : StrikeDatabaseIntegratorBase(strike_database) { + RemoveExpiredStrikes(); +} + +LocalCardMigrationStrikeDatabase::~LocalCardMigrationStrikeDatabase() {} + +std::string LocalCardMigrationStrikeDatabase::GetProjectPrefix() { + return "LocalCardMigration"; +} + +int LocalCardMigrationStrikeDatabase::GetMaxStrikesLimit() { + return 6; +} + +long long LocalCardMigrationStrikeDatabase::GetExpiryTimeMicros() { + // Expiry time is 1 year. + return (long long)1000000 * 60 * 60 * 24 * 365; +} + +bool LocalCardMigrationStrikeDatabase::UniqueIdsRequired() { + return false; +} + +} // namespace autofill
diff --git a/components/autofill/core/browser/local_card_migration_strike_database.h b/components/autofill/core/browser/local_card_migration_strike_database.h new file mode 100644 index 0000000..ab25114 --- /dev/null +++ b/components/autofill/core/browser/local_card_migration_strike_database.h
@@ -0,0 +1,29 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ + +#include <string> + +#include "components/autofill/core/browser/strike_database.h" +#include "components/autofill/core/browser/strike_database_integrator_base.h" + +namespace autofill { + +// Implementation of StrikeDatabaseIntegratorBase for local card migrations. +class LocalCardMigrationStrikeDatabase : public StrikeDatabaseIntegratorBase { + public: + LocalCardMigrationStrikeDatabase(StrikeDatabase* strike_database); + ~LocalCardMigrationStrikeDatabase() override; + + std::string GetProjectPrefix() override; + int GetMaxStrikesLimit() override; + long long GetExpiryTimeMicros() override; + bool UniqueIdsRequired() override; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_
diff --git a/components/autofill/core/browser/local_card_migration_strike_database_unittest.cc b/components/autofill/core/browser/local_card_migration_strike_database_unittest.cc new file mode 100644 index 0000000..c7d3ad0 --- /dev/null +++ b/components/autofill/core/browser/local_card_migration_strike_database_unittest.cc
@@ -0,0 +1,111 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/local_card_migration_strike_database.h" + +#include <utility> +#include <vector> + +#include "base/files/scoped_temp_dir.h" +#include "base/run_loop.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_task_environment.h" +#include "base/threading/thread_task_runner_handle.h" +#include "components/autofill/core/browser/proto/strike_data.pb.h" +#include "components/autofill/core/browser/test_autofill_clock.h" +#include "components/autofill/core/browser/test_local_card_migration_strike_database.h" +#include "components/autofill/core/common/autofill_clock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +class LocalCardMigrationStrikeDatabaseTest : public ::testing::Test { + public: + LocalCardMigrationStrikeDatabaseTest() + : strike_database_(new StrikeDatabase(InitFilePath())) {} + + protected: + base::HistogramTester* GetHistogramTester() { return &histogram_tester_; } + base::test::ScopedTaskEnvironment scoped_task_environment_; + TestLocalCardMigrationStrikeDatabase strike_database_; + + private: + static const base::FilePath InitFilePath() { + base::ScopedTempDir temp_dir_; + EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); + const base::FilePath file_path = + temp_dir_.GetPath().AppendASCII("StrikeDatabaseTest"); + return file_path; + } + + base::HistogramTester histogram_tester_; +}; + +TEST_F(LocalCardMigrationStrikeDatabaseTest, MaxStrikesLimitReachedTest) { + EXPECT_EQ(false, strike_database_.IsMaxStrikesLimitReached()); + // 3 strikes added. + strike_database_.AddStrikes(3); + EXPECT_EQ(false, strike_database_.IsMaxStrikesLimitReached()); + // 4 strike added, total strike count is 7. + strike_database_.AddStrikes(4); + EXPECT_EQ(true, strike_database_.IsMaxStrikesLimitReached()); +} + +TEST_F(LocalCardMigrationStrikeDatabaseTest, + LocalCardMigrationNthStrikeAddedHistogram) { + // 2 strikes logged. + strike_database_.AddStrikes(2); + strike_database_.RemoveStrikes(2); + // 1 strike logged. + strike_database_.AddStrike(); + // 2 strikes logged. + strike_database_.AddStrike(); + std::vector<base::Bucket> buckets = GetHistogramTester()->GetAllSamples( + "Autofill.StrikeDatabase.NthStrikeAdded.LocalCardMigration"); + // There should be two buckets, for strike counts of 1 and 2. + ASSERT_EQ(2U, buckets.size()); + // Bucket for 1 strike should have count of 1. + EXPECT_EQ(1, buckets[0].count); + // Bucket for 2 strikes should have count of 2. + EXPECT_EQ(2, buckets[1].count); +} + +TEST_F(LocalCardMigrationStrikeDatabaseTest, + AddStrikeForZeroAndNonZeroStrikesTest) { + EXPECT_EQ(0, strike_database_.GetStrikes()); + strike_database_.AddStrike(); + EXPECT_EQ(1, strike_database_.GetStrikes()); + strike_database_.AddStrikes(2); + EXPECT_EQ(3, strike_database_.GetStrikes()); +} + +TEST_F(LocalCardMigrationStrikeDatabaseTest, + ClearStrikesForNonZeroStrikesTest) { + strike_database_.AddStrikes(3); + EXPECT_EQ(3, strike_database_.GetStrikes()); + strike_database_.ClearStrikes(); + EXPECT_EQ(0, strike_database_.GetStrikes()); +} + +TEST_F(LocalCardMigrationStrikeDatabaseTest, ClearStrikesForZeroStrikesTest) { + strike_database_.ClearStrikes(); + EXPECT_EQ(0, strike_database_.GetStrikes()); +} + +TEST_F(LocalCardMigrationStrikeDatabaseTest, RemoveExpiredStrikesTest) { + autofill::TestAutofillClock test_clock; + test_clock.SetNow(AutofillClock::Now()); + strike_database_.AddStrikes(2); + EXPECT_EQ(2, strike_database_.GetStrikes()); + + // Advance clock to past expiry time. + test_clock.Advance(base::TimeDelta::FromMicroseconds( + strike_database_.GetExpiryTimeMicros() + 1)); + + // One strike should be removed. + strike_database_.RemoveExpiredStrikes(); + EXPECT_EQ(1, strike_database_.GetStrikes()); +} + +} // namespace autofill
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc index 2c60f2ae..7c66782 100644 --- a/components/autofill/core/browser/personal_data_manager.cc +++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -630,17 +630,20 @@ AutofillProfile* profile = GetProfileByGUID(data_model.guid()); if (profile) { - profile->RecordAndLogUse(); - if (profile->record_type() == AutofillProfile::LOCAL_PROFILE) { - UpdateProfileInDB(*profile); + // We can't make the change directly on the web_profiles_, the update + // should happen in the database first. + AutofillProfile updated_profile(*profile); + updated_profile.RecordAndLogUse(); + UpdateProfileInDB(updated_profile); } else if (profile->record_type() == AutofillProfile::SERVER_PROFILE) { + profile->RecordAndLogUse(); // TODO(crbug.com/864519): Update this once addresses support account // storage, and also use the server database. database_helper_->GetLocalDatabase()->UpdateServerAddressMetadata( *profile); + Refresh(); } - Refresh(); } } @@ -1972,7 +1975,8 @@ break; case AutofillProfileChange::UPDATE: profiles_server_validities_need_update_ = true; - if (profile_exists && !existing_profile->EqualsSansOrigin(profile)) { + if (profile_exists && + !existing_profile->EqualsForUpdatePurposes(profile)) { web_profiles_.erase( FindElementByGUID<AutofillProfile>(web_profiles_, guid)); web_profiles_.push_back(std::make_unique<AutofillProfile>(profile)); @@ -1988,10 +1992,7 @@ NOTREACHED(); } - ongoing_profile_changes_[guid].pop(); - - NotifyPersonalDataChanged(); - HandleNextProfileChange(guid); + OnProfileChangeDone(guid); } void PersonalDataManager::LogServerCardLinkClicked() const { @@ -2120,23 +2121,31 @@ } DVLOG(1) << "Starting autofill profile de-duplication."; - std::unordered_set<AutofillProfile*> profiles_to_delete; + std::unordered_set<std::string> profiles_to_delete; profiles_to_delete.reserve(web_profiles_.size()); // Create the map used to update credit card's billing addresses after the // dedupe. std::unordered_map<std::string, std::string> guids_merge_map; - DedupeProfiles(&web_profiles_, &profiles_to_delete, &guids_merge_map); + // The changes can't happen directly on the web_profiles_, but need to be + // updated in the database at first, and then updated on the web_profiles_. + // Therefore, we need a copy of web_profiles_ to keep track of the changes. + std::vector<std::unique_ptr<AutofillProfile>> new_profiles; + for (const auto& it : web_profiles_) { + new_profiles.push_back(std::make_unique<AutofillProfile>(*(it.get()))); + } + + DedupeProfiles(&new_profiles, &profiles_to_delete, &guids_merge_map); // Apply the profile changes to the database. - for (const auto& profile : web_profiles_) { - // If the profile was set to be deleted, remove it from the database. - if (profiles_to_delete.count(profile.get())) { + for (const auto& profile : new_profiles) { + // If the profile was set to be deleted, remove it from the database, + // otherwise update it. + if (profiles_to_delete.count(profile->guid())) { RemoveProfileFromDB(profile->guid()); } else { - // Otherwise, update the profile in the database. - UpdateProfileInDB(*profile); + UpdateProfileInDB(*(profile.get())); } } @@ -2150,7 +2159,7 @@ void PersonalDataManager::DedupeProfiles( std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles, - std::unordered_set<AutofillProfile*>* profiles_to_delete, + std::unordered_set<std::string>* profiles_to_delete, std::unordered_map<std::string, std::string>* guids_merge_map) const { AutofillMetrics::LogNumberOfProfilesConsideredForDedupe( existing_profiles->size()); @@ -2178,7 +2187,7 @@ // If the profile was set to be deleted, skip it. It has already been // merged into another profile. - if (profiles_to_delete->count(profile_to_merge)) + if (profiles_to_delete->count(profile_to_merge->guid())) continue; // If we have reached the verified profiles, stop trying to merge. Verified @@ -2192,7 +2201,7 @@ AutofillProfile* existing_profile = (*existing_profiles)[j].get(); // Don't try to merge a profile that was already set for deletion. - if (profiles_to_delete->count(existing_profile)) + if (profiles_to_delete->count(existing_profile->guid())) continue; // Move on if the profiles are not mergeable. @@ -2212,7 +2221,7 @@ // Since |profile_to_merge| was a duplicate of |existing_profile| // and was merged successfully, it can now be deleted. - profiles_to_delete->insert(profile_to_merge); + profiles_to_delete->insert(profile_to_merge->guid()); // Now try to merge the new resulting profile with the rest of the // existing profiles. @@ -2577,7 +2586,6 @@ } if (!ProfileChangesAreOnGoing(profile.guid())) { - // Don't add an existing/empty profile. if (FindByGUID<AutofillProfile>(web_profiles_, profile.guid()) || FindByContents(web_profiles_, profile)) { NotifyPersonalDataChanged(); @@ -2585,16 +2593,22 @@ } database_helper_->GetLocalDatabase()->AddAutofillProfile(profile); } - ongoing_profile_changes_[profile.guid()].push( AutofillProfileDeepChange(AutofillProfileChange::ADD, profile)); } void PersonalDataManager::UpdateProfileInDB(const AutofillProfile& profile) { - // Update the profile in the web database. if (!ProfileChangesAreOnGoing(profile.guid())) { - database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile); + const auto* existing_profile = GetProfileByGUID(profile.guid()); + bool profile_exists = (existing_profile != nullptr); + if (profile_exists && !existing_profile->EqualsForUpdatePurposes(profile)) { + database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile); + } else { + NotifyPersonalDataChanged(); + return; + } } + ongoing_profile_changes_[profile.guid()].push( AutofillProfileDeepChange(AutofillProfileChange::UPDATE, profile)); } @@ -2616,7 +2630,8 @@ if (!ProfileChangesAreOnGoing(guid)) return; - const auto& change_type = ongoing_profile_changes_[guid].front().type(); + const auto& change = ongoing_profile_changes_[guid].front(); + const auto& change_type = change.type(); const auto* existing_profile = GetProfileByGUID(guid); const bool profile_exists = (existing_profile != nullptr); const auto& profile = ongoing_profile_changes_[guid].front().profile(); @@ -2625,9 +2640,7 @@ if (change_type == AutofillProfileChange::REMOVE) { if (!profile_exists) { - ongoing_profile_changes_[guid].pop(); - NotifyPersonalDataChanged(); - HandleNextProfileChange(guid); + OnProfileChangeDone(guid); return; } database_helper_->GetLocalDatabase()->RemoveAutofillProfile(guid); @@ -2636,19 +2649,15 @@ if (change_type == AutofillProfileChange::ADD) { if (profile_exists || FindByContents(web_profiles_, profile)) { - ongoing_profile_changes_[guid].pop(); - NotifyPersonalDataChanged(); - HandleNextProfileChange(guid); + OnProfileChangeDone(guid); return; } database_helper_->GetLocalDatabase()->AddAutofillProfile(profile); return; } - if (!profile_exists || existing_profile->EqualsSansOrigin(profile)) { - ongoing_profile_changes_[guid].pop(); - NotifyPersonalDataChanged(); - HandleNextProfileChange(guid); + if (!profile_exists || existing_profile->EqualsForUpdatePurposes(profile)) { + OnProfileChangeDone(guid); return; } database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile); @@ -2669,6 +2678,17 @@ return false; } +void PersonalDataManager::OnProfileChangeDone(const std::string& guid) { + ongoing_profile_changes_[guid].pop(); + + if (!ProfileChangesAreOnGoing()) { + Refresh(); + } else { + NotifyPersonalDataChanged(); + HandleNextProfileChange(guid); + } +} + void PersonalDataManager::ClearOnGoingProfileChanges() { ongoing_profile_changes_.clear(); }
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h index b842de04..754305d 100644 --- a/components/autofill/core/browser/personal_data_manager.h +++ b/components/autofill/core/browser/personal_data_manager.h
@@ -652,7 +652,7 @@ // testing purposes. void DedupeProfiles( std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles, - std::unordered_set<AutofillProfile*>* profile_guids_to_delete, + std::unordered_set<std::string>* profile_guids_to_delete, std::unordered_map<std::string, std::string>* guids_merge_map) const; // Updates the credit cards' billing address reference based on the merges @@ -735,6 +735,9 @@ // returns true if there is any ongoing change for profile with guid = |guid| // that's still on going. bool ProfileChangesAreOnGoing(const std::string& guid); + // Remove the change from the |ongoing_profile_changes_|, handle next task or + // Refresh. + void OnProfileChangeDone(const std::string& guid); // Clear |ongoing_profile_changes_|. void ClearOnGoingProfileChanges();
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc index 5ec08022..f06c16f 100644 --- a/components/autofill/core/browser/personal_data_manager_unittest.cc +++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -216,7 +216,7 @@ personal_data_->OnSyncServiceInitialized(&sync_service_); personal_data_->OnStateChanged(&sync_service_); - WaitForOnPersonalDataChanged(); + WaitForOnPersonalDataChangedRepeatedly(); } void ResetPersonalDataManager(UserMode user_mode) { @@ -418,6 +418,27 @@ GetServerDataTable()->SetServerProfiles(server_profiles); } + void SaveImportedProfileToPersonalDataManager( + const AutofillProfile& profile) { + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1); + + personal_data_->SaveImportedProfile(profile); + run_loop.Run(); + } + + void ConvertWalletAddressesAndUpdateWalletCards() { + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1); + + personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); + run_loop.Run(); + } + // Verifies that the web database has been updated and the notification sent. void WaitForOnPersonalDataChanged() { base::RunLoop run_loop; @@ -436,6 +457,16 @@ run_loop.Run(); } + // Verifies that the web database has been updated and the notification sent. + void WaitForOnPersonalDataChangedRepeatedly() { + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillRepeatedly(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(testing::AnyNumber()); + run_loop.Run(); + } + void ExpectOnValidated(AutofillProfile* profile) { EXPECT_CALL(*personal_data_, OnValidated(profile)).Times(1); ON_CALL(*personal_data_, OnValidated(profile)) @@ -556,15 +587,6 @@ personal_data_->AddProfile(profile); profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("new@email.com")); personal_data_->UpdateProfile(profile); - WaitForOnPersonalDataChanged(); - - profiles = personal_data_->GetProfiles(); - ASSERT_EQ(1U, profiles.size()); - EXPECT_EQ(profiles[0]->GetRawInfo(EMAIL_ADDRESS), - base::ASCIIToUTF16("new@email.com")); - - profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("new@email.com")); - personal_data_->UpdateProfile(profile); profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("newer@email.com")); personal_data_->UpdateProfile(profile); WaitForOnPersonalDataChanged(); @@ -755,11 +777,10 @@ AutofillProfile profile(test::GetFullProfile()); EXPECT_NE(base::Time(), profile.modification_date()); - personal_data_->SaveImportedProfile(profile); - WaitForOnPersonalDataChanged(); + SaveImportedProfileToPersonalDataManager(profile); const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles(); ASSERT_EQ(1U, profiles.size()); - EXPECT_GT(base::TimeDelta::FromMilliseconds(500), + EXPECT_GT(base::TimeDelta::FromMilliseconds(1000), AutofillClock::Now() - profiles[0]->modification_date()); } @@ -1445,9 +1466,7 @@ base::ASCIIToUTF16("1 234 567-8910")); EXPECT_TRUE(new_verified_profile.IsVerified()); - personal_data_->SaveImportedProfile(new_verified_profile); - - WaitForOnPersonalDataChanged(); + SaveImportedProfileToPersonalDataManager(new_verified_profile); // The new profile should be merged into the existing one. const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles(); @@ -2235,8 +2254,7 @@ // Disable Profile autofill. prefs::SetProfileAutofillEnabled(personal_data_->pref_service_, false); WaitForOnPersonalDataChanged(); - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // Check that profiles were saved. EXPECT_EQ(2U, personal_data_->GetProfiles().size()); @@ -2281,8 +2299,7 @@ personal_data_->Refresh(); WaitForOnPersonalDataChanged(); - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // Expect 2 autofilled values or suggestions. EXPECT_EQ(2U, personal_data_->GetProfiles().size()); @@ -3305,8 +3322,16 @@ EXPECT_EQ(1U, added_profile->use_count()); EXPECT_EQ(kArbitraryTime, added_profile->use_date()); EXPECT_EQ(kArbitraryTime, added_profile->modification_date()); + + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillOnce(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1); + personal_data_->RecordUseOf(profile); + run_loop.Run(); + CreditCard* added_card = personal_data_->GetCreditCardByGUID(credit_card.guid()); ASSERT_TRUE(added_card); @@ -3316,8 +3341,6 @@ EXPECT_EQ(kArbitraryTime, added_card->modification_date()); personal_data_->RecordUseOf(credit_card); - WaitForOnPersonalDataChanged(); - // Verify usage stats are updated. added_profile = personal_data_->GetProfileByGUID(profile.guid()); ASSERT_TRUE(added_profile); @@ -3554,8 +3577,7 @@ base::UTF8ToUTF16(change.field_value)); } - personal_data_->SaveImportedProfile(profile2); - WaitForOnPersonalDataChanged(); + SaveImportedProfileToPersonalDataManager(profile2); const std::vector<AutofillProfile*>& saved_profiles = personal_data_->GetProfiles(); @@ -4009,7 +4031,7 @@ base::HistogramTester histogram_tester; std::unordered_map<std::string, std::string> guids_merge_map; - std::unordered_set<AutofillProfile*> profiles_to_delete; + std::unordered_set<std::string> profiles_to_delete; personal_data_->DedupeProfiles(&existing_profiles, &profiles_to_delete, &guids_merge_map); // 5 profiles were considered for dedupe. @@ -4021,11 +4043,11 @@ // Profile1 should be deleted because it was sent as the profile to merge and // thus was merged into profile3 and then into profile5. - EXPECT_TRUE(profiles_to_delete.count(profile1)); + EXPECT_TRUE(profiles_to_delete.count(profile1->guid())); // Profile3 should be deleted because profile1 was merged into it and the // resulting profile was then merged into profile5. - EXPECT_TRUE(profiles_to_delete.count(profile3)); + EXPECT_TRUE(profiles_to_delete.count(profile3->guid())); // Only these two profiles should be deleted. EXPECT_EQ(2U, profiles_to_delete.size()); @@ -4093,7 +4115,8 @@ EnableAutofillProfileCleanup(); std::unordered_map<std::string, std::string> guids_merge_map; - std::unordered_set<AutofillProfile*> profiles_to_delete; + std::unordered_set<std::string> profiles_to_delete; + personal_data_->DedupeProfiles(&existing_profiles, &profiles_to_delete, &guids_merge_map); @@ -5154,15 +5177,7 @@ ASSERT_EQ(1U, personal_data_->GetServerProfiles().size()); ASSERT_EQ(2U, personal_data_->GetCreditCards().size()); - /////////////////////////////////////////////////////////////////////// - // Tested method. - /////////////////////////////////////////////////////////////////////// - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - - /////////////////////////////////////////////////////////////////////// - // Validation. - /////////////////////////////////////////////////////////////////////// - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // The Wallet address should have been added as a new local profile. EXPECT_EQ(2U, personal_data_->GetProfiles().size()); @@ -5259,15 +5274,7 @@ EXPECT_EQ(1U, personal_data_->GetServerProfiles().size()); EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); - /////////////////////////////////////////////////////////////////////// - // Tested method. - /////////////////////////////////////////////////////////////////////// - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - - /////////////////////////////////////////////////////////////////////// - // Validation. - /////////////////////////////////////////////////////////////////////// - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // The Wallet address should have been merged with the existing local profile. EXPECT_EQ(1U, personal_data_->GetProfiles().size()); @@ -5428,15 +5435,7 @@ EXPECT_EQ(2U, personal_data_->GetServerProfiles().size()); EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); - /////////////////////////////////////////////////////////////////////// - // Tested method. - /////////////////////////////////////////////////////////////////////// - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - - /////////////////////////////////////////////////////////////////////// - // Validation. - /////////////////////////////////////////////////////////////////////// - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // The first Wallet address should have been added as a new local profile and // the second one should have merged with the first. @@ -5521,10 +5520,7 @@ EXPECT_EQ(1U, personal_data_->GetServerProfiles().size()); EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); - // Run the conversion. - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // The Wallet address should have been converted to a new local profile. EXPECT_EQ(1U, personal_data_->GetProfiles().size()); @@ -5555,15 +5551,7 @@ EXPECT_EQ(1U, personal_data_->GetProfiles().size()); EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); - /////////////////////////////////////////////////////////////////////// - // Tested method. - /////////////////////////////////////////////////////////////////////// - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - - /////////////////////////////////////////////////////////////////////// - // Validation. - /////////////////////////////////////////////////////////////////////// - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // The conversion should still be recorded in the Wallet address. EXPECT_TRUE(personal_data_->GetServerProfiles().back()->has_converted()); @@ -6036,7 +6024,6 @@ // Reloading the test profile should result in test data being created. ResetPersonalDataManager(USER_MODE_NORMAL); - WaitOnceForOnPersonalDataChanged(); const std::vector<AutofillProfile*> addresses = personal_data_->GetProfiles(); const std::vector<CreditCard*> credit_cards = @@ -6402,9 +6389,15 @@ ASSERT_EQ(4U, personal_data_->GetProfiles().size()); - personal_data_->ClearProfileNonSettingsOrigins(); + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillRepeatedly(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(2); // The setting of profiles 0 and 2 will be cleared. - WaitForOnPersonalDataChanged(); + personal_data_->ClearProfileNonSettingsOrigins(); + run_loop.Run(); + ASSERT_EQ(4U, personal_data_->GetProfiles().size()); // The first three profiles' origin should be cleared and the fourth one still @@ -6522,9 +6515,13 @@ AddProfileToPersonalDataManager(profile4); } + base::RunLoop run_loop; + EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) + .WillRepeatedly(QuitMessageLoop(&run_loop)); + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .Times(2); // For the Japan profiles where the city is not empty. personal_data_->MoveJapanCityToStreetAddress(); - - WaitForOnPersonalDataChanged(); + run_loop.Run(); { AutofillProfile* profile0 = personal_data_->GetProfileByGUID(guid0); @@ -6829,6 +6826,7 @@ TEST_F(PersonalDataManagerTest, UpdateClientValidityStates) { // Create three profiles and add them to personal_data_. AutofillProfile valid_profile(test::GetFullValidProfileForCanada()); + valid_profile.set_use_date(AutofillClock::Now()); valid_profile.set_guid("00000000-0000-0000-0000-000000000001"); AddProfileToPersonalDataManager(valid_profile); @@ -6838,6 +6836,8 @@ PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("invalid phone number!")); profile_invalid_phone_email.SetRawInfo(EMAIL_ADDRESS, base::UTF8ToUTF16("invalid email!")); + profile_invalid_phone_email.set_use_date(AutofillClock::Now() - + base::TimeDelta::FromDays(10)); profile_invalid_phone_email.set_guid("00000000-0000-0000-0000-000000000002"); AddProfileToPersonalDataManager(profile_invalid_phone_email); @@ -6847,6 +6847,8 @@ "alice@munro.ca", "Fox", "123 Zoo St", "unit 5", "Montreal", "CA", "H3C 2A3", "CA", "15142343254"); profile_invalid_province.set_guid("00000000-0000-0000-0000-000000000003"); + profile_invalid_province.set_use_date(AutofillClock::Now() - + base::TimeDelta::FromDays(100)); AddProfileToPersonalDataManager(profile_invalid_province); ASSERT_EQ(3U, personal_data_->GetProfiles().size());
diff --git a/components/autofill/core/browser/phone_number_i18n.cc b/components/autofill/core/browser/phone_number_i18n.cc index 03b9bed..f4e7e3b 100644 --- a/components/autofill/core/browser/phone_number_i18n.cc +++ b/components/autofill/core/browser/phone_number_i18n.cc
@@ -108,7 +108,7 @@ namespace i18n { -const size_t kMaxPhoneNumberSize = 1000u; +const size_t kMaxPhoneNumberSize = 40u; // Returns true if |phone_number| is a possible number. bool IsPossiblePhoneNumber(
diff --git a/components/autofill/core/browser/strike_database.cc b/components/autofill/core/browser/strike_database.cc index a3b85f5b..0e247e7d 100644 --- a/components/autofill/core/browser/strike_database.cc +++ b/components/autofill/core/browser/strike_database.cc
@@ -39,17 +39,20 @@ StrikeDatabase::~StrikeDatabase() {} -int StrikeDatabase::AddStrike(const std::string key) { - int num_strikes = strike_map_cache_.count(key) // Cache has entry for |key|. - ? strike_map_cache_[key].num_strikes() + 1 - : 1; +int StrikeDatabase::AddStrikes(int strikes_increase, const std::string key) { + DCHECK(strikes_increase > 0); + int num_strikes = + strike_map_cache_.count(key) // Cache has entry for |key|. + ? strike_map_cache_[key].num_strikes() + strikes_increase + : strikes_increase; SetStrikeData(key, num_strikes); return num_strikes; } -int StrikeDatabase::RemoveStrike(const std::string key) { +int StrikeDatabase::RemoveStrikes(int strikes_decrease, const std::string key) { + DCHECK(strikes_decrease > 0); DCHECK(strike_map_cache_.count(key)); - int num_strikes = strike_map_cache_[key].num_strikes() - 1; + int num_strikes = strike_map_cache_[key].num_strikes() - strikes_decrease; if (num_strikes < 1) { ClearStrikes(key); return 0;
diff --git a/components/autofill/core/browser/strike_database.h b/components/autofill/core/browser/strike_database.h index 3049e0d8..bea6da0 100644 --- a/components/autofill/core/browser/strike_database.h +++ b/components/autofill/core/browser/strike_database.h
@@ -47,12 +47,13 @@ explicit StrikeDatabase(const base::FilePath& database_dir); ~StrikeDatabase() override; - // Increments in-memory cache and updates underlying ProtoDatabase. - int AddStrike(const std::string key); + // Increases in-memory cache by |strikes_increase| and updates underlying + // ProtoDatabase. + int AddStrikes(int strikes_increase, const std::string key); - // Removes an in-memory cache strike, updates last_update_timestamp, and - // updates underlying ProtoDatabase. - int RemoveStrike(const std::string key); + // Removes |strikes_decrease| in-memory cache strikes, updates + // last_update_timestamp, and updates underlying ProtoDatabase. + int RemoveStrikes(int strikes_decrease, const std::string key); // Returns strike count from in-memory cache. int GetStrikes(const std::string key);
diff --git a/components/autofill/core/browser/strike_database_integrator_base.cc b/components/autofill/core/browser/strike_database_integrator_base.cc index 04b9c90..f643819 100644 --- a/components/autofill/core/browser/strike_database_integrator_base.cc +++ b/components/autofill/core/browser/strike_database_integrator_base.cc
@@ -31,11 +31,19 @@ bool StrikeDatabaseIntegratorBase::IsMaxStrikesLimitReached( const std::string id) { + CheckIdUniqueness(id); return GetStrikes(id) >= GetMaxStrikesLimit(); } int StrikeDatabaseIntegratorBase::AddStrike(const std::string id) { - int num_strikes = strike_database_->AddStrike(GetKey(id)); + CheckIdUniqueness(id); + return AddStrikes(1, id); +} + +int StrikeDatabaseIntegratorBase::AddStrikes(int strikes_increase, + const std::string id) { + CheckIdUniqueness(id); + int num_strikes = strike_database_->AddStrikes(strikes_increase, GetKey(id)); base::UmaHistogramCounts1000( "Autofill.StrikeDatabase.NthStrikeAdded." + GetProjectPrefix(), num_strikes); @@ -43,14 +51,23 @@ } int StrikeDatabaseIntegratorBase::RemoveStrike(const std::string id) { - return strike_database_->RemoveStrike(GetKey(id)); + CheckIdUniqueness(id); + return strike_database_->RemoveStrikes(1, GetKey(id)); +} + +int StrikeDatabaseIntegratorBase::RemoveStrikes(int strikes_decrease, + const std::string id) { + CheckIdUniqueness(id); + return strike_database_->RemoveStrikes(strikes_decrease, GetKey(id)); } int StrikeDatabaseIntegratorBase::GetStrikes(const std::string id) { + CheckIdUniqueness(id); return strike_database_->GetStrikes(GetKey(id)); } void StrikeDatabaseIntegratorBase::ClearStrikes(const std::string id) { + CheckIdUniqueness(id); strike_database_->ClearStrikes(GetKey(id)); } @@ -65,7 +82,7 @@ } } for (std::string key : expired_keys) - strike_database_->RemoveStrike(key); + strike_database_->RemoveStrikes(1, key); } std::string StrikeDatabaseIntegratorBase::GetKey(const std::string id) {
diff --git a/components/autofill/core/browser/strike_database_integrator_base.h b/components/autofill/core/browser/strike_database_integrator_base.h index 9a7d4261..9f207da 100644 --- a/components/autofill/core/browser/strike_database_integrator_base.h +++ b/components/autofill/core/browser/strike_database_integrator_base.h
@@ -9,6 +9,10 @@ namespace autofill { +namespace { +static const char kSharedId[] = "shared_id"; +} // namespace + // Contains virtual functions for per-project implementations of StrikeDatabase // to interface from, as well as a pointer to StrikeDatabase. This class is // seperated from StrikeDatabase since we only want StrikeDatabase's cache to @@ -20,21 +24,29 @@ // Returns whether or not strike count for |id| has reached the strike limit // set by GetMaxStrikesLimit(). - bool IsMaxStrikesLimitReached(const std::string id); + bool IsMaxStrikesLimitReached(const std::string id = kSharedId); // Increments in-memory cache and updates underlying ProtoDatabase. - int AddStrike(const std::string id); + int AddStrike(const std::string id = kSharedId); + + // Increases in-memory cache by |strikes_increase| and updates underlying + // ProtoDatabase. + int AddStrikes(int strikes_increase, const std::string id = kSharedId); // Removes an in-memory cache strike, updates last_update_timestamp, and // updates underlying ProtoDatabase. - int RemoveStrike(const std::string id); + int RemoveStrike(const std::string id = kSharedId); + + // Removes |strikes_decrease| in-memory cache strikes, updates + // |last_update_timestamp|, and updates underlying ProtoDatabase. + int RemoveStrikes(int strikes_decrease, const std::string id = kSharedId); // Returns strike count from in-memory cache. - int GetStrikes(const std::string id); + int GetStrikes(const std::string id = kSharedId); // Removes all database entries from in-memory cache and underlying // ProtoDatabase. - void ClearStrikes(const std::string id); + void ClearStrikes(const std::string id = kSharedId); protected: // Removes all strikes in which it has been longer than GetExpiryTimeMicros() @@ -50,11 +62,22 @@ GetIdForCreditCardSaveTest); FRIEND_TEST_ALL_PREFIXES(CreditCardSaveStrikeDatabaseTest, RemoveExpiredStrikesTest); + FRIEND_TEST_ALL_PREFIXES(LocalCardMigrationStrikeDatabaseTest, + RemoveExpiredStrikesTest); friend class StrikeDatabaseTest; friend class StrikeDatabaseTester; StrikeDatabase* strike_database_; + // For projects in which strikes don't have unique identifiers, the + // id suffix is set to |kSharedId|. This makes sure that projects requiring + // unique IDs always specify |id| instead of relying on the default shared + // value, while projects where unique IDs are unnecessary always fall back to + // the default shared value. + void CheckIdUniqueness(std::string id) { + DCHECK(UniqueIdsRequired() == (id != kSharedId)); + } + // Generates key based on project-specific string identifier. std::string GetKey(const std::string id); @@ -68,6 +91,10 @@ // Returns the time after which the most recent strike should expire. virtual long long GetExpiryTimeMicros() = 0; + + // Returns whether or not a unique string identifier is required for every + // strike in this project. + virtual bool UniqueIdsRequired() = 0; }; } // namespace autofill
diff --git a/components/autofill/core/browser/test_autofill_async_observer.cc b/components/autofill/core/browser/test_autofill_async_observer.cc new file mode 100644 index 0000000..d0f3133a --- /dev/null +++ b/components/autofill/core/browser/test_autofill_async_observer.cc
@@ -0,0 +1,28 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/test_autofill_async_observer.h" + +#include "base/run_loop.h" + +namespace autofill { +namespace test { + +TestAutofillAsyncObserver::TestAutofillAsyncObserver( + NotificationType notification_type, + bool detach_on_notify) + : AutofillObserver(notification_type, detach_on_notify), run_loop_() {} + +TestAutofillAsyncObserver::~TestAutofillAsyncObserver() = default; + +void TestAutofillAsyncObserver::OnNotify() { + run_loop_.Quit(); +} + +void TestAutofillAsyncObserver::Wait() { + run_loop_.Run(); +} + +} // namespace test +} // namespace autofill
diff --git a/components/autofill/core/browser/test_autofill_async_observer.h b/components/autofill/core/browser/test_autofill_async_observer.h new file mode 100644 index 0000000..17afb41 --- /dev/null +++ b/components/autofill/core/browser/test_autofill_async_observer.h
@@ -0,0 +1,42 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_ASYNC_OBSERVER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_ASYNC_OBSERVER_H_ + +#include "base/observer_list_types.h" +#include "base/run_loop.h" +#include "components/autofill/core/browser/autofill_observer.h" + +namespace autofill { +namespace test { + +// Observer which allows to block a thread (wait) until it gets notified with a +// specific NotificationType. Blocks the thread via a base::RunLoop. +// This is a very useful mechanism for browsers tests. +class TestAutofillAsyncObserver : public AutofillObserver { + public: + // |notification_type| is the notification type that this observer observes. + // |detach_on_notify| will let the AutofillSubject know that this + // observer only wants to watch for the first notification of that type. + TestAutofillAsyncObserver(NotificationType notification_type, + bool detach_on_notify = false); + + ~TestAutofillAsyncObserver() override; + + // Invoked by the watched AutofillSubject, this will effectively quit the + // current run loop. + void OnNotify() override; + + // Blocks the thread until the expected notification occurs. + void Wait(); + + private: + base::RunLoop run_loop_; +}; + +} // namespace test +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_ASYNC_OBSERVER_H_
diff --git a/components/autofill/core/browser/test_autofill_client.cc b/components/autofill/core/browser/test_autofill_client.cc index 9625f38..b2605601 100644 --- a/components/autofill/core/browser/test_autofill_client.cc +++ b/components/autofill/core/browser/test_autofill_client.cc
@@ -93,6 +93,7 @@ void TestAutofillClient::ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) { // If |migration_card_selection_| hasn't been preset by tests, default to
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h index 8a17870c..c2237b1 100644 --- a/components/autofill/core/browser/test_autofill_client.h +++ b/components/autofill/core/browser/test_autofill_client.h
@@ -57,6 +57,7 @@ base::OnceClosure show_migration_dialog_closure) override; void ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) override; void ShowLocalCardMigrationResults(
diff --git a/components/autofill/core/browser/test_local_card_migration_strike_database.cc b/components/autofill/core/browser/test_local_card_migration_strike_database.cc new file mode 100644 index 0000000..cc212712 --- /dev/null +++ b/components/autofill/core/browser/test_local_card_migration_strike_database.cc
@@ -0,0 +1,13 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/test_local_card_migration_strike_database.h" + +namespace autofill { + +TestLocalCardMigrationStrikeDatabase::TestLocalCardMigrationStrikeDatabase( + StrikeDatabase* strike_database) + : LocalCardMigrationStrikeDatabase(strike_database) {} + +} // namespace autofill
diff --git a/components/autofill/core/browser/test_local_card_migration_strike_database.h b/components/autofill/core/browser/test_local_card_migration_strike_database.h new file mode 100644 index 0000000..c1cac18 --- /dev/null +++ b/components/autofill/core/browser/test_local_card_migration_strike_database.h
@@ -0,0 +1,20 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ + +#include "components/autofill/core/browser/local_card_migration_strike_database.h" + +namespace autofill { + +class TestLocalCardMigrationStrikeDatabase + : public LocalCardMigrationStrikeDatabase { + public: + TestLocalCardMigrationStrikeDatabase(StrikeDatabase* strike_database); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_
diff --git a/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h b/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h index 03e7b7bca..f2dcc17 100644 --- a/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h +++ b/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h
@@ -29,6 +29,7 @@ virtual const std::vector<MigratableCreditCard>& GetCardList() const = 0; virtual const LegalMessageLines& GetLegalMessageLines() const = 0; virtual const base::string16& GetTipMessage() const = 0; + virtual const std::string& GetUserEmail() const = 0; virtual void OnSaveButtonClicked( const std::vector<std::string>& selected_cards_guids) = 0; virtual void OnCancelButtonClicked() = 0;
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc index 338cb06..44741c8 100644 --- a/components/autofill/core/browser/webdata/autofill_table.cc +++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -34,6 +34,7 @@ #include "components/autofill/core/browser/webdata/autofill_table_encryptor.h" #include "components/autofill/core/browser/webdata/autofill_table_encryptor_factory.h" #include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/autofill_util.h" @@ -54,10 +55,6 @@ // The period after which autocomplete entries should expire in days. const int64_t kExpirationPeriodInDays = 60; -// The period after which autocomplete entries should be cleaned-up in days. -// Equivalent to roughly 14 months. -const int64_t kAutocompleteRetentionPolicyPeriodInDays = 14 * 31; - // Helper struct for AutofillTable::RemoveFormElementsAddedBetween(). // Contains all the necessary fields to update a row in the 'autofill' table. struct AutofillUpdate {
diff --git a/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/components/autofill/core/browser/webdata/autofill_table_unittest.cc index 167ddb1..14d9f4e 100644 --- a/components/autofill/core/browser/webdata/autofill_table_unittest.cc +++ b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -846,7 +846,8 @@ scoped_feature_list_.InitAndEnableFeature( features::kAutocompleteRetentionPolicyEnabled); auto kNow = AutofillClock::Now(); - auto k2YearsOld = kNow - base::TimeDelta::FromDays(2 * 365); + auto k2YearsOld = kNow - base::TimeDelta::FromDays( + 2 * kAutocompleteRetentionPolicyPeriodInDays); AutofillChangeList changes; FormFieldData field;
diff --git a/components/autofill/core/common/autofill_constants.h b/components/autofill/core/common/autofill_constants.h index 04e6bd9..f5c34161 100644 --- a/components/autofill/core/common/autofill_constants.h +++ b/components/autofill/core/common/autofill_constants.h
@@ -50,6 +50,10 @@ constexpr base::TimeDelta kDisusedDataModelDeletionTimeDelta = base::TimeDelta::FromDays(395); +// The period after which autocomplete entries should be cleaned-up in days. +// Equivalent to roughly 14 months. +const int64_t kAutocompleteRetentionPolicyPeriodInDays = 14 * 31; + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_CONSTANTS_H_
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp index 54af8be..9996ab79 100644 --- a/components/autofill_strings.grdp +++ b/components/autofill_strings.grdp
@@ -262,8 +262,8 @@ <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_CARDHOLDER_NAME" desc="The label text for the cardholder name textfield."> Cardholder name </message> - <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_CARDHOLDER_NAME_TOOLTIP" desc="The tooltip text for the cardholder name textfield." formatter_data="android_java"> - This name is from your Google Account. + <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_CARDHOLDER_NAME_TOOLTIP" desc="The tooltip text for the cardholder name textfield. Note that the translation should not have period" formatter_data="android_java"> + This name is from your Google Account </message> <message name="IDS_AUTOFILL_SAVE_CARD_CARDHOLDER_NAME_FIX_FLOW_HEADER" desc="Header for the cardholder name fix flow."> Confirm name @@ -304,10 +304,10 @@ <message name="IDS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_CHECKBOX_UNCHECK_WARNING" desc="The warning text, after the user unchecks the checkbox, to indicate this card will still be saved on this device only, not to Google account."> Saved on this device only </message> - <message name="IDS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_MESSAGE_OFFER" desc="The body text for a dialog that offers to migrate local cards into the cloud. [ICU Syntax]"> + <message name="IDS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_MESSAGE_OFFER" desc="The body text for a dialog that offers to migrate local cards into the cloud. [CHAR-LIMIT=NONE] [ICU Syntax]"> {NUM_CARDS, plural, - =1 {You'll be able to use it when you're signed in. This card and its billing address will be saved in your Google Account.} - other {You'll be able to use them when you're signed in. These cards and their billing addresses will be saved in your Google Account.}} + =1 {This card and its billing address will be saved. You'll be able to use it when signed in to <ph name="USER_EMAIL">$1<ex>user@gmail.com</ex></ph>.} + other {These cards and their billing addresses will be saved. You'll be able to use them when signed in to <ph name="USER_EMAIL">$1<ex>user@gmail.com</ex></ph>.}} </message> <message name="IDS_AUTOFILL_LOCAL_CARD_MIGRATION_DIALOG_MESSAGE_DONE" desc="The body text for a dialog shown after the user accepts another dialog that offers to migrate local cards into the cloud and all cards are successfully migrated. [ICU Syntax]"> {NUM_CARDS, plural,
diff --git a/components/certificate_matching/BUILD.gn b/components/certificate_matching/BUILD.gn new file mode 100644 index 0000000..aa7e3bf --- /dev/null +++ b/components/certificate_matching/BUILD.gn
@@ -0,0 +1,32 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +component("certificate_matching") { + sources = [ + "certificate_principal_pattern.cc", + "certificate_principal_pattern.h", + ] + + defines = [ "IS_CERTIFICATE_MATCHING_IMPL" ] + + deps = [ + "//base", + "//net", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ + "certificate_principal_pattern_unittest.cc", + ] + + deps = [ + ":certificate_matching", + "//base", + "//net", + "//testing/gmock", + "//testing/gtest", + ] +}
diff --git a/components/certificate_matching/DEPS b/components/certificate_matching/DEPS new file mode 100644 index 0000000..ff594df --- /dev/null +++ b/components/certificate_matching/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+net/cert", +]
diff --git a/components/certificate_matching/OWNERS b/components/certificate_matching/OWNERS new file mode 100644 index 0000000..be4c2b35 --- /dev/null +++ b/components/certificate_matching/OWNERS
@@ -0,0 +1,2 @@ +file://chromeos/policy/OWNERS +file://chromeos/network/OWNERS
diff --git a/components/certificate_matching/certificate_principal_pattern.cc b/components/certificate_matching/certificate_principal_pattern.cc new file mode 100644 index 0000000..9552b45d8 --- /dev/null +++ b/components/certificate_matching/certificate_principal_pattern.cc
@@ -0,0 +1,101 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/certificate_matching/certificate_principal_pattern.h" + +#include <string> + +#include "base/strings/string_piece.h" +#include "base/values.h" +#include "net/cert/x509_cert_types.h" +#include "net/cert/x509_certificate.h" + +namespace certificate_matching { +namespace { + +std::string GetOptionalStringKey(const base::Value& dictionary, + base::StringPiece key) { + auto* value = dictionary.FindStringKey(key); + return value ? *value : std::string(); +} + +} // namespace + +CertificatePrincipalPattern::CertificatePrincipalPattern() = default; + +CertificatePrincipalPattern::CertificatePrincipalPattern( + std::string common_name, + std::string locality, + std::string organization, + std::string organization_unit) + : common_name_(std::move(common_name)), + locality_(std::move(locality)), + organization_(std::move(organization)), + organization_unit_(std::move(organization_unit)) {} + +CertificatePrincipalPattern::CertificatePrincipalPattern( + const CertificatePrincipalPattern& rhs) = default; + +CertificatePrincipalPattern::CertificatePrincipalPattern( + CertificatePrincipalPattern&& rhs) = default; + +CertificatePrincipalPattern::~CertificatePrincipalPattern() = default; + +CertificatePrincipalPattern& CertificatePrincipalPattern::operator=( + const CertificatePrincipalPattern& rhs) = default; +CertificatePrincipalPattern& CertificatePrincipalPattern::operator=( + CertificatePrincipalPattern&& rhs) = default; + +bool CertificatePrincipalPattern::Empty() const { + return common_name_.empty() && locality_.empty() && organization_.empty() && + organization_unit_.empty(); +} + +bool CertificatePrincipalPattern::Matches( + const net::CertPrincipal& principal) const { + if (!common_name_.empty() && common_name_ != principal.common_name) { + return false; + } + + if (!locality_.empty() && locality_ != principal.locality_name) { + return false; + } + + if (!organization_.empty()) { + if (std::find(principal.organization_names.begin(), + principal.organization_names.end(), + organization_) == principal.organization_names.end()) { + return false; + } + } + + if (!organization_unit_.empty()) { + if (std::find(principal.organization_unit_names.begin(), + principal.organization_unit_names.end(), + organization_unit_) == + principal.organization_unit_names.end()) { + return false; + } + } + + return true; +} + +// static +CertificatePrincipalPattern CertificatePrincipalPattern::ParseFromOptionalDict( + const base::Value* dict, + base::StringPiece key_common_name, + base::StringPiece key_locality, + base::StringPiece key_organization, + base::StringPiece key_organization_unit) { + if (!dict || !dict->is_dict()) + return CertificatePrincipalPattern(); + return CertificatePrincipalPattern( + GetOptionalStringKey(*dict, key_common_name), + GetOptionalStringKey(*dict, key_locality), + GetOptionalStringKey(*dict, key_organization), + GetOptionalStringKey(*dict, key_organization_unit)); +} + +} // namespace certificate_matching
diff --git a/components/certificate_matching/certificate_principal_pattern.h b/components/certificate_matching/certificate_principal_pattern.h new file mode 100644 index 0000000..61757117 --- /dev/null +++ b/components/certificate_matching/certificate_principal_pattern.h
@@ -0,0 +1,79 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CERTIFICATE_MATCHING_CERTIFICATE_PRINCIPAL_PATTERN_H_ +#define COMPONENTS_CERTIFICATE_MATCHING_CERTIFICATE_PRINCIPAL_PATTERN_H_ + +#include <string> + +#include "base/component_export.h" +#include "base/strings/string_piece_forward.h" + +namespace base { +class Value; +} + +namespace net { +struct CertPrincipal; +} // namespace net + +namespace certificate_matching { + +// Class to represent fields of a principal (issuer or subject) of a X509 +// certificate and compare them. +class COMPONENT_EXPORT(CERTIFICATE_MATCHING) CertificatePrincipalPattern { + public: + // Creates a pattern that matches every certificate principal. + CertificatePrincipalPattern(); + // Creates a pattern that requires an exact equality with the specified + // |common_name|, |locality|, |organization| and |organization_unit| for a + // certificate to match. If one of these is empty, no constraint is put on the + // corresponding principal field. + CertificatePrincipalPattern(std::string common_name, + std::string locality, + std::string organization, + std::string organization_unit); + CertificatePrincipalPattern(const CertificatePrincipalPattern& rhs); + CertificatePrincipalPattern(CertificatePrincipalPattern&& rhs); + ~CertificatePrincipalPattern(); + + CertificatePrincipalPattern& operator=( + const CertificatePrincipalPattern& rhs); + CertificatePrincipalPattern& operator=(CertificatePrincipalPattern&& rhs); + + // Returns true if all fields in the pattern are empty. A return value of true + // means that this pattern will match every |CertPrincipal|. + bool Empty() const; + + // Returns true if this pattern matches |principal|. + bool Matches(const net::CertPrincipal& principal) const; + + const std::string& common_name() const { return common_name_; } + const std::string& locality() const { return locality_; } + const std::string& organization() const { return organization_; } + const std::string& organization_unit() const { return organization_unit_; } + + // Parses |value| to create a |CertificatePrincipalPattern|. If |value| is + // present and a dictionary, the |key_*| parameters will be used to fill + // corresponding fields of the resulting |CertificatePrincipalPattern|. If a + // key is not present in the dictionary, the corresponding field will be left + // empty (putting no constraint on the principal field). If |value| is nullptr + // or not a dictionary, returns an empty pattern. + static CertificatePrincipalPattern ParseFromOptionalDict( + const base::Value* dict, + base::StringPiece key_common_name, + base::StringPiece key_locality, + base::StringPiece key_organization, + base::StringPiece key_organization_unit); + + private: + std::string common_name_; + std::string locality_; + std::string organization_; + std::string organization_unit_; +}; + +} // namespace certificate_matching + +#endif // COMPONENTS_CERTIFICATE_MATCHING_CERTIFICATE_PRINCIPAL_PATTERN_H_
diff --git a/components/certificate_matching/certificate_principal_pattern_unittest.cc b/components/certificate_matching/certificate_principal_pattern_unittest.cc new file mode 100644 index 0000000..dab4b49 --- /dev/null +++ b/components/certificate_matching/certificate_principal_pattern_unittest.cc
@@ -0,0 +1,124 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/certificate_matching/certificate_principal_pattern.h" + +#include "base/values.h" +#include "net/cert/x509_cert_types.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace certificate_matching { +namespace { +constexpr char kKeyCN[] = "CN"; +constexpr char kKeyL[] = "L"; +constexpr char kKeyO[] = "O"; +constexpr char kKeyOU[] = "OU"; +} // namespace + +TEST(CertificatePrincipalPatternTest, EmptyPattern) { + CertificatePrincipalPattern pattern; + EXPECT_TRUE(pattern.Empty()); + + EXPECT_TRUE(pattern.Matches(net::CertPrincipal())); + { + net::CertPrincipal principal; + principal.common_name = "CN"; + EXPECT_TRUE(pattern.Matches(principal)); + } +} + +TEST(CertificatePrincipalPatternTest, MatchingOnlyCN) { + CertificatePrincipalPattern pattern("CN" /* common_name */, "" /* locality */, + "" /* organization */, + "" /* organization_unit */); + EXPECT_FALSE(pattern.Empty()); + + EXPECT_FALSE(pattern.Matches(net::CertPrincipal())); + { + net::CertPrincipal principal; + principal.common_name = "CN"; + EXPECT_TRUE(pattern.Matches(principal)); + } + { + net::CertPrincipal principal; + principal.common_name = "CNIsWrong"; + EXPECT_FALSE(pattern.Matches(principal)); + } + { + net::CertPrincipal principal; + principal.common_name = "CN"; + principal.locality_name = "NotRelevant"; + EXPECT_TRUE(pattern.Matches(principal)); + } +} + +TEST(CertificatePrincipalPatternTest, MatchingEverything) { + CertificatePrincipalPattern pattern( + "CN" /* common_name */, "L" /* locality */, "O" /* organization */, + "OU" /* organization_unit */); + EXPECT_FALSE(pattern.Empty()); + + // Matches an empty CertPrincipal + EXPECT_FALSE(pattern.Matches(net::CertPrincipal())); + net::CertPrincipal principal; + principal.common_name = "CN"; + EXPECT_FALSE(pattern.Matches(principal)); + principal.locality_name = "L"; + EXPECT_FALSE(pattern.Matches(principal)); + principal.organization_names.push_back("O"); + EXPECT_FALSE(pattern.Matches(principal)); + principal.organization_unit_names.push_back("OU"); + EXPECT_TRUE(pattern.Matches(principal)); + + // Additional entries in the lists don't cause matching to fail. + principal.organization_names.insert(principal.organization_names.begin(), + "Front"); + principal.organization_names.push_back("Back"); + principal.organization_unit_names.insert( + principal.organization_unit_names.begin(), "Front"); + principal.organization_unit_names.push_back("Back"); + EXPECT_TRUE(pattern.Matches(principal)); +} + +TEST(CertificatePrincipalPatternTest, ParseFromNullptr) { + CertificatePrincipalPattern pattern = + CertificatePrincipalPattern::ParseFromOptionalDict(nullptr, kKeyCN, kKeyL, + kKeyO, kKeyOU); + EXPECT_TRUE(pattern.Empty()); +} + +TEST(CertificatePrincipalPatternTest, ParseFromNonDict) { + base::Value string_value("test"); + CertificatePrincipalPattern pattern = + CertificatePrincipalPattern::ParseFromOptionalDict(&string_value, kKeyCN, + kKeyL, kKeyO, kKeyOU); + EXPECT_TRUE(pattern.Empty()); +} + +TEST(CertificatePrincipalPatternTest, ParseFromEmptyDict) { + base::Value dict_value(base::Value::Type::DICTIONARY); + CertificatePrincipalPattern pattern = + CertificatePrincipalPattern::ParseFromOptionalDict(&dict_value, kKeyCN, + kKeyL, kKeyO, kKeyOU); + EXPECT_TRUE(pattern.Empty()); +} + +TEST(CertificatePrincipalPatternTest, Parse) { + base::Value dict_value(base::Value::Type::DICTIONARY); + dict_value.SetKey(kKeyCN, base::Value("ValueCN")); + dict_value.SetKey(kKeyL, base::Value("ValueL")); + dict_value.SetKey(kKeyO, base::Value("ValueO")); + dict_value.SetKey(kKeyOU, base::Value("ValueOU")); + CertificatePrincipalPattern pattern = + CertificatePrincipalPattern::ParseFromOptionalDict(&dict_value, kKeyCN, + kKeyL, kKeyO, kKeyOU); + EXPECT_FALSE(pattern.Empty()); + EXPECT_EQ("ValueCN", pattern.common_name()); + EXPECT_EQ("ValueL", pattern.locality()); + EXPECT_EQ("ValueO", pattern.organization()); + EXPECT_EQ("ValueOU", pattern.organization_unit()); +} + +} // namespace certificate_matching
diff --git a/components/content_settings/core/browser/content_settings_pref.cc b/components/content_settings/core/browser/content_settings_pref.cc index defa57b5..0bca90c 100644 --- a/components/content_settings/core/browser/content_settings_pref.cc +++ b/components/content_settings/core/browser/content_settings_pref.cc
@@ -293,9 +293,9 @@ if (value) { base::Time last_modified = GetTimeStamp(settings_dictionary); DCHECK(IsValueAllowedForType(value, content_type_)); - value_map_.SetValue(pattern_pair.first, pattern_pair.second, - content_type_, ResourceIdentifier(), last_modified, - value->Clone()); + value_map_.SetValue(std::move(pattern_pair.first), + std::move(pattern_pair.second), content_type_, + ResourceIdentifier(), last_modified, value->Clone()); } } }
diff --git a/components/content_settings/core/browser/host_content_settings_map.cc b/components/content_settings/core/browser/host_content_settings_map.cc index 7d705f2..858cdbd 100644 --- a/components/content_settings/core/browser/host_content_settings_map.cc +++ b/components/content_settings/core/browser/host_content_settings_map.cc
@@ -559,14 +559,14 @@ ContentSettingsPattern::Relation r1 = info.primary_pattern.Compare(patterns.first); if (r1 == ContentSettingsPattern::PREDECESSOR) { - patterns.first = info.primary_pattern; + patterns.first = std::move(info.primary_pattern); } else if (r1 == ContentSettingsPattern::IDENTITY) { ContentSettingsPattern::Relation r2 = info.secondary_pattern.Compare(patterns.second); DCHECK(r2 != ContentSettingsPattern::DISJOINT_ORDER_POST && r2 != ContentSettingsPattern::DISJOINT_ORDER_PRE); if (r2 == ContentSettingsPattern::PREDECESSOR) - patterns.second = info.secondary_pattern; + patterns.second = std::move(info.secondary_pattern); } return patterns;
diff --git a/components/content_settings/core/common/content_settings_pattern.cc b/components/content_settings/core/common/content_settings_pattern.cc index a0b9ac07..8931da2 100644 --- a/components/content_settings/core/common/content_settings_pattern.cc +++ b/components/content_settings/core/common/content_settings_pattern.cc
@@ -8,10 +8,12 @@ #include <memory> #include <tuple> +#include <utility> #include <vector> #include "base/optional.h" #include "base/stl_util.h" +#include "base/strings/string_piece.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "components/content_settings/core/common/content_settings_pattern_parser.h" @@ -35,19 +37,21 @@ static_assert(base::size(kSchemeNames) == ContentSettingsPattern::SCHEME_MAX, "kSchemeNames should have SCHEME_MAX elements"); -std::string GetDefaultPort(const std::string& scheme) { +// Note: it is safe to return a base::StringPiece here as long as they are +// either empty or referencing constant string literals. +base::StringPiece GetDefaultPort(base::StringPiece scheme) { if (scheme == url::kHttpScheme) return "80"; if (scheme == url::kHttpsScheme) return "443"; - return std::string(); + return base::StringPiece(); } // Returns true if |sub_domain| is a sub domain or equals |domain|. E.g. // "mail.google.com" is a sub domain of "google.com" but "evilhost.com" is not a // subdomain of "host.com". -bool IsSubDomainOrEqual(const std::string& sub_domain, - const std::string& domain) { +bool IsSubDomainOrEqual(base::StringPiece sub_domain, + base::StringPiece domain) { // The empty string serves as wildcard. Each domain is a subdomain of the // wildcard. if (domain.empty()) @@ -160,7 +164,7 @@ } BuilderInterface* ContentSettingsPattern::Builder::WithPortWildcard() { - parts_.port = ""; + parts_.port.clear(); parts_.is_port_wildcard = true; return this; } @@ -184,7 +188,7 @@ } BuilderInterface* ContentSettingsPattern::Builder::WithSchemeWildcard() { - parts_.scheme = ""; + parts_.scheme.clear(); parts_.is_scheme_wildcard = true; return this; } @@ -197,7 +201,7 @@ } BuilderInterface* ContentSettingsPattern::Builder::WithPathWildcard() { - parts_.path = ""; + parts_.path.clear(); parts_.is_path_wildcard = true; return this; } @@ -217,44 +221,45 @@ return ContentSettingsPattern(); // A pattern is invalid if canonicalization is not idempotent. - PatternParts parts(parts_); - if (!Canonicalize(&parts)) + PatternParts twice_canonicalized_parts(parts_); + if (!Canonicalize(&twice_canonicalized_parts)) return ContentSettingsPattern(); - if (ContentSettingsPattern(parts_, true) != - ContentSettingsPattern(parts, true)) { - return ContentSettingsPattern(); - } - return ContentSettingsPattern(parts_, is_valid_); + ContentSettingsPattern canonical_pattern(std::move(parts_), true); + ContentSettingsPattern doubly_canonical_pattern( + std::move(twice_canonicalized_parts), true); + if (canonical_pattern != doubly_canonical_pattern) + return ContentSettingsPattern(); + return canonical_pattern; } // static bool ContentSettingsPattern::Builder::Canonicalize(PatternParts* parts) { // Canonicalize the scheme part. - const std::string scheme(base::ToLowerASCII(parts->scheme)); - parts->scheme = scheme; + parts->scheme = base::ToLowerASCII(parts->scheme); - if (parts->scheme == std::string(url::kFileScheme) && - !parts->is_path_wildcard) { + if (parts->scheme == url::kFileScheme && !parts->is_path_wildcard) { GURL url(std::string(url::kFileScheme) + std::string(url::kStandardSchemeSeparator) + parts->path); parts->path = url.path(); } // Canonicalize the host part. - const std::string host(parts->host); url::CanonHostInfo host_info; - std::string canonicalized_host(net::CanonicalizeHost(host, &host_info)); + std::string canonicalized_host( + net::CanonicalizeHost(parts->host, &host_info)); if (host_info.IsIPAddress() && parts->has_domain_wildcard) return false; canonicalized_host = net::TrimEndingDot(canonicalized_host); - parts->host = ""; - if ((host.find('*') == std::string::npos) && + if ((parts->host.find('*') == std::string::npos) && !canonicalized_host.empty()) { // Valid host. - parts->host += canonicalized_host; + parts->host = std::move(canonicalized_host); + } else { + parts->host.clear(); } + return true; } @@ -270,14 +275,13 @@ } // file:// URL patterns have an empty host and port. - if (parts.scheme == std::string(url::kFileScheme)) { + if (parts.scheme == url::kFileScheme) { if (parts.has_domain_wildcard || !parts.host.empty() || !parts.port.empty()) return false; if (parts.is_path_wildcard) return parts.path.empty(); - return (!parts.path.empty() && - parts.path != "/" && - parts.path.find("*") == std::string::npos); + return (!parts.path.empty() && parts.path != "/" && + parts.path.find('*') == std::string::npos); } // If the pattern is for a URL with a non-wildcard domain without a port, @@ -296,13 +300,12 @@ return false; } - if (parts.host.find("*") != std::string::npos) + if (parts.host.find('*') != std::string::npos) return false; // Test if the scheme is supported or a wildcard. - if (!parts.is_scheme_wildcard && - parts.scheme != std::string(url::kHttpScheme) && - parts.scheme != std::string(url::kHttpsScheme)) { + if (!parts.is_scheme_wildcard && parts.scheme != url::kHttpScheme && + parts.scheme != url::kHttpsScheme) { return false; } return true; @@ -319,9 +322,16 @@ ContentSettingsPattern::PatternParts::PatternParts(const PatternParts& other) = default; +ContentSettingsPattern::PatternParts::PatternParts(PatternParts&& other) = + default; ContentSettingsPattern::PatternParts::~PatternParts() {} +ContentSettingsPattern::PatternParts& ContentSettingsPattern::PatternParts:: +operator=(const PatternParts& other) = default; +ContentSettingsPattern::PatternParts& ContentSettingsPattern::PatternParts:: +operator=(PatternParts&& other) = default; + // //////////////////////////////////////////////////////////////////////////// // ContentSettingsPattern // @@ -377,9 +387,9 @@ } else { // Unsupported scheme } - if (local_url->port().empty()) { + if (local_url->port_piece().empty()) { if (local_url->SchemeIs(url::kHttpsScheme)) - builder.WithPort(GetDefaultPort(url::kHttpsScheme)); + builder.WithPort(GetDefaultPort(url::kHttpsScheme).as_string()); else builder.WithPortWildcard(); } else { @@ -401,8 +411,8 @@ builder.WithScheme(local_url->scheme())->WithPath(local_url->path()); } else { builder.WithScheme(local_url->scheme())->WithHost(local_url->host()); - if (local_url->port().empty()) { - builder.WithPort(GetDefaultPort(local_url->scheme())); + if (local_url->port_piece().empty()) { + builder.WithPort(GetDefaultPort(local_url->scheme_piece()).as_string()); } else { builder.WithPort(local_url->port()); } @@ -412,7 +422,7 @@ // static ContentSettingsPattern ContentSettingsPattern::FromString( - const std::string& pattern_spec) { + base::StringPiece pattern_spec) { ContentSettingsPattern::Builder builder; content_settings::PatternParser::Parse(pattern_spec, &builder); return builder.Build(); @@ -436,7 +446,7 @@ // static bool ContentSettingsPattern::IsNonWildcardDomainNonPortScheme( - const std::string& scheme) { + base::StringPiece scheme) { DCHECK(g_non_domain_wildcard_non_port_schemes || g_non_domain_wildcard_non_port_schemes_count == 0); for (size_t i = 0; i < g_non_domain_wildcard_non_port_schemes_count; ++i) { @@ -451,12 +461,8 @@ : is_valid_(false) { } -ContentSettingsPattern::ContentSettingsPattern( - const PatternParts& parts, - bool valid) - : parts_(parts), - is_valid_(valid) { -} +ContentSettingsPattern::ContentSettingsPattern(PatternParts parts, bool valid) + : parts_(std::move(parts)), is_valid_(valid) {} bool ContentSettingsPattern::Matches( const GURL& url) const { @@ -470,9 +476,8 @@ } // Match the scheme part. - const std::string scheme(local_url->scheme()); if (!parts_.is_scheme_wildcard && - parts_.scheme != scheme) { + parts_.scheme != local_url->scheme_piece()) { return false; } @@ -482,17 +487,17 @@ // filesystem:file:///temporary/... are equivalent. // TODO(msramek): The file scheme should not behave differently when nested // inside the filesystem scheme. Investigate and fix. - if (!parts_.is_scheme_wildcard && scheme == url::kFileScheme) - return parts_.is_path_wildcard || - parts_.path == std::string(local_url->path()); + if (!parts_.is_scheme_wildcard && + local_url->scheme_piece() == url::kFileScheme) + return parts_.is_path_wildcard || parts_.path == local_url->path_piece(); // Match the host part. - const std::string host(net::TrimEndingDot(local_url->host())); + const std::string trimmed_host = net::TrimEndingDot(local_url->host_piece()); if (!parts_.has_domain_wildcard) { - if (parts_.host != host) + if (parts_.host != trimmed_host) return false; } else { - if (!IsSubDomainOrEqual(host, parts_.host)) + if (!IsSubDomainOrEqual(trimmed_host, parts_.host)) return false; } @@ -501,17 +506,13 @@ return true; // Match the port part. - std::string port(local_url->port()); - // Use the default port if the port string is empty. GURL returns an empty // string if no port at all was specified or if the default port was // specified. - if (port.empty()) { - port = GetDefaultPort(scheme); - } - - if (!parts_.is_port_wildcard && - parts_.port != port ) { + const base::StringPiece port = local_url->port_piece().empty() + ? GetDefaultPort(local_url->scheme_piece()) + : local_url->port_piece(); + if (!parts_.is_port_wildcard && parts_.port != port) { return false; }
diff --git a/components/content_settings/core/common/content_settings_pattern.h b/components/content_settings/core/common/content_settings_pattern.h index 2ac2643..0c93c0bc 100644 --- a/components/content_settings/core/common/content_settings_pattern.h +++ b/components/content_settings/core/common/content_settings_pattern.h
@@ -11,6 +11,7 @@ #include <string> #include "base/gtest_prod_util.h" +#include "base/strings/string_piece_forward.h" #include "mojo/public/cpp/bindings/struct_traits.h" class GURL; @@ -78,8 +79,12 @@ struct PatternParts { PatternParts(); PatternParts(const PatternParts& other); + PatternParts(PatternParts&& other); ~PatternParts(); + PatternParts& operator=(const PatternParts& other); + PatternParts& operator=(PatternParts&& other); + // Lowercase string of the URL scheme to match. This string is empty if the // |is_scheme_wildcard| flag is set. std::string scheme; @@ -165,7 +170,7 @@ // - file://path (The path has to be an absolute path and start with a '/') // - a.b.c.d (matches an exact IPv4 ip) // - [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip) - static ContentSettingsPattern FromString(const std::string& pattern_spec); + static ContentSettingsPattern FromString(base::StringPiece pattern_spec); // Sets schemes that do not support domain wildcards and ports. // Needs to be called by the embedder before using ContentSettingsPattern. @@ -179,7 +184,7 @@ size_t count); // Compares |scheme| against the schemes set by the embedder. - static bool IsNonWildcardDomainNonPortScheme(const std::string& scheme); + static bool IsNonWildcardDomainNonPortScheme(base::StringPiece scheme); // Constructs an empty pattern. Empty patterns are invalid patterns. Invalid // patterns match nothing. @@ -248,7 +253,7 @@ const ContentSettingsPattern::PatternParts& parts, const ContentSettingsPattern::PatternParts& other_parts); - ContentSettingsPattern(const PatternParts& parts, bool valid); + ContentSettingsPattern(PatternParts parts, bool valid); PatternParts parts_;
diff --git a/components/content_settings/core/common/content_settings_pattern_parser.cc b/components/content_settings/core/common/content_settings_pattern_parser.cc index d0844d4f..00af108 100644 --- a/components/content_settings/core/common/content_settings_pattern_parser.cc +++ b/components/content_settings/core/common/content_settings_pattern_parser.cc
@@ -6,6 +6,7 @@ #include <stddef.h> +#include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "url/url_constants.h" @@ -20,24 +21,11 @@ const char kUrlPathSeparator[] = "/"; const char kUrlPortSeparator[] = ":"; -class Component { - public: - Component() : start(0), len(0) {} - Component(size_t s, size_t l) : start(s), len(l) {} - - bool IsNonEmpty() { - return len > 0; - } - - size_t start; - size_t len; -}; - } // namespace namespace content_settings { -void PatternParser::Parse(const std::string& pattern_spec, +void PatternParser::Parse(base::StringPiece pattern_spec, ContentSettingsPattern::BuilderInterface* builder) { if (pattern_spec == "*") { builder->WithSchemeWildcard(); @@ -48,10 +36,10 @@ // Initialize components for the individual patterns parts to empty // sub-strings. - Component scheme_component; - Component host_component; - Component port_component; - Component path_component; + base::StringPiece scheme_piece; + base::StringPiece host_piece; + base::StringPiece port_piece; + base::StringPiece path_piece; size_t start = 0; size_t current_pos = 0; @@ -63,7 +51,7 @@ const std::string standard_scheme_separator(url::kStandardSchemeSeparator); current_pos = pattern_spec.find(standard_scheme_separator, start); if (current_pos != std::string::npos) { - scheme_component = Component(start, current_pos); + scheme_piece = pattern_spec.substr(start, current_pos - start); start = current_pos + standard_scheme_separator.size(); current_pos = start; } else { @@ -82,28 +70,28 @@ if (current_pos == std::string::npos) return; // Bad pattern spec. - current_pos = pattern_spec.find(std::string(kUrlPortSeparator), current_pos); + current_pos = pattern_spec.find(kUrlPortSeparator, current_pos); if (current_pos == std::string::npos) { // No port spec found - current_pos = pattern_spec.find(std::string(kUrlPathSeparator), start); + current_pos = pattern_spec.find(kUrlPathSeparator, start); if (current_pos == std::string::npos) { current_pos = pattern_spec.size(); - host_component = Component(start, current_pos - start); + host_piece = pattern_spec.substr(start, current_pos - start); } else { // Pattern has a path spec. - host_component = Component(start, current_pos - start); + host_piece = pattern_spec.substr(start, current_pos - start); } start = current_pos; } else { // Port spec found. - host_component = Component(start, current_pos - start); + host_piece = pattern_spec.substr(start, current_pos - start); start = current_pos + 1; if (start < pattern_spec.size()) { - current_pos = pattern_spec.find(std::string(kUrlPathSeparator), start); + current_pos = pattern_spec.find(kUrlPathSeparator, start); if (current_pos == std::string::npos) { current_pos = pattern_spec.size(); } - port_component = Component(start, current_pos - start); + port_piece = pattern_spec.substr(start, current_pos - start); start = current_pos; } } @@ -111,86 +99,82 @@ current_pos = pattern_spec.size(); if (start < current_pos) { // Pattern has a path spec. - path_component = Component(start, current_pos - start); + path_piece = pattern_spec.substr(start, current_pos - start); } // Set pattern parts. - std::string scheme; - if (scheme_component.IsNonEmpty()) { - scheme = pattern_spec.substr(scheme_component.start, scheme_component.len); - if (scheme == kSchemeWildcard) { + if (!scheme_piece.empty()) { + if (scheme_piece == kSchemeWildcard) { builder->WithSchemeWildcard(); } else { - builder->WithScheme(scheme); + builder->WithScheme(scheme_piece.as_string()); } } else { builder->WithSchemeWildcard(); } - if (host_component.IsNonEmpty()) { - std::string host = pattern_spec.substr(host_component.start, - host_component.len); - if (host == kHostWildcard) { - if (ContentSettingsPattern::IsNonWildcardDomainNonPortScheme(scheme)) { + if (!host_piece.empty()) { + if (host_piece == kHostWildcard) { + if (ContentSettingsPattern::IsNonWildcardDomainNonPortScheme( + scheme_piece)) { builder->Invalid(); return; } builder->WithDomainWildcard(); - } else if (base::StartsWith(host, kDomainWildcard, + } else if (base::StartsWith(host_piece, kDomainWildcard, base::CompareCase::SENSITIVE)) { - if (ContentSettingsPattern::IsNonWildcardDomainNonPortScheme(scheme)) { + if (ContentSettingsPattern::IsNonWildcardDomainNonPortScheme( + scheme_piece)) { builder->Invalid(); return; } - host = host.substr(kDomainWildcardLength); + host_piece.remove_prefix(kDomainWildcardLength); builder->WithDomainWildcard(); - builder->WithHost(host); + builder->WithHost(host_piece.as_string()); } else { // If the host contains a wildcard symbol then it is invalid. - if (host.find(kHostWildcard) != std::string::npos) { + if (host_piece.find(kHostWildcard) != std::string::npos) { builder->Invalid(); return; } - builder->WithHost(host); + builder->WithHost(host_piece.as_string()); } } - if (port_component.IsNonEmpty()) { - if (ContentSettingsPattern::IsNonWildcardDomainNonPortScheme(scheme)) { + if (!port_piece.empty()) { + if (ContentSettingsPattern::IsNonWildcardDomainNonPortScheme( + scheme_piece)) { builder->Invalid(); return; } - const std::string port = pattern_spec.substr(port_component.start, - port_component.len); - if (port == kPortWildcard) { + if (port_piece == kPortWildcard) { builder->WithPortWildcard(); } else { // Check if the port string represents a valid port. - for (size_t i = 0; i < port.size(); ++i) { - if (!base::IsAsciiDigit(port[i])) { + for (size_t i = 0; i < port_piece.size(); ++i) { + if (!base::IsAsciiDigit(port_piece[i])) { builder->Invalid(); return; } } // TODO(markusheintz): Check port range. - builder->WithPort(port); + builder->WithPort(port_piece.as_string()); } } else { - if (!ContentSettingsPattern::IsNonWildcardDomainNonPortScheme(scheme) && - scheme != url::kFileScheme) + if (!ContentSettingsPattern::IsNonWildcardDomainNonPortScheme( + scheme_piece) && + scheme_piece != url::kFileScheme) builder->WithPortWildcard(); } - if (path_component.IsNonEmpty()) { - const std::string path = pattern_spec.substr(path_component.start, - path_component.len); - if (path.substr(1) == kPathWildcard) + if (!path_piece.empty()) { + if (path_piece.substr(1) == kPathWildcard) builder->WithPathWildcard(); else - builder->WithPath(path); + builder->WithPath(path_piece.as_string()); } } @@ -199,20 +183,26 @@ const ContentSettingsPattern::PatternParts& parts) { // Return the most compact form to support legacy code and legacy pattern // strings. - if (parts.is_scheme_wildcard && - parts.has_domain_wildcard && - parts.host.empty() && - parts.is_port_wildcard) + if (parts.is_scheme_wildcard && parts.has_domain_wildcard && + parts.host.empty() && parts.is_port_wildcard) { return "*"; + } std::string str; - if (!parts.is_scheme_wildcard) - str += parts.scheme + url::kStandardSchemeSeparator; + + if (!parts.is_scheme_wildcard) { + str += parts.scheme; + str += url::kStandardSchemeSeparator; + } if (parts.scheme == url::kFileScheme) { - if (parts.is_path_wildcard) - return str + kUrlPathSeparator + kPathWildcard; - return str + parts.path; + if (parts.is_path_wildcard) { + str += kUrlPathSeparator; + str += kPathWildcard; + return str; + } + str += parts.path; + return str; } if (parts.has_domain_wildcard) { @@ -224,12 +214,16 @@ str += parts.host; if (ContentSettingsPattern::IsNonWildcardDomainNonPortScheme(parts.scheme)) { - str += parts.path.empty() ? std::string(kUrlPathSeparator) : parts.path; + if (parts.path.empty()) + str += std::string(kUrlPathSeparator); + else + str += parts.path; return str; } if (!parts.is_port_wildcard) { - str += std::string(kUrlPortSeparator) + parts.port; + str += kUrlPortSeparator; + str += parts.port; } return str;
diff --git a/components/content_settings/core/common/content_settings_pattern_parser.h b/components/content_settings/core/common/content_settings_pattern_parser.h index 80f1f3a..3013d63 100644 --- a/components/content_settings/core/common/content_settings_pattern_parser.h +++ b/components/content_settings/core/common/content_settings_pattern_parser.h
@@ -8,13 +8,14 @@ #include <string> #include "base/macros.h" +#include "base/strings/string_piece_forward.h" #include "components/content_settings/core/common/content_settings_pattern.h" namespace content_settings { class PatternParser { public: - static void Parse(const std::string& pattern_spec, + static void Parse(base::StringPiece pattern_spec, ContentSettingsPattern::BuilderInterface* builder); static std::string ToString(
diff --git a/components/content_settings/core/common/content_settings_pattern_parser_unittest.cc b/components/content_settings/core/common/content_settings_pattern_parser_unittest.cc index 4587a06..20c7c7ac0 100644 --- a/components/content_settings/core/common/content_settings_pattern_parser_unittest.cc +++ b/components/content_settings/core/common/content_settings_pattern_parser_unittest.cc
@@ -5,6 +5,7 @@ #include "components/content_settings/core/common/content_settings_pattern.h" #include "components/content_settings/core/common/content_settings_pattern_parser.h" +#include "base/strings/string_piece.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/cronet/BUILD.gn b/components/cronet/BUILD.gn index 1c2feff..794bad1 100644 --- a/components/cronet/BUILD.gn +++ b/components/cronet/BUILD.gn
@@ -79,6 +79,16 @@ } } +source_set("metrics_util") { + sources = [ + "metrics_util.cc", + "metrics_util.h", + ] + deps = [ + "//base", + ] +} + # Unit tests for Cronet common implementation. source_set("cronet_common_unittests") { testonly = true
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn index fbf00e58..e21e8b98 100644 --- a/components/cronet/android/BUILD.gn +++ b/components/cronet/android/BUILD.gn
@@ -154,6 +154,7 @@ "//base/third_party/dynamic_annotations", "//components/cronet:cronet_common", "//components/cronet:cronet_version_header", + "//components/cronet:metrics_util", "//components/cronet/native:cronet_native_impl", "//components/metrics", "//components/prefs", @@ -174,8 +175,6 @@ "//components/cronet/android/cronet_url_request_context_adapter.h", "//components/cronet/android/io_buffer_with_byte_buffer.cc", "//components/cronet/android/io_buffer_with_byte_buffer.h", - "//components/cronet/android/metrics_util.cc", - "//components/cronet/android/metrics_util.h", "//components/cronet/android/url_request_error.cc", "//components/cronet/android/url_request_error.h", _jni_registration_header,
diff --git a/components/cronet/android/cronet_bidirectional_stream_adapter.cc b/components/cronet/android/cronet_bidirectional_stream_adapter.cc index 0801a20..17570231 100644 --- a/components/cronet/android/cronet_bidirectional_stream_adapter.cc +++ b/components/cronet/android/cronet_bidirectional_stream_adapter.cc
@@ -14,8 +14,8 @@ #include "base/strings/string_number_conversions.h" #include "components/cronet/android/cronet_url_request_context_adapter.h" #include "components/cronet/android/io_buffer_with_byte_buffer.h" -#include "components/cronet/android/metrics_util.h" #include "components/cronet/android/url_request_error.h" +#include "components/cronet/metrics_util.h" #include "jni/CronetBidirectionalStream_jni.h" #include "net/base/net_errors.h" #include "net/base/request_priority.h" @@ -27,7 +27,7 @@ #include "net/http/http_util.h" #include "net/ssl/ssl_info.h" #include "net/third_party/quic/core/quic_packets.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/url_request/http_user_agent_settings.h" #include "net/url_request/url_request_context.h" #include "url/gurl.h"
diff --git a/components/cronet/android/cronet_url_request_adapter.cc b/components/cronet/android/cronet_url_request_adapter.cc index de1b32a..59720dd 100644 --- a/components/cronet/android/cronet_url_request_adapter.cc +++ b/components/cronet/android/cronet_url_request_adapter.cc
@@ -13,8 +13,8 @@ #include "base/logging.h" #include "components/cronet/android/cronet_url_request_context_adapter.h" #include "components/cronet/android/io_buffer_with_byte_buffer.h" -#include "components/cronet/android/metrics_util.h" #include "components/cronet/android/url_request_error.h" +#include "components/cronet/metrics_util.h" #include "jni/CronetUrlRequest_jni.h" #include "net/base/load_flags.h" #include "net/base/load_states.h"
diff --git a/components/cronet/android/metrics_util.h b/components/cronet/android/metrics_util.h deleted file mode 100644 index 89d2d73c8..0000000 --- a/components/cronet/android/metrics_util.h +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_CRONET_ANDROID_CRONET_METRICS_UTIL_H_ -#define COMPONENTS_CRONET_ANDROID_CRONET_METRICS_UTIL_H_ - -#include <stdint.h> - -#include "base/time/time.h" - -namespace cronet { - -namespace metrics_util { - -// Converts timing metrics stored as TimeTicks into the format expected by the -// Java layer: ms since Unix epoch, or -1 for null -int64_t ConvertTime(const base::TimeTicks& ticks, - const base::TimeTicks& start_ticks, - const base::Time& start_time); -} // namespace metrics_util - -} // namespace cronet - -#endif // COMPONENTS_CRONET_ANDROID_CRONET_METRICS_UTIL_H_
diff --git a/components/cronet/android/sample/AndroidManifest.xml b/components/cronet/android/sample/AndroidManifest.xml index 79f6bcc..d1dd142 100644 --- a/components/cronet/android/sample/AndroidManifest.xml +++ b/components/cronet/android/sample/AndroidManifest.xml
@@ -9,7 +9,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.cronet_sample_apk"> - <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" /> + <!-- //components/cronet still needs to support Jelly Bean. See crbug.com/922656 --> + <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <application android:name="CronetSampleApplication"
diff --git a/components/cronet/android/sample/javatests/AndroidManifest.xml b/components/cronet/android/sample/javatests/AndroidManifest.xml index 1b07d9c..5d3ad5e3 100644 --- a/components/cronet/android/sample/javatests/AndroidManifest.xml +++ b/components/cronet/android/sample/javatests/AndroidManifest.xml
@@ -8,7 +8,8 @@ doesn't ignore this. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.cronet_sample_apk.tests"> - <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" /> + <!-- //components/cronet still needs to support Jelly Bean. See crbug.com/922656 --> + <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /> <!-- We add an application tag here just so that we can indicate that this package needs to link against the android.test library, which is
diff --git a/components/cronet/android/test/javaperftests/AndroidManifest.xml b/components/cronet/android/test/javaperftests/AndroidManifest.xml index 166e3e2..c7cd37c 100644 --- a/components/cronet/android/test/javaperftests/AndroidManifest.xml +++ b/components/cronet/android/test/javaperftests/AndroidManifest.xml
@@ -1,7 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.net"> - <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" /> + <!-- //components/cronet still needs to support Jelly Bean. See crbug.com/922656 --> + <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
diff --git a/components/cronet/android/test/javatests/AndroidManifest.xml b/components/cronet/android/test/javatests/AndroidManifest.xml index 3bfcb46..af6ac00 100644 --- a/components/cronet/android/test/javatests/AndroidManifest.xml +++ b/components/cronet/android/test/javatests/AndroidManifest.xml
@@ -6,7 +6,8 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.net.tests"> - <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="24" /> + <!-- //components/cronet still needs to support Jelly Bean. See crbug.com/922656 --> + <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="24" /> <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
diff --git a/components/cronet/android/metrics_util.cc b/components/cronet/metrics_util.cc similarity index 89% rename from components/cronet/android/metrics_util.cc rename to components/cronet/metrics_util.cc index de18baa..1a0d731 100644 --- a/components/cronet/android/metrics_util.cc +++ b/components/cronet/metrics_util.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/cronet/android/metrics_util.h" +#include "components/cronet/metrics_util.h" #include "base/logging.h" @@ -14,7 +14,7 @@ const base::TimeTicks& start_ticks, const base::Time& start_time) { if (ticks.is_null() || start_ticks.is_null()) { - return -1; + return kNullTime; } DCHECK(!start_time.is_null()); return (start_time + (ticks - start_ticks)).ToJavaTime();
diff --git a/components/cronet/metrics_util.h b/components/cronet/metrics_util.h new file mode 100644 index 0000000..f381c48 --- /dev/null +++ b/components/cronet/metrics_util.h
@@ -0,0 +1,46 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CRONET_METRICS_UTIL_H_ +#define COMPONENTS_CRONET_METRICS_UTIL_H_ + +#include <stdint.h> + +#include "base/time/time.h" + +namespace cronet { + +namespace metrics_util { + +constexpr int64_t kNullTime = -1; + +// Converts timing metrics stored as TimeTicks into the format expected by the +// API layer: ms since Unix epoch, or kNullTime for null (if either |ticks| or +// |start_ticks| is null). +// +// By calculating time values using a base (|start_ticks|, |start_time|) pair, +// time values are normalized. This allows time deltas between pairs of events +// to be accurately computed, even if the system clock changed between those +// events, as long as times for both events were calculated using the same +// (|start_ticks|, |start_time|) pair. +// +// Args: +// +// ticks: The ticks value corresponding to the time of the event -- the returned +// time corresponds to this event. +// +// start_ticks: The ticks measurement at some base time -- the ticks equivalent +// of start_time. Should be smaller than ticks. +// +// start_time: Time measurement at some base time -- the time equivalent of +// start_ticks. Must not be null. +int64_t ConvertTime(const base::TimeTicks& ticks, + const base::TimeTicks& start_ticks, + const base::Time& start_time); + +} // namespace metrics_util + +} // namespace cronet + +#endif // COMPONENTS_CRONET_METRICS_UTIL_H_
diff --git a/components/cronet/native/url_request.cc b/components/cronet/native/url_request.cc index 98c645f..1688f23 100644 --- a/components/cronet/native/url_request.cc +++ b/components/cronet/native/url_request.cc
@@ -434,7 +434,7 @@ return IsDoneLocked(); } -bool Cronet_UrlRequestImpl::IsDoneLocked() { +bool Cronet_UrlRequestImpl::IsDoneLocked() const { lock_.AssertAcquired(); return started_ && request_ == nullptr; }
diff --git a/components/cronet/native/url_request.h b/components/cronet/native/url_request.h index e3936b1a..08ba896 100644 --- a/components/cronet/native/url_request.h +++ b/components/cronet/native/url_request.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" +#include "base/thread_annotations.h" #include "components/cronet/cronet_url_request.h" #include "components/cronet/cronet_url_request_context.h" #include "components/cronet/native/generated/cronet.idl_impl_interface.h" @@ -53,7 +54,7 @@ // Return |true| if request has started and is now done. // Must be called under |lock_| held. - bool IsDoneLocked(); + bool IsDoneLocked() const SHARED_LOCKS_REQUIRED(lock_); // Helper method to set final status of CronetUrlRequest and clean up the // native request adapter. Returns true if request is already done, false @@ -65,7 +66,8 @@ // native request adapter. Returns true if request is already done, false // request is not done and is destroyed. Must be called under |lock_| held. bool DestroyRequestUnlessDoneLocked( - Cronet_RequestFinishedInfo_FINISHED_REASON finished_reason); + Cronet_RequestFinishedInfo_FINISHED_REASON finished_reason) + EXCLUSIVE_LOCKS_REQUIRED(lock_); // Helper method to post |task| to the |executor_|. void PostTaskToExecutor(base::OnceClosure task); @@ -90,14 +92,15 @@ base::Lock lock_; // NetworkTask object lives on the network thread. Owned by |request_|. // Outlives this. - NetworkTasks* network_tasks_ = nullptr; + NetworkTasks* network_tasks_ GUARDED_BY(lock_) = nullptr; // Cronet URLRequest used for this operation. - CronetURLRequest* request_ = nullptr; - bool started_ = false; - bool waiting_on_redirect_ = false; - bool waiting_on_read_ = false; + CronetURLRequest* request_ GUARDED_BY(lock_) = nullptr; + bool started_ GUARDED_BY(lock_) = false; + bool waiting_on_redirect_ GUARDED_BY(lock_) = false; + bool waiting_on_read_ GUARDED_BY(lock_) = false; // Set of status_listeners_ that have not yet been called back. - std::unordered_multiset<Cronet_UrlRequestStatusListenerPtr> status_listeners_; + std::unordered_multiset<Cronet_UrlRequestStatusListenerPtr> status_listeners_ + GUARDED_BY(lock_); // Response info updated by callback with number of bytes received. May be // nullptr, if no response has been received.
diff --git a/components/dom_distiller/content/browser/distillable_page_utils.cc b/components/dom_distiller/content/browser/distillable_page_utils.cc index ed5dfdc1..c210a395 100644 --- a/components/dom_distiller/content/browser/distillable_page_utils.cc +++ b/components/dom_distiller/content/browser/distillable_page_utils.cc
@@ -4,6 +4,8 @@ #include "components/dom_distiller/content/browser/distillable_page_utils.h" +#include <string> + #include "base/bind.h" #include "base/location.h" #include "base/single_thread_task_runner.h" @@ -17,15 +19,18 @@ #include "components/dom_distiller/core/page_features.h" #include "components/grit/components_resources.h" #include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" #include "ui/base/resource/resource_bundle.h" namespace dom_distiller { namespace { + void OnExtractFeaturesJsResult(const DistillablePageDetector* detector, base::Callback<void(bool)> callback, const base::Value* result) { callback.Run(detector->Classify(CalculateDerivedFeaturesFromJSON(result))); } + } // namespace void IsDistillablePageForDetector(content::WebContents* web_contents, @@ -46,12 +51,12 @@ base::Bind(OnExtractFeaturesJsResult, detector, callback)); } -void setDelegate(content::WebContents* web_contents, +void SetDelegate(content::WebContents* web_contents, DistillabilityDelegate delegate) { CHECK(web_contents); DistillabilityDriver::CreateForWebContents(web_contents); - DistillabilityDriver *driver = + DistillabilityDriver* driver = DistillabilityDriver::FromWebContents(web_contents); CHECK(driver); driver->SetDelegate(delegate);
diff --git a/components/dom_distiller/content/browser/distillable_page_utils.h b/components/dom_distiller/content/browser/distillable_page_utils.h index e6f31c5..632fff0c 100644 --- a/components/dom_distiller/content/browser/distillable_page_utils.h +++ b/components/dom_distiller/content/browser/distillable_page_utils.h
@@ -6,7 +6,10 @@ #define COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_DISTILLABLE_PAGE_UTILS_H_ #include "base/callback.h" -#include "content/public/browser/web_contents.h" + +namespace content { +class WebContents; +} // namespace content namespace dom_distiller { @@ -15,15 +18,22 @@ // Uses the provided DistillablePageDetector to detect if the page is // distillable. The passed detector must be alive until after the callback is // called. +// +// |web_contents| and |detector| must be non-null. void IsDistillablePageForDetector(content::WebContents* web_contents, const DistillablePageDetector* detector, base::Callback<void(bool)> callback); -typedef base::RepeatingCallback<void(bool, bool, bool)> DistillabilityDelegate; - // Set the delegate to receive the result of whether the page is distillable. -void setDelegate(content::WebContents* web_contents, +// +// |web_contents| must be non-null. +using DistillabilityDelegate = + base::RepeatingCallback<void(bool /* is_distillable */, + bool /* is_last */, + bool /* is_mobile_friendly */)>; +void SetDelegate(content::WebContents* web_contents, DistillabilityDelegate delegate); -} + +} // namespace dom_distiller #endif // COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_DISTILLABLE_PAGE_UTILS_H_
diff --git a/components/dom_distiller/content/browser/distillable_page_utils_android.cc b/components/dom_distiller/content/browser/distillable_page_utils_android.cc index 0182c364..fe8f0da 100644 --- a/components/dom_distiller/content/browser/distillable_page_utils_android.cc +++ b/components/dom_distiller/content/browser/distillable_page_utils_android.cc
@@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <memory> - #include "base/bind.h" #include "base/location.h" #include "base/single_thread_task_runner.h" @@ -41,8 +39,8 @@ DistillabilityDelegate delegate = base::Bind( OnIsPageDistillableUpdate, ScopedJavaGlobalRef<jobject>(env, callback)); - setDelegate(web_contents, delegate); + SetDelegate(web_contents, delegate); } -} -} +} // namespace android +} // namespace dom_distiller
diff --git a/components/dom_distiller/content/browser/web_contents_main_frame_observer.h b/components/dom_distiller/content/browser/web_contents_main_frame_observer.h index f8fce2f..2a9af47 100644 --- a/components/dom_distiller/content/browser/web_contents_main_frame_observer.h +++ b/components/dom_distiller/content/browser/web_contents_main_frame_observer.h
@@ -21,11 +21,11 @@ public: ~WebContentsMainFrameObserver() override; - bool is_document_loaded_in_main_frame() { + bool is_document_loaded_in_main_frame() const { return is_document_loaded_in_main_frame_; } - bool is_initialized() { return is_initialized_; } + bool is_initialized() const { return is_initialized_; } // content::WebContentsObserver implementation. void DocumentLoadedInFrame(
diff --git a/components/dom_distiller/content/browser/web_contents_main_frame_observer_unittest.cc b/components/dom_distiller/content/browser/web_contents_main_frame_observer_unittest.cc index 964eedf2..d8a9b64 100644 --- a/components/dom_distiller/content/browser/web_contents_main_frame_observer_unittest.cc +++ b/components/dom_distiller/content/browser/web_contents_main_frame_observer_unittest.cc
@@ -13,6 +13,13 @@ namespace dom_distiller { +// Define named constants to make tests a bit easier to read. +const bool kMainFrame = true; +const bool kChildFrame = false; + +const bool kSameDocument = true; +const bool kDifferentDocument = false; + class WebContentsMainFrameObserverTest : public content::RenderViewHostTestHarness { public: @@ -21,11 +28,10 @@ // This needed to keep the WebContentsObserverSanityChecker checks happy for // when AppendChild is called. NavigateAndCommit(GURL("about:blank")); - dom_distiller::WebContentsMainFrameObserver::CreateForWebContents( - web_contents()); + WebContentsMainFrameObserver::CreateForWebContents(web_contents()); main_frame_observer_ = WebContentsMainFrameObserver::FromWebContents(web_contents()); - ASSERT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); + EXPECT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); } void Navigate(bool main_frame, bool same_document) { @@ -45,58 +51,58 @@ }; TEST_F(WebContentsMainFrameObserverTest, ListensForMainFrameNavigation) { - Navigate(true, false); - ASSERT_TRUE(main_frame_observer_->is_initialized()); - ASSERT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); + Navigate(kMainFrame, kDifferentDocument); + EXPECT_TRUE(main_frame_observer_->is_initialized()); + EXPECT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); main_frame_observer_->DocumentLoadedInFrame(main_rfh()); - ASSERT_TRUE(main_frame_observer_->is_document_loaded_in_main_frame()); + EXPECT_TRUE(main_frame_observer_->is_document_loaded_in_main_frame()); } TEST_F(WebContentsMainFrameObserverTest, IgnoresChildFrameNavigation) { - Navigate(false, false); - ASSERT_FALSE(main_frame_observer_->is_initialized()); - ASSERT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); + Navigate(kChildFrame, kDifferentDocument); + EXPECT_FALSE(main_frame_observer_->is_initialized()); + EXPECT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); } TEST_F(WebContentsMainFrameObserverTest, IgnoresSameDocumentNavigation) { - Navigate(true, true); - ASSERT_FALSE(main_frame_observer_->is_initialized()); - ASSERT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); + Navigate(kMainFrame, kSameDocument); + EXPECT_FALSE(main_frame_observer_->is_initialized()); + EXPECT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); } TEST_F(WebContentsMainFrameObserverTest, IgnoresSameDocumentavigationUnlessMainFrameLoads) { - Navigate(true, true); - ASSERT_FALSE(main_frame_observer_->is_initialized()); - ASSERT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); + Navigate(kMainFrame, kSameDocument); + EXPECT_FALSE(main_frame_observer_->is_initialized()); + EXPECT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); // Even if we didn't acknowledge a same-document navigation, if the main // frame loads, consider a load complete. main_frame_observer_->DocumentLoadedInFrame(main_rfh()); - ASSERT_TRUE(main_frame_observer_->is_document_loaded_in_main_frame()); + EXPECT_TRUE(main_frame_observer_->is_document_loaded_in_main_frame()); } TEST_F(WebContentsMainFrameObserverTest, ResetOnPageNavigation) { - Navigate(true, false); + Navigate(kMainFrame, kDifferentDocument); main_frame_observer_->DocumentLoadedInFrame(main_rfh()); - ASSERT_TRUE(main_frame_observer_->is_document_loaded_in_main_frame()); + EXPECT_TRUE(main_frame_observer_->is_document_loaded_in_main_frame()); // Another navigation should result in waiting for a page load. - Navigate(true, false); - ASSERT_TRUE(main_frame_observer_->is_initialized()); - ASSERT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); + Navigate(kMainFrame, kDifferentDocument); + EXPECT_TRUE(main_frame_observer_->is_initialized()); + EXPECT_FALSE(main_frame_observer_->is_document_loaded_in_main_frame()); } TEST_F(WebContentsMainFrameObserverTest, DoesNotResetOnInPageNavigation) { - Navigate(true, false); + Navigate(kMainFrame, kDifferentDocument); main_frame_observer_->DocumentLoadedInFrame(main_rfh()); - ASSERT_TRUE(main_frame_observer_->is_document_loaded_in_main_frame()); + EXPECT_TRUE(main_frame_observer_->is_document_loaded_in_main_frame()); // Navigating withing the page should not result in waiting for a page load. - Navigate(true, true); - ASSERT_TRUE(main_frame_observer_->is_initialized()); - ASSERT_TRUE(main_frame_observer_->is_document_loaded_in_main_frame()); + Navigate(kMainFrame, kSameDocument); + EXPECT_TRUE(main_frame_observer_->is_initialized()); + EXPECT_TRUE(main_frame_observer_->is_document_loaded_in_main_frame()); } } // namespace dom_distiller
diff --git a/components/download/quarantine/common_mac.h b/components/download/quarantine/common_mac.h index 3d51b1c..179bb13 100644 --- a/components/download/quarantine/common_mac.h +++ b/components/download/quarantine/common_mac.h
@@ -15,10 +15,6 @@ namespace download { -bool GetQuarantinePropertiesDeprecated( - const base::FilePath& file, - base::scoped_nsobject<NSMutableDictionary>* properties); - bool GetQuarantineProperties( const base::FilePath& file, base::scoped_nsobject<NSMutableDictionary>* properties);
diff --git a/components/download/quarantine/common_mac.mm b/components/download/quarantine/common_mac.mm index 3682e0a..a8ccaeba 100644 --- a/components/download/quarantine/common_mac.mm +++ b/components/download/quarantine/common_mac.mm
@@ -17,46 +17,6 @@ namespace download { -// Once Chrome no longer supports macOS 10.9, this code will no longer be -// necessary. Note that LSCopyItemAttribute was deprecated in macOS 10.8, but -// the replacement to kLSItemQuarantineProperties did not exist until macOS -// 10.10. -#if !defined(MAC_OS_X_VERSION_10_10) || \ - MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10 -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -bool GetQuarantinePropertiesDeprecated( - const base::FilePath& file, - base::scoped_nsobject<NSMutableDictionary>* properties) { - const UInt8* path = reinterpret_cast<const UInt8*>(file.value().c_str()); - FSRef file_ref; - if (FSPathMakeRef(path, &file_ref, nullptr) != noErr) - return false; - - base::ScopedCFTypeRef<CFTypeRef> quarantine_properties; - OSStatus status = - LSCopyItemAttribute(&file_ref, kLSRolesAll, kLSItemQuarantineProperties, - quarantine_properties.InitializeInto()); - if (status != noErr) - return true; - - CFDictionaryRef quarantine_properties_dict = - base::mac::CFCast<CFDictionaryRef>(quarantine_properties.get()); - if (!quarantine_properties_dict) { - LOG(WARNING) << "kLSItemQuarantineProperties is not a dictionary on file " - << file.value(); - return false; - } - - properties->reset( - [base::mac::CFToNSCast(quarantine_properties_dict) mutableCopy]); - return true; -} - -#pragma clang diagnostic pop -#endif - -API_AVAILABLE(macos(10.10)) bool GetQuarantineProperties( const base::FilePath& file, base::scoped_nsobject<NSMutableDictionary>* properties) {
diff --git a/components/download/quarantine/quarantine_mac.mm b/components/download/quarantine/quarantine_mac.mm index b4a3341..c43cac8 100644 --- a/components/download/quarantine/quarantine_mac.mm +++ b/components/download/quarantine/quarantine_mac.mm
@@ -23,34 +23,6 @@ namespace { -// Once Chrome no longer supports macOS 10.9, this code will no longer be -// necessary. Note that LSCopyItemAttribute was deprecated in macOS 10.8, but -// the replacement to kLSItemQuarantineProperties did not exist until macOS -// 10.10. -#if !defined(MAC_OS_X_VERSION_10_10) || \ - MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10 -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -bool SetQuarantinePropertiesDeprecated(const base::FilePath& file, - NSDictionary* properties) { - const UInt8* path = reinterpret_cast<const UInt8*>(file.value().c_str()); - FSRef file_ref; - if (FSPathMakeRef(path, &file_ref, nullptr) != noErr) - return false; - - OSStatus os_error = LSSetItemAttribute( - &file_ref, kLSRolesAll, kLSItemQuarantineProperties, properties); - if (os_error != noErr) { - OSSTATUS_LOG(WARNING, os_error) - << "Unable to set quarantine attributes on file " << file.value(); - return false; - } - return true; -} -#pragma clang diagnostic pop -#endif - -API_AVAILABLE(macos(10.10)) bool SetQuarantineProperties(const base::FilePath& file, NSDictionary* properties) { base::scoped_nsobject<NSURL> file_url([[NSURL alloc] @@ -170,12 +142,7 @@ const GURL& referrer) { base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); base::scoped_nsobject<NSMutableDictionary> properties; - bool success = false; - if (@available(macos 10.10, *)) { - success = GetQuarantineProperties(file, &properties); - } else { - success = GetQuarantinePropertiesDeprecated(file, &properties); - } + bool success = GetQuarantineProperties(file, &properties); if (!success) return false; @@ -213,11 +180,7 @@ [properties setValue:origin_url forKey:(NSString*)kLSQuarantineDataURLKey]; } - if (@available(macos 10.10, *)) { - return SetQuarantineProperties(file, properties); - } else { - return SetQuarantinePropertiesDeprecated(file, properties); - } + return SetQuarantineProperties(file, properties); } } // namespace
diff --git a/components/download/quarantine/test_support_mac.mm b/components/download/quarantine/test_support_mac.mm index a1ebbd6d..7158aba6 100644 --- a/components/download/quarantine/test_support_mac.mm +++ b/components/download/quarantine/test_support_mac.mm
@@ -26,11 +26,7 @@ return false; base::scoped_nsobject<NSMutableDictionary> properties; - bool success = false; - if (@available(macos 10.10, *)) - success = GetQuarantineProperties(file, &properties); - else - success = GetQuarantinePropertiesDeprecated(file, &properties); + bool success = GetQuarantineProperties(file, &properties); if (!success || !properties) return false;
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc index 89a3b12..275784e 100644 --- a/components/exo/client_controlled_shell_surface_unittest.cc +++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -16,7 +16,7 @@ #include "ash/shell_test_api.h" #include "ash/system/unified/unified_system_tray.h" #include "ash/wm/drag_window_resizer.h" -#include "ash/wm/overview/window_selector_controller.h" +#include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h" @@ -1117,7 +1117,7 @@ // FLING the window not inisde preview area with large enough y veloicty // (larger than kFlingToOverviewThreshold) will drop the window into overview. - EXPECT_FALSE(shell->window_selector_controller()->IsSelecting()); + EXPECT_FALSE(shell->overview_controller()->IsSelecting()); end = gfx::Point(400, 210); const base::TimeDelta duration = event_generator->CalculateScrollDurationForFlingVelocity( @@ -1125,16 +1125,16 @@ ash::TabletModeWindowDragDelegate::kFlingToOverviewThreshold + 10.f, 200); event_generator->GestureScrollSequence(start, end, duration, 200); - EXPECT_TRUE(shell->window_selector_controller()->IsSelecting()); - EXPECT_TRUE(shell->window_selector_controller() - ->window_selector() - ->IsWindowInOverview(window)); + EXPECT_TRUE(shell->overview_controller()->IsSelecting()); + EXPECT_TRUE( + shell->overview_controller()->overview_session()->IsWindowInOverview( + window)); // Drag the window long enough (pass one fourth of the screen vertical // height) to snap the window to splitscreen. end = gfx::Point(0, 210); - shell->window_selector_controller()->ToggleOverview(); - EXPECT_FALSE(shell->window_selector_controller()->IsSelecting()); + shell->overview_controller()->ToggleOverview(); + EXPECT_FALSE(shell->overview_controller()->IsSelecting()); EXPECT_TRUE(ash::wm::GetWindowState(window)->IsMaximized()); event_generator->GestureScrollSequence( start, end, base::TimeDelta::FromMilliseconds(100), 20);
diff --git a/components/feed/core/feed_scheduler_host.cc b/components/feed/core/feed_scheduler_host.cc index 68120727..4fd86dc 100644 --- a/components/feed/core/feed_scheduler_host.cc +++ b/components/feed/core/feed_scheduler_host.cc
@@ -316,7 +316,7 @@ user_classifier_.OnEvent(UserClassifier::Event::kSuggestionsViewed); } -void FeedSchedulerHost::OnArticlesCleared(bool suppress_refreshes) { +bool FeedSchedulerHost::OnArticlesCleared(bool suppress_refreshes) { base::TimeDelta attempt_age = clock_->Now() - profile_prefs_->GetTime(prefs::kLastFetchAttemptTime); UMA_HISTOGRAM_CUSTOM_TIMES( @@ -340,8 +340,13 @@ clock_->Now() + base::TimeDelta::FromMinutes(kSuppressRefreshDurationMinutes.Get()); } else if (ShouldRefresh(TriggerType::kNtpShown)) { - refresh_callback_.Run(); + // Instead of using |refresh_callback_|, instead return our desire to + // refresh back up to our caller. This allows more information to be given + // all at once to the Feed which allows it to act more intelligently. + return true; } + + return false; } void FeedSchedulerHost::OnEulaAccepted() {
diff --git a/components/feed/core/feed_scheduler_host.h b/components/feed/core/feed_scheduler_host.h index 086e07c..ca3991b 100644 --- a/components/feed/core/feed_scheduler_host.h +++ b/components/feed/core/feed_scheduler_host.h
@@ -111,8 +111,10 @@ // Should be called when something happens to clear stored articles. The // scheduler updates its internal state and treats this event as a kNtpShown - // trigger. - void OnArticlesCleared(bool suppress_refreshes); + // trigger. Similar to ShouldSessionRequestData(), the scheduler will not + // start a refresh itself during this method. Instead, the caller should check + // the return value, and if true, the caller should start a refresh. + bool OnArticlesCleared(bool suppress_refreshes); private: FRIEND_TEST_ALL_PREFIXES(FeedSchedulerHostTest, GetTriggerThreshold);
diff --git a/components/feed/core/feed_scheduler_host_unittest.cc b/components/feed/core/feed_scheduler_host_unittest.cc index e753572..f236a914 100644 --- a/components/feed/core/feed_scheduler_host_unittest.cc +++ b/components/feed/core/feed_scheduler_host_unittest.cc
@@ -792,7 +792,7 @@ scheduler()->OnForegrounded(); EXPECT_EQ(0, refresh_call_count()); - scheduler()->OnArticlesCleared(/*suppress_refreshes*/ true); + EXPECT_FALSE(scheduler()->OnArticlesCleared(/*suppress_refreshes*/ true)); scheduler()->OnForegrounded(); EXPECT_EQ(0, refresh_call_count()); @@ -823,7 +823,7 @@ kInterestFeedContentSuggestions.name, {{kSuppressRefreshDurationMinutes.name, "100"}}, {kInterestFeedContentSuggestions.name}); - scheduler()->OnArticlesCleared(/*suppress_refreshes*/ true); + EXPECT_FALSE(scheduler()->OnArticlesCleared(/*suppress_refreshes*/ true)); test_clock()->Advance(TimeDelta::FromMinutes(99)); scheduler()->OnForegrounded(); @@ -835,21 +835,17 @@ } TEST_F(FeedSchedulerHostTest, OnArticlesClearedNoSuppress) { + EXPECT_TRUE(scheduler()->OnArticlesCleared(/*suppress_refreshes*/ false)); + scheduler()->OnReceiveNewContent(test_clock()->Now()); + + EXPECT_TRUE(scheduler()->OnArticlesCleared(/*suppress_refreshes*/ false)); + scheduler()->OnReceiveNewContent(test_clock()->Now()); + + EXPECT_FALSE(scheduler()->OnArticlesCleared(/*suppress_refreshes*/ true)); + EXPECT_FALSE(scheduler()->OnArticlesCleared(/*suppress_refreshes*/ false)); + + // OnArticlesCleared() should never trigger the refresh itself. EXPECT_EQ(0, refresh_call_count()); - - scheduler()->OnArticlesCleared(/*suppress_refreshes*/ false); - EXPECT_EQ(1, refresh_call_count()); - scheduler()->OnReceiveNewContent(test_clock()->Now()); - - scheduler()->OnArticlesCleared(/*suppress_refreshes*/ false); - EXPECT_EQ(2, refresh_call_count()); - scheduler()->OnReceiveNewContent(test_clock()->Now()); - - scheduler()->OnArticlesCleared(/*suppress_refreshes*/ true); - EXPECT_EQ(2, refresh_call_count()); - - scheduler()->OnArticlesCleared(/*suppress_refreshes*/ false); - EXPECT_EQ(2, refresh_call_count()); } TEST_F(FeedSchedulerHostTest, OnArticlesClearedIgnoresOutstanding) { @@ -861,8 +857,10 @@ EXPECT_EQ(1, refresh_call_count()); // Clearing articles should disregard the outstanding request logic. - scheduler()->OnArticlesCleared(/*suppress_refreshes*/ false); - EXPECT_EQ(2, refresh_call_count()); + EXPECT_TRUE(scheduler()->OnArticlesCleared(/*suppress_refreshes*/ false)); + // OnArticlesCleared() should have returned true instead of triggering a + // refresh directly. + EXPECT_EQ(1, refresh_call_count()); } TEST_F(FeedSchedulerHostTest, OustandingRequest) {
diff --git a/components/grpc_support/bidirectional_stream.cc b/components/grpc_support/bidirectional_stream.cc index 7141763..7a6e43a 100644 --- a/components/grpc_support/bidirectional_stream.cc +++ b/components/grpc_support/bidirectional_stream.cc
@@ -24,8 +24,8 @@ #include "net/http/http_status_code.h" #include "net/http/http_transaction_factory.h" #include "net/http/http_util.h" -#include "net/third_party/spdy/core/spdy_header_block.h" #include "net/ssl/ssl_info.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/url_request/http_user_agent_settings.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h"
diff --git a/components/grpc_support/bidirectional_stream_c.cc b/components/grpc_support/bidirectional_stream_c.cc index daeca99..b72e7623 100644 --- a/components/grpc_support/bidirectional_stream_c.cc +++ b/components/grpc_support/bidirectional_stream_c.cc
@@ -28,8 +28,8 @@ #include "net/http/http_status_code.h" #include "net/http/http_transaction_factory.h" #include "net/http/http_util.h" -#include "net/third_party/spdy/core/spdy_header_block.h" #include "net/ssl/ssl_info.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/url_request/http_user_agent_settings.h" #include "net/url_request/url_request_context.h" #include "url/gurl.h"
diff --git a/components/heap_profiling/test_driver.cc b/components/heap_profiling/test_driver.cc index e17fe78f..7a6decc 100644 --- a/components/heap_profiling/test_driver.cc +++ b/components/heap_profiling/test_driver.cc
@@ -20,8 +20,8 @@ #include "base/values.h" #include "build/build_config.h" #include "components/heap_profiling/supervisor.h" -#include "components/services/heap_profiling/public/cpp/allocator_shim.h" #include "components/services/heap_profiling/public/cpp/controller.h" +#include "components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h" #include "components/services/heap_profiling/public/cpp/settings.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h"
diff --git a/components/leveldb_proto/BUILD.gn b/components/leveldb_proto/BUILD.gn index 58f080c4..13e078b 100644 --- a/components/leveldb_proto/BUILD.gn +++ b/components/leveldb_proto/BUILD.gn
@@ -14,6 +14,8 @@ sources = [ "internal/leveldb_database.cc", "internal/leveldb_database.h", + "internal/leveldb_proto_feature_list.cc", + "internal/leveldb_proto_feature_list.h", "internal/migration_delegate.h", "internal/proto_database_wrapper.cc", "internal/proto_database_wrapper.h", @@ -64,6 +66,7 @@ testonly = true sources = [ "internal/proto_database_wrapper_unittest.cc", + "internal/shared_proto_database_client_list_unittest.cc", "internal/shared_proto_database_client_unittest.cc", "internal/shared_proto_database_unittest.cc", "internal/unique_proto_database_unittest.cc",
diff --git a/components/leveldb_proto/internal/leveldb_proto_feature_list.cc b/components/leveldb_proto/internal/leveldb_proto_feature_list.cc new file mode 100644 index 0000000..5b302bac --- /dev/null +++ b/components/leveldb_proto/internal/leveldb_proto_feature_list.cc
@@ -0,0 +1,12 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/leveldb_proto/internal/leveldb_proto_feature_list.h" + +namespace leveldb_proto { + +const base::Feature kProtoDBSharedMigration{"ProtoDBSharedMigration", + base::FEATURE_DISABLED_BY_DEFAULT}; + +} // namespace leveldb_proto
diff --git a/components/leveldb_proto/internal/leveldb_proto_feature_list.h b/components/leveldb_proto/internal/leveldb_proto_feature_list.h new file mode 100644 index 0000000..f87217de --- /dev/null +++ b/components/leveldb_proto/internal/leveldb_proto_feature_list.h
@@ -0,0 +1,16 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_LEVELDB_PROTO_INTERNAL_LEVELDB_PROTO_FEATURE_LIST_H_ +#define COMPONENTS_LEVELDB_PROTO_INTERNAL_LEVELDB_PROTO_FEATURE_LIST_H_ + +#include "base/feature_list.h" + +namespace leveldb_proto { + +extern const base::Feature kProtoDBSharedMigration; + +} // namespace leveldb_proto + +#endif // COMPONENTS_LEVELDB_PROTO_FEATURE_LIST_H_ \ No newline at end of file
diff --git a/components/leveldb_proto/internal/shared_proto_database_client_list_unittest.cc b/components/leveldb_proto/internal/shared_proto_database_client_list_unittest.cc new file mode 100644 index 0000000..9583cd7 --- /dev/null +++ b/components/leveldb_proto/internal/shared_proto_database_client_list_unittest.cc
@@ -0,0 +1,66 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/leveldb_proto/public/shared_proto_database_client_list.h" +#include "base/metrics/field_trial.h" +#include "base/metrics/field_trial_params.h" +#include "base/test/mock_entropy_provider.h" +#include "base/test/scoped_feature_list.h" +#include "components/leveldb_proto/internal/leveldb_proto_feature_list.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace leveldb_proto { + +namespace { +const char kTestClientName[] = "TestClientName"; +} + +class SharedProtoDatabaseClientListTest : public testing::Test { + public: + void SetUpExperimentParam(std::string key, std::string value) { + std::map<std::string, std::string> params = { + {"migrate_ClientNameFoo", "true"}, + {"migrate_" + key, value}, + {"migrate_ClientNameBar", "false"}, + }; + + scoped_feature_list_.InitAndEnableFeatureWithParameters( + kProtoDBSharedMigration, params); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +TEST_F(SharedProtoDatabaseClientListTest, ShouldUseSharedDBTest) { + // Parameter value is case sensitive + SetUpExperimentParam(kTestClientName, "true"); + + bool use_shared = + SharedProtoDatabaseClientList::ShouldUseSharedDB(kTestClientName); + + ASSERT_TRUE(use_shared); +} + +TEST_F(SharedProtoDatabaseClientListTest, + ShouldUseSharedDBTest_OnlyWhenParamMatchesName) { + SetUpExperimentParam("AnotherClientName", "true"); + + bool use_shared = + SharedProtoDatabaseClientList::ShouldUseSharedDB(kTestClientName); + + ASSERT_FALSE(use_shared); +} + +TEST_F(SharedProtoDatabaseClientListTest, + ShouldUseSharedDBTest_OnlyWhenParamValueIsTrue) { + SetUpExperimentParam(kTestClientName, "false"); + + bool use_shared = + SharedProtoDatabaseClientList::ShouldUseSharedDB(kTestClientName); + + ASSERT_FALSE(use_shared); +} + +} // namespace leveldb_proto
diff --git a/components/leveldb_proto/public/shared_proto_database_client_list.cc b/components/leveldb_proto/public/shared_proto_database_client_list.cc index e5ff035..ccb7b6e7 100644 --- a/components/leveldb_proto/public/shared_proto_database_client_list.cc +++ b/components/leveldb_proto/public/shared_proto_database_client_list.cc
@@ -8,16 +8,27 @@ #include <string> +#include "base/metrics/field_trial_params.h" #include "base/stl_util.h" +#include "components/leveldb_proto/internal/leveldb_proto_feature_list.h" + namespace leveldb_proto { +const char* const kDBNameParamPrefix = "migrate_"; + // static bool SharedProtoDatabaseClientList::ShouldUseSharedDB( const std::string& client_name) { - // TODO(thildebr): Make this check variations flags instead of just returning - // false. - return false; + if (!base::FeatureList::IsEnabled(kProtoDBSharedMigration)) + return false; + + std::map<std::string, std::string> params; + if (!base::GetFieldTrialParamsByFeature(kProtoDBSharedMigration, ¶ms)) + return false; + + return base::GetFieldTrialParamByFeatureAsBool( + kProtoDBSharedMigration, kDBNameParamPrefix + client_name, false); } } // namespace leveldb_proto \ No newline at end of file
diff --git a/components/management_strings.grdp b/components/management_strings.grdp index 316f935c..ed0c163 100644 --- a/components/management_strings.grdp +++ b/components/management_strings.grdp
@@ -21,6 +21,9 @@ <message name="IDS_MANAGEMENT_DEVICE_REPORTING" desc="Title of the types of device reporting section of the page" translateable="false"> Device reporting </message> + <message name="IDS_MANAGEMENT_BROWSER_REPORTING" desc="Title of the types of browser reporting section of the page" translateable="false"> + Browser reporting + </message> <message name="IDS_MANAGEMENT_DEVICE_CONFIGURATION" desc="Message telling users that their administrator has set some specific policies on their device" translateable="false"> Your device has been configured to: </message> @@ -62,6 +65,33 @@ <message name="IDS_MANAGEMENT_DESKTOP_MONITORING_NOTICE" desc="Message explaining that the administrators have ways to monitor users outside of chrome's control" translateable="false"> Administrators may have other ways of monitoring users, outside of Chrome. </message> + <message name="IDS_MANAGEMENT_EXTENSION_REPORT_MACHINE_NAME" desc="Message explaining that an extension currently reports the user's machine name" translateable="false"> + Report your machine's name + </message> + <message name="IDS_MANAGEMENT_EXTENSION_REPORT_MACHINE_NAME_ADDRESS" desc="Message explaining that an extension currently reports the user's machine name and address" translateable="false"> + Report your machine's name and network address + </message> + <message name="IDS_MANAGEMENT_EXTENSION_REPORT_USERNAME" desc="Message explaining that an extension currently reports the user's username" translateable="false"> + Report you OS and browser usernames + </message> + <message name="IDS_MANAGEMENT_EXTENSION_REPORT_VERSION" desc="Message explaining that an extension currently reports the user's browser and machine version" translateable="false"> + Report software version information about your browser and machine + </message> + <message name="IDS_MANAGEMENT_EXTENSION_REPORT_POLICIES" desc="Message explaining that an extension currently reports the user's enterprise policies" translateable="false"> + Report information about applied enterprise policies + </message> + <message name="IDS_MANAGEMENT_EXTENSION_REPORT_EXTENSIONS_PLUGINS" desc="Message explaining that an extension currently reports the user's exensions and plugins" translateable="false"> + Report installed extensions and plugins + </message> + <message name="IDS_MANAGEMENT_EXTENSION_REPORT_SAFE_BROWSING_WARNINGS" desc="Message explaining that an extension currently reports the user's safe browsing warnings and ignored warnings" translateable="false"> + Report Safe Browsing warnings + </message> + <message name="IDS_MANAGEMENT_EXTENSION_REPORT_PERF_CRASH" desc="Message explaining that an extension currently reports the user's performance data and crash report" translateable="false"> + Report performance data and crash reports + </message> + <message name="IDS_MANAGEMENT_EXTENSION_REPORT_WEBSITE_USAGE_STATISTICS" desc="Message explaining that an extension currently reports the user's website usage statistics" translateable="false"> + Report how much time you spend on each website + </message> <if expr="chromeos"> <message name="IDS_MANAGEMENT_TRUST_ROOTS_CONFIGURED" desc="Message describing that the administrators have installed their own certificates" translateable="false"> Your account/device has been configured with local trust roots, which might allow administrators to see the contents of websites that you visit
diff --git a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/FakeModuleInstallerBackend.java b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/FakeModuleInstallerBackend.java index 749416dc..84785b3 100644 --- a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/FakeModuleInstallerBackend.java +++ b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/FakeModuleInstallerBackend.java
@@ -5,6 +5,7 @@ package org.chromium.components.module_installer; import android.content.Context; +import android.content.pm.PackageManager; import com.google.android.play.core.splitcompat.SplitCompat; import com.google.android.play.core.splitcompat.ingestion.Verifier; @@ -93,8 +94,12 @@ } // Check that the module's signature matches Chrome's. - Verifier verifier = new Verifier(context); - if (!verifier.verifySplits()) { + try { + Verifier verifier = new Verifier(context); + if (!verifier.verifySplits()) { + return false; + } + } catch (IOException | PackageManager.NameNotFoundException e) { return false; }
diff --git a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java index cb090ea..18ee5fd2 100644 --- a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java +++ b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java
@@ -13,10 +13,11 @@ import org.chromium.base.ContextUtils; import org.chromium.base.Log; +import org.chromium.base.metrics.RecordHistogram; import org.chromium.components.module_installer.ModuleInstallerBackend.OnFinishedListener; -import java.util.Arrays; import java.util.Collections; +import java.util.List; /** * Backend that uses the Play Core SDK to download a module from Play and install it subsequently. @@ -27,6 +28,16 @@ private final SplitInstallManager mManager; private boolean mIsClosed; + // FeatureModuleInstallStatus defined in //tools/metrics/histograms/enums.xml. + // These values are persisted to logs. Entries should not be renumbered and numeric values + // should never be reused. + private static final int INSTALL_STATUS_SUCCESS = 0; + private static final int INSTALL_STATUS_FAILURE = 1; + private static final int INSTALL_STATUS_REQUEST_ERROR = 2; + private static final int INSTALL_STATUS_CANCELLATION = 3; + // Keep this one at the end and increment appropriately when adding new status. + private static final int INSTALL_STATUS_COUNT = 4; + public PlayCoreModuleInstallerBackend(OnFinishedListener listener) { super(listener); mManager = SplitInstallManagerFactory.create(ContextUtils.getApplicationContext()); @@ -42,7 +53,7 @@ Log.e(TAG, "Failed to request module '%s': error code %s", moduleName, errorCode); // If we reach this error condition |onStateUpdate| won't be called. Thus, call // |onFinished| here. - onFinished(false, Arrays.asList(moduleName)); + finish(false, Collections.singletonList(moduleName), INSTALL_STATUS_REQUEST_ERROR); }); } @@ -64,14 +75,25 @@ assert !mIsClosed; switch (state.status()) { case SplitInstallSessionStatus.INSTALLED: - onFinished(true, state.moduleNames()); + finish(true, state.moduleNames(), INSTALL_STATUS_SUCCESS); break; case SplitInstallSessionStatus.CANCELED: case SplitInstallSessionStatus.FAILED: Log.e(TAG, "Failed to install modules '%s': error code %s", state.moduleNames(), state.status()); - onFinished(false, state.moduleNames()); + int status = state.status() == SplitInstallSessionStatus.CANCELED + ? INSTALL_STATUS_CANCELLATION + : INSTALL_STATUS_FAILURE; + finish(false, state.moduleNames(), status); break; } } + + private void finish(boolean success, List<String> moduleNames, int eventId) { + for (String name : moduleNames) { + RecordHistogram.recordEnumeratedHistogram( + "Android.FeatureModules.InstallStatus." + name, eventId, INSTALL_STATUS_COUNT); + } + onFinished(success, moduleNames); + } }
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc index 95e2d11..b537ddc 100644 --- a/components/network_session_configurator/browser/network_session_configurator.cc +++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -28,7 +28,7 @@ #include "net/quic/quic_utils_chromium.h" #include "net/spdy/spdy_session_pool.h" #include "net/third_party/quic/core/quic_packets.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #if defined(OS_MACOSX) && !defined(OS_IOS) #include "base/mac/mac_util.h"
diff --git a/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/components/network_session_configurator/browser/network_session_configurator_unittest.cc index 1f3c98b7..a072f84 100644 --- a/components/network_session_configurator/browser/network_session_configurator_unittest.cc +++ b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -21,7 +21,7 @@ #include "net/http/http_stream_factory.h" #include "net/third_party/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quic/core/quic_packets.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/url_request/url_request_context_builder.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/omnibox/browser/location_bar_model_delegate.cc b/components/omnibox/browser/location_bar_model_delegate.cc index ce31556..4f01f6c1 100644 --- a/components/omnibox/browser/location_bar_model_delegate.cc +++ b/components/omnibox/browser/location_bar_model_delegate.cc
@@ -4,6 +4,10 @@ #include "components/omnibox/browser/location_bar_model_delegate.h" +bool LocationBarModelDelegate::ShouldPreventElision() const { + return false; +} + bool LocationBarModelDelegate::ShouldDisplayURL() const { return true; }
diff --git a/components/omnibox/browser/location_bar_model_delegate.h b/components/omnibox/browser/location_bar_model_delegate.h index 09904aa..7de779b 100644 --- a/components/omnibox/browser/location_bar_model_delegate.h +++ b/components/omnibox/browser/location_bar_model_delegate.h
@@ -36,6 +36,10 @@ // exists. Otherwise returns false and leaves |url| unmodified. virtual bool GetURL(GURL* url) const = 0; + // Returns whether we should prevent elision of the display URL and turn off + // query in omnibox. Based on whether user has a specified extension enabled. + virtual bool ShouldPreventElision() const; + // Returns whether the URL for the current navigation entry should be // in the location bar. virtual bool ShouldDisplayURL() const;
diff --git a/components/omnibox/browser/location_bar_model_impl.cc b/components/omnibox/browser/location_bar_model_impl.cc index 377bd973..1683ff03 100644 --- a/components/omnibox/browser/location_bar_model_impl.cc +++ b/components/omnibox/browser/location_bar_model_impl.cc
@@ -48,6 +48,11 @@ url_formatter::FormatUrlTypes format_types = url_formatter::kFormatUrlOmitDefaults; + // Early exit to prevent elision of URLs when relevant extension is enabled. + if (delegate_->ShouldPreventElision()) { + return GetFormattedURL(format_types); + } + #if defined(OS_IOS) format_types |= url_formatter::kFormatUrlTrimAfterHost; #endif @@ -102,7 +107,8 @@ } bool LocationBarModelImpl::GetDisplaySearchTerms(base::string16* search_terms) { - if (!base::FeatureList::IsEnabled(omnibox::kQueryInOmnibox)) + if (!base::FeatureList::IsEnabled(omnibox::kQueryInOmnibox) || + delegate_->ShouldPreventElision()) return false; // Only show the search terms if the site is secure. However, make an
diff --git a/components/omnibox/browser/location_bar_model_impl_unittest.cc b/components/omnibox/browser/location_bar_model_impl_unittest.cc index 7dea081..1d3c926 100644 --- a/components/omnibox/browser/location_bar_model_impl_unittest.cc +++ b/components/omnibox/browser/location_bar_model_impl_unittest.cc
@@ -18,6 +18,9 @@ class FakeLocationBarModelDelegate : public LocationBarModelDelegate { public: void SetURL(const GURL& url) { url_ = url; } + void SetShouldPreventElision(bool should_prevent_elision) { + should_prevent_elision_ = should_prevent_elision; + } void SetSecurityInfo(const security_state::SecurityInfo& info) { security_info_ = info; } @@ -34,6 +37,8 @@ return true; } + bool ShouldPreventElision() const override { return should_prevent_elision_; } + void GetSecurityInfo(security_state::SecurityInfo* result) const override { *result = security_info_; } @@ -50,6 +55,7 @@ GURL url_; security_state::SecurityInfo security_info_; TestOmniboxClient omnibox_client_; + bool should_prevent_elision_ = false; }; class LocationBarModelImplTest : public testing::Test { @@ -86,6 +92,28 @@ model()->GetURLForDisplay()); } +TEST_F(LocationBarModelImplTest, PreventElisionWorks) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + {omnibox::kHideSteadyStateUrlScheme, + omnibox::kHideSteadyStateUrlTrivialSubdomains, omnibox::kQueryInOmnibox}, + {}); + + delegate()->SetShouldPreventElision(true); + delegate()->SetURL(GURL("https://www.google.com/search?q=foo+query+unelide")); + + EXPECT_EQ(base::ASCIIToUTF16( + "https://www.google.com/search?q=foo+query+unelide/TestSuffix"), + model()->GetURLForDisplay()); + + // Verify that query in omnibox is turned off. + security_state::SecurityInfo info; + info.connection_info_initialized = true; + info.security_level = security_state::SecurityLevel::SECURE; + delegate()->SetSecurityInfo(info); + EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr)); +} + TEST_F(LocationBarModelImplTest, QueryInOmniboxFeatureFlagWorks) { delegate()->SetURL(kValidSearchResultsPage); security_state::SecurityInfo info;
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc index f7bd5ce..a8f1623 100644 --- a/components/omnibox/browser/omnibox_edit_model.cc +++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -232,12 +232,6 @@ bool OmniboxEditModel::ResetDisplayTexts() { const base::string16 old_display_text = GetPermanentDisplayText(); - // Track if the user has modified the text. This is different from - // |user_input_in_progress_| because we care if the user has actually - // modified the text, while |user_input_in_progress_| may be true even if - // the user has merely made a partial selection. - bool user_has_modified_text = view_->GetText() != old_display_text; - LocationBarModel* location_bar_model = controller()->GetLocationBarModel(); url_for_editing_ = location_bar_model->GetFormattedFullURL(); @@ -266,7 +260,7 @@ // URL" (which sounds as if it might be persistent) from seeing just that URL // forever afterwards. return (GetPermanentDisplayText() != old_display_text) && - (!has_focus() || (!user_has_modified_text && !PopupIsOpen())); + (!has_focus() || (!user_input_in_progress_ && !PopupIsOpen())); } GURL OmniboxEditModel::PermanentURL() const { @@ -275,9 +269,6 @@ } base::string16 OmniboxEditModel::GetPermanentDisplayText() const { - if (user_input_in_progress_) - return url_for_editing_; - return display_text_; } @@ -308,7 +299,6 @@ location_bar_model->GetDisplaySearchTerms(nullptr)) return false; - SetUserText(url_for_editing_); view_->SetWindowTextAndCaretPos(url_for_editing_, 0, false, false); // Select all in reverse to ensure the beginning of the URL is shown. @@ -366,7 +356,7 @@ // If the user has not modified the display text and is copying the whole // display text, copy the omnibox contents as a hyperlink to the current page. - if (!user_input_in_progress_ && *text == GetPermanentDisplayText()) { + if (!user_input_in_progress_ && *text == display_text_) { *url_from_text = PermanentURL(); *write_url = true; @@ -1230,7 +1220,7 @@ view_->OnInlineAutocompleteTextCleared(); const base::string16& user_text = - user_input_in_progress_ ? user_text_ : GetPermanentDisplayText(); + user_input_in_progress_ ? user_text_ : view_->GetText(); if (keyword_state_changed && is_keyword_selected()) { // If we reach here, the user most likely entered keyword mode by inserting // a space between a keyword name and a search string (as pressing space or
diff --git a/components/omnibox/browser/omnibox_edit_model_unittest.cc b/components/omnibox/browser/omnibox_edit_model_unittest.cc index d5d52357..5b2f744a 100644 --- a/components/omnibox/browser/omnibox_edit_model_unittest.cc +++ b/components/omnibox/browser/omnibox_edit_model_unittest.cc
@@ -229,6 +229,32 @@ EXPECT_EQ(base::string16(), view()->inline_autocomplete_text()); } +// iOS doesn't use elisions in the Omnibox textfield. +#if !defined(OS_IOS) +TEST_F(OmniboxEditModelTest, RespectUnelisionInZeroSuggest) { + location_bar_model()->set_url(GURL("https://www.example.com/")); + location_bar_model()->set_url_for_display(base::ASCIIToUTF16("example.com")); + + EXPECT_TRUE(model()->ResetDisplayTexts()); + model()->Revert(); + + // Set up view with unelided text. + EXPECT_EQ(base::ASCIIToUTF16("example.com"), view()->GetText()); + EXPECT_TRUE(model()->Unelide(false /* exit_query_in_omnibox */)); + EXPECT_EQ(base::ASCIIToUTF16("https://www.example.com/"), view()->GetText()); + EXPECT_FALSE(model()->user_input_in_progress()); + EXPECT_TRUE(view()->IsSelectAll()); + + // Test that we don't clobber the unelided text with inline autocomplete text. + EXPECT_EQ(base::string16(), view()->inline_autocomplete_text()); + model()->OnPopupDataChanged(base::string16(), nullptr, base::string16(), + false); + EXPECT_EQ(base::ASCIIToUTF16("https://www.example.com/"), view()->GetText()); + EXPECT_FALSE(model()->user_input_in_progress()); + EXPECT_TRUE(view()->IsSelectAll()); +} +#endif // !defined(OS_IOS) + // This verifies the fix for a bug where calling OpenMatch() with a valid // alternate nav URL would fail a DCHECK if the input began with "http://". // The failure was due to erroneously trying to strip the scheme from the @@ -295,6 +321,7 @@ // permanent display text. Unelision should return false. EXPECT_EQ(base::ASCIIToUTF16("https://www.example.com/"), model()->GetPermanentDisplayText()); + EXPECT_EQ(base::ASCIIToUTF16("https://www.example.com/"), view()->GetText()); EXPECT_FALSE(model()->Unelide(false /* exit_query_in_omnibox */)); EXPECT_FALSE(model()->user_input_in_progress()); EXPECT_FALSE(view()->IsSelectAll()); @@ -302,8 +329,9 @@ // Verify we can unelide and show the full URL properly. EXPECT_EQ(base::ASCIIToUTF16("example.com"), model()->GetPermanentDisplayText()); + EXPECT_EQ(base::ASCIIToUTF16("example.com"), view()->GetText()); EXPECT_TRUE(model()->Unelide(false /* exit_query_in_omnibox */)); - EXPECT_TRUE(model()->user_input_in_progress()); + EXPECT_FALSE(model()->user_input_in_progress()); EXPECT_TRUE(view()->IsSelectAll()); #endif @@ -332,7 +360,7 @@ // Verify we can exit Query in Omnibox mode properly. EXPECT_TRUE(model()->Unelide(true /* exit_query_in_omnibox */)); EXPECT_EQ(base::ASCIIToUTF16("https://www.example.com/"), view()->GetText()); - EXPECT_TRUE(model()->user_input_in_progress()); + EXPECT_FALSE(model()->user_input_in_progress()); EXPECT_TRUE(view()->IsSelectAll()); EXPECT_TRUE(model()->CurrentTextIsURL());
diff --git a/components/omnibox/browser/test_omnibox_view.cc b/components/omnibox/browser/test_omnibox_view.cc index a2a1cda..62503970 100644 --- a/components/omnibox/browser/test_omnibox_view.cc +++ b/components/omnibox/browser/test_omnibox_view.cc
@@ -54,7 +54,12 @@ const bool text_changed = text_ != display_text; text_ = display_text; inline_autocomplete_text_ = display_text.substr(user_text_length); - selection_ = gfx::Range(text_.size(), user_text_length); + + // Just like the Views control, only change the selection if the text has + // actually changed. + if (text_changed) + selection_ = gfx::Range(text_.size(), user_text_length); + return text_changed; }
diff --git a/components/page_image_annotation/DEPS b/components/page_image_annotation/DEPS index 2ea972b2..3f62e9f 100644 --- a/components/page_image_annotation/DEPS +++ b/components/page_image_annotation/DEPS
@@ -4,5 +4,6 @@ "-components/page_image_annotation/content", "+services/image_annotation/public/mojom", "+services/image_annotation/public/cpp", + "+services/service_manager/public/cpp", "+third_party/skia", ]
diff --git a/components/page_image_annotation/content/renderer/BUILD.gn b/components/page_image_annotation/content/renderer/BUILD.gn index e73589c3..a96c4d0 100644 --- a/components/page_image_annotation/content/renderer/BUILD.gn +++ b/components/page_image_annotation/content/renderer/BUILD.gn
@@ -14,6 +14,8 @@ "//content/public/common", "//content/public/renderer", "//crypto", + "//services/image_annotation/public/mojom", + "//services/service_manager/public/cpp", "//skia", "//third_party/blink/public:blink", "//third_party/blink/public/common",
diff --git a/components/page_image_annotation/content/renderer/content_page_annotator_driver.cc b/components/page_image_annotation/content/renderer/content_page_annotator_driver.cc index c2cb2df0..55c3aa9b 100644 --- a/components/page_image_annotation/content/renderer/content_page_annotator_driver.cc +++ b/components/page_image_annotation/content/renderer/content_page_annotator_driver.cc
@@ -9,6 +9,8 @@ #include "base/optional.h" #include "content/public/renderer/render_frame.h" #include "crypto/sha2.h" +#include "services/image_annotation/public/mojom/image_annotation.mojom.h" +#include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/public/web/web_document.h" #include "third_party/blink/public/web/web_local_frame.h" @@ -18,6 +20,8 @@ namespace { +namespace ia_mojom = image_annotation::mojom; + // The number of milliseconds to wait before traversing the DOM to find image // elements. constexpr int kDomCrawlDelayMs = 3000; @@ -36,6 +40,13 @@ return PageAnnotator::ImageMetadata{node_id, source_id}; } +ia_mojom::AnnotatorPtr RequestAnnotator( + content::RenderFrame* const render_frame) { + ia_mojom::AnnotatorPtr ptr; + render_frame->GetRemoteInterfaces()->GetInterface(mojo::MakeRequest(&ptr)); + return ptr; +} + } // namespace ContentPageAnnotatorDriver::ContentPageAnnotatorDriver( @@ -43,6 +54,7 @@ : RenderFrameObserver(render_frame), RenderFrameObserverTracker<ContentPageAnnotatorDriver>(render_frame), next_node_id_(1), + page_annotator_(RequestAnnotator(render_frame)), weak_ptr_factory_(this) {} ContentPageAnnotatorDriver::~ContentPageAnnotatorDriver() {}
diff --git a/components/page_image_annotation/core/page_annotator.cc b/components/page_image_annotation/core/page_annotator.cc index 7755315..46611fc 100644 --- a/components/page_image_annotation/core/page_annotator.cc +++ b/components/page_image_annotation/core/page_annotator.cc
@@ -6,9 +6,12 @@ namespace page_image_annotation { +namespace ia_mojom = image_annotation::mojom; + PageAnnotator::Observer::~Observer() {} -PageAnnotator::PageAnnotator() {} +PageAnnotator::PageAnnotator(ia_mojom::AnnotatorPtr annotator_ptr) + : annotator_ptr_(std::move(annotator_ptr)) {} PageAnnotator::~PageAnnotator() {} @@ -45,6 +48,20 @@ } } +void PageAnnotator::AnnotateImage(Observer* const observer, + const uint64_t node_id) { + DCHECK(observers_.HasObserver(observer)); + + const auto lookup = images_.find(node_id); + if (lookup == images_.end()) + return; + + annotator_ptr_->AnnotateImage( + lookup->second.first.source_id, lookup->second.second.GetPtr(), + base::BindOnce(&PageAnnotator::NotifyObserver, base::Unretained(this), + observer, node_id)); +} + void PageAnnotator::AddObserver(Observer* const observer) { observers_.AddObserver(observer); @@ -63,4 +80,10 @@ std::forward_as_tuple(metadata, std::move(pixels_callback))); } +void PageAnnotator::NotifyObserver(Observer* const observer, + const uint64_t node_id, + ia_mojom::AnnotateImageResultPtr result) { + observer->OnImageAnnotated(node_id, std::move(result)); +} + } // namespace page_image_annotation
diff --git a/components/page_image_annotation/core/page_annotator.h b/components/page_image_annotation/core/page_annotator.h index 4469251..e36115a 100644 --- a/components/page_image_annotation/core/page_annotator.h +++ b/components/page_image_annotation/core/page_annotator.h
@@ -6,6 +6,7 @@ #define COMPONENTS_PAGE_IMAGE_ANNOTATION_CORE_PAGE_ANNOTATOR_H_ #include <map> +#include <string> #include <utility> #include "base/callback.h" @@ -14,6 +15,7 @@ #include "base/observer_list.h" #include "base/observer_list_types.h" #include "services/image_annotation/public/cpp/image_processor.h" +#include "services/image_annotation/public/mojom/image_annotation.mojom.h" #include "third_party/skia/include/core/SkBitmap.h" namespace page_image_annotation { @@ -56,11 +58,24 @@ // Called at the point that an image disappears from the page. virtual void OnImageRemoved(uint64_t node_id) = 0; + + // Called when annotation is complete (either successfully or + // unsuccessfully) for a request made by this client. + virtual void OnImageAnnotated( + uint64_t node_id, + image_annotation::mojom::AnnotateImageResultPtr result) = 0; }; - PageAnnotator(); + explicit PageAnnotator(image_annotation::mojom::AnnotatorPtr annotator_ptr); ~PageAnnotator(); + // Request annotation of the given image via the image annotation service. + // When annotation is complete (or fails), the OnImageAnnotated() method of + // the observer is called. + // + // Must be called on a valid (i.e. added and not yet removed) node ID. + void AnnotateImage(Observer* observer, uint64_t node_id); + // Called by platform drivers. void ImageAddedOrPossiblyModified( const ImageMetadata& metadata, @@ -80,6 +95,14 @@ void AddNewImage(const ImageMetadata& metadata, base::RepeatingCallback<SkBitmap()> pixels_callback); + // Callback passed to the image annotation service to receive image annotation + // results. + void NotifyObserver(Observer* observer, + uint64_t node_id, + image_annotation::mojom::AnnotateImageResultPtr result); + + image_annotation::mojom::AnnotatorPtr annotator_ptr_; + base::ObserverList<Observer> observers_; std::map<uint64_t, std::pair<ImageMetadata, image_annotation::ImageProcessor>>
diff --git a/components/page_image_annotation/core/page_annotator_unittest.cc b/components/page_image_annotation/core/page_annotator_unittest.cc index c16dcec..a2c84cb 100644 --- a/components/page_image_annotation/core/page_annotator_unittest.cc +++ b/components/page_image_annotation/core/page_annotator_unittest.cc
@@ -4,68 +4,197 @@ #include "components/page_image_annotation/core/page_annotator.h" +#include <vector> + #include "base/test/scoped_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace page_image_annotation { +namespace { + +namespace ia_mojom = image_annotation::mojom; + +using testing::ElementsAre; using testing::Eq; +using testing::NiceMock; +using testing::SizeIs; -// Tests that the right messages are sent to observers. -TEST(PageAnnotatorTest, Observers) { - class TestObserver : public PageAnnotator::Observer { - public: - TestObserver() : last_added_(0), last_modified_(0), last_removed_(0) {} +// A gMock matcher that compares an ImageMetadata to the given node and source +// IDs. +MATCHER_P2(IsImageMetadata, expected_node_id, expected_source_id, "") { + return arg.node_id == expected_node_id && arg.source_id == expected_source_id; +} - void OnImageAdded(const PageAnnotator::ImageMetadata& metadata) override { - last_added_ = metadata.node_id; - } +// A gMock matcher that (deep) compares an AnnotateImageResultPtr to the +// expected result (which is of type AnnotateImageResult*). +MATCHER_P(IsAnnotateImageResult, expected, "") { + return arg->Equals(*expected); +} - void OnImageModified( - const PageAnnotator::ImageMetadata& metadata) override { - last_modified_ = metadata.node_id; - } +class MockObserver : public PageAnnotator::Observer { + public: + MOCK_METHOD1(OnImageAdded, + void(const PageAnnotator::ImageMetadata& metadata)); + MOCK_METHOD1(OnImageModified, + void(const PageAnnotator::ImageMetadata& metadata)); + MOCK_METHOD1(OnImageRemoved, void(uint64_t node_id)); + MOCK_METHOD2(OnImageAnnotated, + void(uint64_t node_id, ia_mojom::AnnotateImageResultPtr result)); +}; - void OnImageRemoved(const uint64_t node_id) override { - last_removed_ = node_id; - } +// An annotator that just stores and exposes the arguments with which its +// AnnotateImage method was called. +class TestAnnotator : public ia_mojom::Annotator { + public: + ia_mojom::AnnotatorPtr GetPtr() { + ia_mojom::AnnotatorPtr ptr; + bindings_.AddBinding(this, mojo::MakeRequest(&ptr)); + return ptr; + } - uint64_t last_added_, last_modified_, last_removed_; - }; + void AnnotateImage(const std::string& source_id, + ia_mojom::ImageProcessorPtr image_processor, + AnnotateImageCallback callback) override { + source_ids_.push_back(source_id); + + image_processors_.push_back(std::move(image_processor)); + image_processors_.back().set_connection_error_handler( + base::BindOnce(&TestAnnotator::ResetImageProcessor, + base::Unretained(this), image_processors_.size() - 1)); + + callbacks_.push_back(std::move(callback)); + } + + // Tests should not delete entries in these lists. + std::vector<std::string> source_ids_; + std::vector<ia_mojom::ImageProcessorPtr> image_processors_; + std::vector<AnnotateImageCallback> callbacks_; + + private: + void ResetImageProcessor(const size_t index) { + image_processors_[index].reset(); + } + + mojo::BindingSet<ia_mojom::Annotator> bindings_; +}; + +// Tests that correct image tracking messages are sent to observers. +TEST(PageAnnotatorTest, ImageTracking) { + const auto get_pixels = base::BindRepeating([]() { return SkBitmap(); }); base::test::ScopedTaskEnvironment test_task_env; - const auto get_pixels = base::BindRepeating([]() { return SkBitmap(); }); + PageAnnotator page_annotator(ia_mojom::AnnotatorPtr{}); - PageAnnotator page_annotator; - - TestObserver o1; + MockObserver o1; page_annotator.AddObserver(&o1); + EXPECT_CALL(o1, OnImageAdded(IsImageMetadata(1ul, "test.jpg"))); page_annotator.ImageAddedOrPossiblyModified({1ul, "test.jpg"}, get_pixels); - EXPECT_THAT(o1.last_added_, Eq(1ul)); + EXPECT_CALL(o1, OnImageAdded(IsImageMetadata(2ul, "example.png"))); page_annotator.ImageAddedOrPossiblyModified({2ul, "example.png"}, get_pixels); - EXPECT_THAT(o1.last_added_, Eq(2ul)); + EXPECT_CALL(o1, OnImageModified(IsImageMetadata(1ul, "demo.gif"))); page_annotator.ImageAddedOrPossiblyModified({1ul, "demo.gif"}, get_pixels); - EXPECT_THAT(o1.last_added_, Eq(2ul)); - EXPECT_THAT(o1.last_modified_, Eq(1ul)); + EXPECT_CALL(o1, OnImageRemoved(2ul)); page_annotator.ImageRemoved(2ul); - EXPECT_THAT(o1.last_added_, Eq(2ul)); - EXPECT_THAT(o1.last_modified_, Eq(1ul)); - EXPECT_THAT(o1.last_removed_, Eq(2ul)); - TestObserver o2; + MockObserver o2; + EXPECT_CALL(o2, OnImageAdded(IsImageMetadata(1ul, "demo.gif"))); page_annotator.AddObserver(&o2); - - EXPECT_THAT(o1.last_added_, Eq(2ul)); - EXPECT_THAT(o2.last_added_, Eq(1ul)); } -// TODO(crbug.com/916363): add more tests when behavior is added to the -// PageAnnotator class. +// Tests service and observer communication when performing image annotation. +TEST(PageAnnotatorTest, Annotation) { + // Returning a null SkBitmap is ok as long as we don't request JPG data from + // the local ImageProcessor. + const auto get_pixels = base::BindRepeating([]() { return SkBitmap(); }); + + base::test::ScopedTaskEnvironment test_task_env; + + TestAnnotator test_annotator; + PageAnnotator page_annotator(test_annotator.GetPtr()); + test_task_env.RunUntilIdle(); + + // We use NiceMocks here since we don't place expectations on image added / + // removed calls, which will otherwise cause many (benign) warnings to be + // logged. + NiceMock<MockObserver> o1, o2; + page_annotator.AddObserver(&o1); + page_annotator.AddObserver(&o2); + + // First image added. + page_annotator.ImageAddedOrPossiblyModified({1ul, "test.jpg"}, get_pixels); + + // Observer 1 requests annotation of the first image. + page_annotator.AnnotateImage(&o1, 1ul); + test_task_env.RunUntilIdle(); + + // The annotator should have been provided observer 1's request info. + EXPECT_THAT(test_annotator.source_ids_, ElementsAre("test.jpg")); + ASSERT_THAT(test_annotator.image_processors_, SizeIs(1)); + EXPECT_THAT(test_annotator.image_processors_[0].is_bound(), Eq(true)); + EXPECT_THAT(test_annotator.callbacks_, SizeIs(1)); + + // Observer 2 requests annotation of the same image. + page_annotator.AnnotateImage(&o2, 1ul); + test_task_env.RunUntilIdle(); + + // The annotator should have been provided observer 2's request info. + EXPECT_THAT(test_annotator.source_ids_, ElementsAre("test.jpg", "test.jpg")); + ASSERT_THAT(test_annotator.image_processors_, SizeIs(2)); + EXPECT_THAT(test_annotator.image_processors_[0].is_bound(), Eq(true)); + EXPECT_THAT(test_annotator.image_processors_[1].is_bound(), Eq(true)); + EXPECT_THAT(test_annotator.callbacks_, SizeIs(2)); + + // Second image added. + page_annotator.ImageAddedOrPossiblyModified({2ul, "example.png"}, get_pixels); + + // Observer 2 requests annotation of the second image. + page_annotator.AnnotateImage(&o2, 2ul); + test_task_env.RunUntilIdle(); + + // All three requests should have been provided to the annotator. + EXPECT_THAT(test_annotator.source_ids_, + ElementsAre("test.jpg", "test.jpg", "example.png")); + ASSERT_THAT(test_annotator.image_processors_, SizeIs(3)); + EXPECT_THAT(test_annotator.image_processors_[0].is_bound(), Eq(true)); + EXPECT_THAT(test_annotator.image_processors_[1].is_bound(), Eq(true)); + EXPECT_THAT(test_annotator.image_processors_[2].is_bound(), Eq(true)); + EXPECT_THAT(test_annotator.callbacks_, SizeIs(3)); + + // Image 1 goes away. + page_annotator.ImageRemoved(1ul); + test_task_env.RunUntilIdle(); + + // The corresponding image processors should have been disconnected. + ASSERT_THAT(test_annotator.image_processors_, SizeIs(3)); + EXPECT_THAT(test_annotator.image_processors_[0].is_bound(), Eq(false)); + EXPECT_THAT(test_annotator.image_processors_[1].is_bound(), Eq(false)); + EXPECT_THAT(test_annotator.image_processors_[2].is_bound(), Eq(true)); + + // Expect success and failure to be reported. + const auto error = ia_mojom::AnnotateImageResult::NewErrorCode( + ia_mojom::AnnotateImageError::kCanceled); + const auto success = + ia_mojom::AnnotateImageResult::NewOcrText("text from image"); + + ASSERT_THAT(test_annotator.callbacks_, SizeIs(3)); + std::move(test_annotator.callbacks_[0]).Run(error.Clone()); + std::move(test_annotator.callbacks_[1]).Run(error.Clone()); + std::move(test_annotator.callbacks_[2]).Run(success.Clone()); + + EXPECT_CALL(o1, OnImageAnnotated(1ul, IsAnnotateImageResult(error.get()))); + EXPECT_CALL(o2, OnImageAnnotated(1ul, IsAnnotateImageResult(error.get()))); + EXPECT_CALL(o2, OnImageAnnotated(2ul, IsAnnotateImageResult(success.get()))); + + test_task_env.RunUntilIdle(); +} + +} // namespace } // namespace page_image_annotation
diff --git a/components/password_manager/content/browser/content_password_manager_driver.cc b/components/password_manager/content/browser/content_password_manager_driver.cc index 8128de7..2e1d54c 100644 --- a/components/password_manager/content/browser/content_password_manager_driver.cc +++ b/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -135,10 +135,6 @@ GetAutofillAgent()->ClearPreviewedForm(); } -void ContentPasswordManagerDriver::GeneratePassword() { - GetPasswordGenerationAgent()->UserTriggeredGeneratePassword(); -} - PasswordGenerationManager* ContentPasswordManagerDriver::GetPasswordGenerationManager() { return &password_generation_manager_; @@ -184,6 +180,13 @@ } } +void ContentPasswordManagerDriver::GeneratePassword( + autofill::mojom::PasswordGenerationAgent:: + UserTriggeredGeneratePasswordCallback callback) { + GetPasswordGenerationAgent()->UserTriggeredGeneratePassword( + std::move(callback)); +} + const autofill::mojom::AutofillAgentAssociatedPtr& ContentPasswordManagerDriver::GetAutofillAgent() { autofill::ContentAutofillDriver* autofill_driver =
diff --git a/components/password_manager/content/browser/content_password_manager_driver.h b/components/password_manager/content/browser/content_password_manager_driver.h index 6df54c8..ff901b7 100644 --- a/components/password_manager/content/browser/content_password_manager_driver.h +++ b/components/password_manager/content/browser/content_password_manager_driver.h
@@ -70,7 +70,6 @@ void ShowInitialPasswordAccountSuggestions( const autofill::PasswordFormFillData& form_data) override; void ClearPreviewedForm() override; - void GeneratePassword() override; PasswordGenerationManager* GetPasswordGenerationManager() override; PasswordManager* GetPasswordManager() override; PasswordAutofillManager* GetPasswordAutofillManager() override; @@ -80,6 +79,13 @@ GURL GetLastCommittedURL() const override; void DidNavigateFrame(content::NavigationHandle* navigation_handle); + // Notify the renderer that the user wants to generate password manually. + void GeneratePassword(autofill::mojom::PasswordGenerationAgent:: + UserTriggeredGeneratePasswordCallback callback); + + content::RenderFrameHost* render_frame_host() const { + return render_frame_host_; + } private: const autofill::mojom::AutofillAgentAssociatedPtr& GetAutofillAgent();
diff --git a/components/password_manager/core/browser/form_parsing/form_parser.cc b/components/password_manager/core/browser/form_parsing/form_parser.cc index 962e07f..5e906ef8 100644 --- a/components/password_manager/core/browser/form_parsing/form_parser.cc +++ b/components/password_manager/core/browser/form_parsing/form_parser.cc
@@ -180,6 +180,11 @@ return s.empty() || (s.size() < 3 && DoesStringContainOnlyDigits(s)); } +// Returns |typed_value| if it is not empty, |value| otherwise. +base::string16 GetFieldValue(const FormFieldData& field) { + return field.typed_value.empty() ? field.value : field.typed_value; +} + // A helper struct that is used to capture significant fields to be used for // the construction of a PasswordForm. struct SignificantFields { @@ -711,7 +716,7 @@ if (significant_fields.username) { password_form->username_element = GetPlatformSpecificIdentifier(*significant_fields.username); - password_form->username_value = significant_fields.username->value; + password_form->username_value = GetFieldValue(*significant_fields.username); password_form->username_element_renderer_id = significant_fields.username->unique_renderer_id; } @@ -719,7 +724,7 @@ if (significant_fields.password) { password_form->password_element = GetPlatformSpecificIdentifier(*significant_fields.password); - password_form->password_value = significant_fields.password->value; + password_form->password_value = GetFieldValue(*significant_fields.password); password_form->password_element_renderer_id = significant_fields.password->unique_renderer_id; } @@ -727,7 +732,8 @@ if (significant_fields.new_password) { password_form->new_password_element = GetPlatformSpecificIdentifier(*significant_fields.new_password); - password_form->new_password_value = significant_fields.new_password->value; + password_form->new_password_value = + GetFieldValue(*significant_fields.new_password); password_form->new_password_element_renderer_id = significant_fields.new_password->unique_renderer_id; }
diff --git a/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc b/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc index ee1c49c..ceb3c254c5 100644 --- a/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc +++ b/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
@@ -68,6 +68,7 @@ FieldPropertiesFlags::NO_FLAGS; const char* autocomplete_attribute = nullptr; const char* value = kNonimportantValue; + const char* typed_value = nullptr; const char* name = kNonimportantValue; const char* form_control_type = "text"; PasswordFieldPrediction prediction = {.type = autofill::MAX_VALID_FIELD_TYPE}; @@ -193,6 +194,8 @@ } if (field_description.autocomplete_attribute) field.autocomplete_attribute = field_description.autocomplete_attribute; + if (field_description.typed_value) + field.typed_value = ASCIIToUTF16(field_description.typed_value); form_data.fields.push_back(field); if (field_description.role == ElementRole::NONE) { UpdateResultWithIdByRole(fill_result, unique_id, @@ -261,8 +264,11 @@ EXPECT_EQ(element_name, field_it->name); #endif + base::string16 expected_value = + field_it->typed_value.empty() ? field_it->value : field_it->typed_value; + if (element_value) - EXPECT_EQ(*element_value, field_it->value); + EXPECT_EQ(expected_value, *element_value); } // Describes the |form_data| including field values and names. Use this in @@ -1924,6 +1930,29 @@ } } +TEST(FormParserTest, TypedValues) { + CheckTestData({{"Simple sign-in forms with typed values", + // Tests that typed values are taken as username, password and + // new password instead of values that are set by JavaScript. + { + {.role = ElementRole::USERNAME, + .form_control_type = "text", + .autocomplete_attribute = "username", + .value = "js_username", + .typed_value = "typed_username"}, + {.role = ElementRole::CURRENT_PASSWORD, + .form_control_type = "password", + .autocomplete_attribute = "current-password", + .value = "js_password", + .typed_value = "typed_password"}, + {.role = ElementRole::NEW_PASSWORD, + .form_control_type = "password", + .autocomplete_attribute = "new-password", + .value = "js_new_password", + .typed_value = "typed_new_password"}, + }}}); +} + } // namespace } // namespace password_manager
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc index 4126bb56..0fd9e5e 100644 --- a/components/password_manager/core/browser/login_database.cc +++ b/components/password_manager/core/browser/login_database.cc
@@ -1071,15 +1071,34 @@ return true; } -bool LoginDatabase::RemoveLoginById(int id) { +bool LoginDatabase::RemoveLoginByPrimaryKey(int primary_key, + PasswordStoreChangeList* changes) { + PrimaryKeyToFormMap key_to_form_map; + if (changes) { + changes->clear(); + sql::Statement s1(db_.GetCachedStatement( + SQL_FROM_HERE, "SELECT * FROM logins WHERE id = ?")); + s1.BindInt(0, primary_key); + if (!StatementToForms(&s1, nullptr, &key_to_form_map)) { + return false; + } + } + #if defined(OS_IOS) - DeleteEncryptedPasswordById(id); + DeleteEncryptedPasswordById(primary_key); #endif DCHECK(!delete_by_id_statement_.empty()); - sql::Statement s( + sql::Statement s2( db_.GetCachedStatement(SQL_FROM_HERE, delete_by_id_statement_.c_str())); - s.BindInt(0, id); - return s.Run() && db_.GetLastChangeCount() > 0; + s2.BindInt(0, primary_key); + if (!s2.Run() || db_.GetLastChangeCount() == 0) { + return false; + } + if (changes) { + changes->emplace_back(PasswordStoreChange::REMOVE, + *key_to_form_map[primary_key], primary_key); + } + return true; } bool LoginDatabase::RemoveLoginsCreatedBetween( @@ -1424,6 +1443,16 @@ return StatementToForms(&s, nullptr, key_to_form_map); } +bool LoginDatabase::GetAllLogins(PrimaryKeyToFormMap* key_to_form_map) { + DCHECK(key_to_form_map); + key_to_form_map->clear(); + + sql::Statement s( + db_.GetCachedStatement(SQL_FROM_HERE, "SELECT * FROM logins")); + + return StatementToForms(&s, nullptr, key_to_form_map); +} + bool LoginDatabase::GetAutofillableLogins( std::vector<std::unique_ptr<PasswordForm>>* forms) { return GetAllLoginsWithBlacklistSetting(false, forms);
diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h index 0492ada..7fceb88 100644 --- a/components/password_manager/core/browser/login_database.h +++ b/components/password_manager/core/browser/login_database.h
@@ -37,9 +37,6 @@ class SQLTableBuilder; -using PrimaryKeyToFormMap = - std::map<int, std::unique_ptr<autofill::PasswordForm>>; - extern const int kCurrentVersionNumber; extern const int kCompatibleVersionNumber; @@ -92,9 +89,11 @@ bool RemoveLogin(const autofill::PasswordForm& form, PasswordStoreChangeList* changes) WARN_UNUSED_RESULT; - // Removes the form with |id| from the list of remembered password forms. - // Returns true if the form was successfully removed from the database. - bool RemoveLoginById(int id) WARN_UNUSED_RESULT; + // Removes the form with |primary_key| from the list of remembered password + // forms. Returns true if the form was successfully removed from the database. + bool RemoveLoginByPrimaryKey(int primary_key, + PasswordStoreChangeList* changes) + WARN_UNUSED_RESULT; // Removes all logins created from |delete_begin| onwards (inclusive) and // before |delete_end|. You may use a null Time value to do an unbounded @@ -145,6 +144,9 @@ PrimaryKeyToFormMap* key_to_form_map) WARN_UNUSED_RESULT; + // Gets the complete list of all credentials. + bool GetAllLogins(PrimaryKeyToFormMap* key_to_form_map) WARN_UNUSED_RESULT; + // Gets the complete list of not blacklisted credentials. bool GetAutofillableLogins( std::vector<std::unique_ptr<autofill::PasswordForm>>* forms)
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc index b3f7b618..762df3e4 100644 --- a/components/password_manager/core/browser/login_database_unittest.cc +++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -58,6 +58,11 @@ 1, PasswordStoreChange(PasswordStoreChange::UPDATE, form)); } +PasswordStoreChangeList RemoveChangeForForm(const PasswordForm& form) { + return PasswordStoreChangeList( + 1, PasswordStoreChange(PasswordStoreChange::REMOVE, form)); +} + void GenerateExamplePasswordForm(PasswordForm* form) { form->origin = GURL("http://accounts.google.com/LoginAuth"); form->action = GURL("http://accounts.google.com/Login"); @@ -265,11 +270,15 @@ TEST_F(LoginDatabaseTest, Logins) { std::vector<std::unique_ptr<PasswordForm>> result; + PrimaryKeyToFormMap key_to_form_map; // Verify the database is empty. EXPECT_TRUE(db().GetAutofillableLogins(&result)); EXPECT_EQ(0U, result.size()); + EXPECT_TRUE(db().GetAllLogins(&key_to_form_map)); + EXPECT_EQ(0U, key_to_form_map.size()); + // Example password form. PasswordForm form; GenerateExamplePasswordForm(&form); @@ -284,6 +293,11 @@ EXPECT_EQ(form, *result[0]); result.clear(); + EXPECT_TRUE(db().GetAllLogins(&key_to_form_map)); + EXPECT_EQ(1U, key_to_form_map.size()); + EXPECT_EQ(form, *key_to_form_map[1]); + key_to_form_map.clear(); + // Match against an exact copy. EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result)); ASSERT_EQ(1U, result.size()); @@ -390,7 +404,7 @@ EXPECT_EQ(1, change_list[0].primary_key()); } -TEST_F(LoginDatabaseTest, RemoveLoginsById) { +TEST_F(LoginDatabaseTest, RemoveLoginsByPrimaryKey) { std::vector<std::unique_ptr<PasswordForm>> result; // Verify the database is empty. @@ -405,14 +419,15 @@ // correctly. PasswordStoreChangeList change_list = db().AddLogin(form); ASSERT_EQ(1U, change_list.size()); - int id = change_list[0].primary_key(); + int primary_key = change_list[0].primary_key(); EXPECT_EQ(AddChangeForForm(form), change_list); EXPECT_TRUE(db().GetAutofillableLogins(&result)); ASSERT_EQ(1U, result.size()); EXPECT_EQ(form, *result[0]); result.clear(); - EXPECT_TRUE(db().RemoveLoginById(id)); + EXPECT_TRUE(db().RemoveLoginByPrimaryKey(primary_key, &change_list)); + EXPECT_EQ(RemoveChangeForForm(form), change_list); EXPECT_TRUE(db().GetAutofillableLogins(&result)); EXPECT_EQ(0U, result.size()); }
diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h index 72276a4..3437806 100644 --- a/components/password_manager/core/browser/mock_password_store.h +++ b/components/password_manager/core/browser/mock_password_store.h
@@ -88,9 +88,10 @@ MOCK_METHOD0(ClearAllGaiaPasswordHash, void()); MOCK_METHOD0(ClearAllEnterprisePasswordHash, void()); #endif - MOCK_METHOD0(BeginTransaction, bool()); MOCK_METHOD0(CommitTransaction, bool()); + MOCK_METHOD1(ReadAllLogins, bool(PrimaryKeyToFormMap*)); + MOCK_METHOD1(RemoveLoginByPrimaryKeySync, PasswordStoreChangeList(int)); MOCK_METHOD0(GetMetadataStore, syncer::SyncMetadataStore*()); PasswordStoreSync* GetSyncInterface() { return this; }
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc index aba03bf..f7aa982 100644 --- a/components/password_manager/core/browser/password_manager.cc +++ b/components/password_manager/core/browser/password_manager.cc
@@ -860,19 +860,26 @@ // Create form manager for new forms. for (const PasswordForm* new_form : new_forms) { - form_managers_.push_back(std::make_unique<NewPasswordFormManager>( - client_, - driver ? driver->AsWeakPtr() : base::WeakPtr<PasswordManagerDriver>(), - new_form->form_data, nullptr, - std::make_unique<FormSaverImpl>(client_->GetPasswordStore()), nullptr)); - form_managers_.back()->set_old_parsing_result(*new_form); - form_managers_.back()->ProcessServerPredictions(predictions_); + auto* manager = CreateFormManager(driver, new_form->form_data); + manager->set_old_parsing_result(*new_form); } } +NewPasswordFormManager* PasswordManager::CreateFormManager( + PasswordManagerDriver* driver, + const autofill::FormData& form) { + form_managers_.push_back(std::make_unique<NewPasswordFormManager>( + client_, + driver ? driver->AsWeakPtr() : base::WeakPtr<PasswordManagerDriver>(), + form, nullptr, + std::make_unique<FormSaverImpl>(client_->GetPasswordStore()), nullptr)); + form_managers_.back()->ProcessServerPredictions(predictions_); + return form_managers_.back().get(); +} + NewPasswordFormManager* PasswordManager::ProvisionallySaveForm( const FormData& submitted_form, - const PasswordManagerDriver* driver) { + PasswordManagerDriver* driver) { std::unique_ptr<BrowserSavePasswordProgressLogger> logger; if (password_manager_util::IsLoggingActive(client_)) { logger.reset( @@ -906,13 +913,13 @@ kMissingProvisionallySave; if (client_ && client_->GetMetricsRecorder()) client_->GetMetricsRecorder()->RecordFormManagerAvailable(availability); + if (!matching_form_manager) { - // TODO(https://crbug.com/831123): Implement more robust handling when - // |matching_form_manager| is not found. RecordProvisionalSaveFailure( PasswordManagerMetricsRecorder::NO_MATCHING_FORM, submitted_form.origin, logger.get()); - return nullptr; + matching_form_manager = CreateFormManager(driver, submitted_form); + matching_form_manager->ProvisionallySaveIfIsManaged(submitted_form, driver); } // Set all other form managers to no submission state. @@ -1390,7 +1397,7 @@ scoped_refptr<PasswordFormMetricsRecorder> PasswordManager::GetMetricRecorderFromNewPasswordFormManager( - const autofill::FormData& form, + const FormData& form, const PasswordManagerDriver* driver) { for (auto& form_manager : form_managers_) { if (form_manager->DoesManage(form, driver)) @@ -1400,9 +1407,11 @@ return nullptr; } +// TODO(https://crbug.com/831123): Implement creating missing +// NewPasswordFormManager when PasswordFormManager is gone. PasswordFormManagerInterface* PasswordManager::GetMatchedManager( const PasswordManagerDriver* driver, - const autofill::PasswordForm& form) { + const PasswordForm& form) { if (!is_new_form_parsing_for_saving_enabled_) return GetMatchingPendingManager(form);
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h index acd55e41..7129d048 100644 --- a/components/password_manager/core/browser/password_manager.h +++ b/components/password_manager/core/browser/password_manager.h
@@ -233,16 +233,20 @@ void CreateFormManagers(PasswordManagerDriver* driver, const std::vector<autofill::PasswordForm>& forms); - // Passes |form| to NewPasswordManager that manages it for using it after + // Create NewPasswordFormManager for |form|, adds the newly created one to + // |form_managers_| and returns it. + NewPasswordFormManager* CreateFormManager(PasswordManagerDriver* driver, + const autofill::FormData& forms); + + // Passes |form| to NewPasswordFormManager that manages it for using it after // detecting submission success for saving. |driver| is needed to determine // the match. If the function is called multiple times, only the form from the // last call is provisionally saved. Multiple calls is possible because it is - // called on any user keystroke. - // Returns manager which manages |form| or nullptr if such manager is not - // found. - NewPasswordFormManager* ProvisionallySaveForm( - const autofill::FormData& form, - const PasswordManagerDriver* driver); + // called on any user keystroke. If there is no NewPasswordFormManager that + // manages |form|, the new one is created. + // Returns manager which manages |form|. + NewPasswordFormManager* ProvisionallySaveForm(const autofill::FormData& form, + PasswordManagerDriver* driver); // Returns the best match in |pending_login_managers_| for |form|. May return // nullptr if no match exists.
diff --git a/components/password_manager/core/browser/password_manager_driver.h b/components/password_manager/core/browser/password_manager_driver.h index c871b18c..1206b23 100644 --- a/components/password_manager/core/browser/password_manager_driver.h +++ b/components/password_manager/core/browser/password_manager_driver.h
@@ -94,10 +94,6 @@ // Tells the driver to clear previewed password and username fields. virtual void ClearPreviewedForm() = 0; - // Tells the driver to find the focused password field and to show generation - // popup at it. - virtual void GeneratePassword() {} - // Returns the PasswordGenerationManager associated with this instance. virtual PasswordGenerationManager* GetPasswordGenerationManager() = 0;
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc index d0c03b58..d04a263b 100644 --- a/components/password_manager/core/browser/password_manager_unittest.cc +++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -3074,6 +3074,8 @@ TEST_F(PasswordManagerTest, ProvisionallySaveFailure) { EXPECT_CALL(client_, IsSavingAndFillingEnabled(_)) .WillRepeatedly(Return(true)); + EXPECT_CALL(*store_, GetLogins(_, _)) + .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms())); for (bool new_parsing_for_saving : {false, true}) { SCOPED_TRACE(testing::Message() << "new_parsing_for_saving = " << new_parsing_for_saving); @@ -3131,6 +3133,9 @@ // The expected value of the PageWithPassword::kFormManagerAvailableName // metric, or base::nullopt if no value should be logged. base::Optional<int64_t> expected_metric_value; + + bool run_for_old_parser = true; + bool run_for_new_parser = true; }; } // namespace @@ -3167,6 +3172,19 @@ .expected_metric_value = MetricValue(PasswordManagerMetricsRecorder::FormManagerAvailable:: kMissingManual), + .run_for_new_parser = false, + }, + { + .description = "Manual saving is requested and a " + "NewPasswordFormManager is created.", + .parsed_forms = {}, + .save_signal = MissingFormManagerTestCase::Signal::Manual, + // .parsed_forms is empty, so the processed form below was not + // observed and has no form manager associated. + .processed_forms = {form}, + .expected_metric_value = MetricValue( + PasswordManagerMetricsRecorder::FormManagerAvailable::kSuccess), + .run_for_old_parser = false, }, { .description = "Manual saving is successfully requested.", @@ -3220,6 +3238,10 @@ .WillRepeatedly(Return(test_case.saving == MissingFormManagerTestCase::Saving::Enabled)); for (bool new_parsing_for_saving : {false, true}) { + if ((new_parsing_for_saving && !test_case.run_for_new_parser) || + (!new_parsing_for_saving && !test_case.run_for_old_parser)) { + continue; + } SCOPED_TRACE(testing::Message() << "test case = " << test_case.description << ", new_parsing_for_saving = " << new_parsing_for_saving); @@ -3273,4 +3295,42 @@ } } +// Tests that despite there a form was not seen on a page load, new +// |NewPasswordFormManager| is created in process of saving. +TEST_F(PasswordManagerTest, CreateNewPasswordFormManagerOnSaving) { + base::test::ScopedFeatureList scoped_feature_list; + TurnOnNewParsingForSaving(&scoped_feature_list); + + EXPECT_CALL(client_, IsSavingAndFillingEnabled(_)) + .WillRepeatedly(Return(true)); + + PasswordForm form(MakeSimpleForm()); + EXPECT_CALL(*store_, GetLogins(_, _)) + .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms())); + + manager()->OnPasswordFormsParsed(&driver_, {form}); + + // Simulate that JavaScript creates a new form, fills username/password and + // submits it. + auto submitted_form = form; + submitted_form.form_data.unique_renderer_id += 1000; + submitted_form.username_value = ASCIIToUTF16("username1"); + submitted_form.form_data.fields[0].value = submitted_form.username_value; + submitted_form.password_value = ASCIIToUTF16("password1"); + submitted_form.form_data.fields[1].value = submitted_form.password_value; + + OnPasswordFormSubmitted(submitted_form); + EXPECT_TRUE(manager()->GetSubmittedManagerForTest()); + + std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save; + EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)) + .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save))); + + // The form disappeared, so the submission is condered to be successful. + manager()->OnPasswordFormsRendered(&driver_, {}, true); + ASSERT_TRUE(form_manager_to_save); + EXPECT_THAT(form_manager_to_save->GetPendingCredentials(), + FormMatches(submitted_form)); +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h index 5aab1e9..f6b4c16 100644 --- a/components/password_manager/core/browser/password_store.h +++ b/components/password_manager/core/browser/password_store.h
@@ -592,6 +592,18 @@ const base::Callback<bool(const GURL&)>& origin_filter, const base::Closure& completion); + // Overwrites |forms| with all stored non-blacklisted credentials. Returns + // true on success. + virtual bool FillAutofillableLogins( + std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) + WARN_UNUSED_RESULT = 0; + + // Overwrites |forms| with all stored blacklisted credentials. Returns true on + // success. + virtual bool FillBlacklistLogins( + std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) + WARN_UNUSED_RESULT = 0; + // Finds all logins organization-name-matching |signon_realm| and notifies the // consumer. void GetLoginsForSameOrganizationNameImpl(
diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc index 3f243b36..c518a89f 100644 --- a/components/password_manager/core/browser/password_store_default.cc +++ b/components/password_manager/core/browser/password_store_default.cc
@@ -238,6 +238,21 @@ return false; } +bool PasswordStoreDefault::ReadAllLogins(PrimaryKeyToFormMap* key_to_form_map) { + DCHECK(background_task_runner()->RunsTasksInCurrentSequence()); + return login_db_ && login_db_->GetAllLogins(key_to_form_map); +} + +PasswordStoreChangeList PasswordStoreDefault::RemoveLoginByPrimaryKeySync( + int primary_key) { + DCHECK(background_task_runner()->RunsTasksInCurrentSequence()); + PasswordStoreChangeList changes; + if (login_db_ && login_db_->RemoveLoginByPrimaryKey(primary_key, &changes)) { + return changes; + } + return PasswordStoreChangeList(); +} + syncer::SyncMetadataStore* PasswordStoreDefault::GetMetadataStore() { return login_db_.get(); }
diff --git a/components/password_manager/core/browser/password_store_default.h b/components/password_manager/core/browser/password_store_default.h index 703daf7d..ecc4e98 100644 --- a/components/password_manager/core/browser/password_store_default.h +++ b/components/password_manager/core/browser/password_store_default.h
@@ -87,6 +87,8 @@ // Implements PasswordStoreSync interface. bool BeginTransaction() override; bool CommitTransaction() override; + bool ReadAllLogins(PrimaryKeyToFormMap* key_to_form_map) override; + PasswordStoreChangeList RemoveLoginByPrimaryKeySync(int primary_key) override; syncer::SyncMetadataStore* GetMetadataStore() override; inline bool DeleteAndRecreateDatabaseFile() {
diff --git a/components/password_manager/core/browser/password_store_sync.h b/components/password_manager/core/browser/password_store_sync.h index 0394e3e..051e857 100644 --- a/components/password_manager/core/browser/password_store_sync.h +++ b/components/password_manager/core/browser/password_store_sync.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_SYNC_H_ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_SYNC_H_ +#include <map> #include <memory> #include <vector> @@ -22,6 +23,9 @@ namespace password_manager { +using PrimaryKeyToFormMap = + std::map<int, std::unique_ptr<autofill::PasswordForm>>; + // This enum is used to determine result status when deleting undecryptable // logins from database. enum class DatabaseCleanupResult { @@ -39,16 +43,9 @@ public: PasswordStoreSync(); - // Overwrites |forms| with all stored non-blacklisted credentials. Returns - // true on success. - virtual bool FillAutofillableLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) - WARN_UNUSED_RESULT = 0; - - // Overwrites |forms| with all stored blacklisted credentials. Returns true on - // success. - virtual bool FillBlacklistLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) + // Overwrites |key_to_form_map| with a map from the DB primary key to the + // corresponding form for all stored credentials. Returns true on success. + virtual bool ReadAllLogins(PrimaryKeyToFormMap* key_to_form_map) WARN_UNUSED_RESULT = 0; // Deletes logins that cannot be decrypted. @@ -66,6 +63,10 @@ virtual PasswordStoreChangeList RemoveLoginSync( const autofill::PasswordForm& form) = 0; + // Synchronous implementation to remove the login with the given primary key. + virtual PasswordStoreChangeList RemoveLoginByPrimaryKeySync( + int primary_key) = 0; + // Notifies observers that password store data may have been changed. virtual void NotifyLoginsChanged(const PasswordStoreChangeList& changes) = 0;
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc index ae77b94..1136213 100644 --- a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc +++ b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -79,10 +79,8 @@ MockPasswordStoreSync() = default; ~MockPasswordStoreSync() = default; - MOCK_METHOD1(FillAutofillableLogins, - bool(std::vector<std::unique_ptr<autofill::PasswordForm>>*)); - MOCK_METHOD1(FillBlacklistLogins, - bool(std::vector<std::unique_ptr<autofill::PasswordForm>>*)); + MOCK_METHOD1(ReadAllLogins, bool(PrimaryKeyToFormMap*)); + MOCK_METHOD1(RemoveLoginByPrimaryKeySync, PasswordStoreChangeList(int)); MOCK_METHOD0(DeleteUndecryptableLogins, DatabaseCleanupResult()); MOCK_METHOD1(AddLoginSync, PasswordStoreChangeList(const autofill::PasswordForm&));
diff --git a/components/password_manager/core/browser/sync/password_syncable_service.cc b/components/password_manager/core/browser/sync/password_syncable_service.cc index 6765684..e1401d25 100644 --- a/components/password_manager/core/browser/sync/password_syncable_service.cc +++ b/components/password_manager/core/browser/sync/password_syncable_service.cc
@@ -326,10 +326,8 @@ std::vector<std::unique_ptr<autofill::PasswordForm>>* password_entries, PasswordEntryMap* passwords_entry_map) const { DCHECK(password_entries); - std::vector<std::unique_ptr<autofill::PasswordForm>> autofillable_entries; - std::vector<std::unique_ptr<autofill::PasswordForm>> blacklist_entries; - if (!password_store_->FillAutofillableLogins(&autofillable_entries) || - !password_store_->FillBlacklistLogins(&blacklist_entries)) { + PrimaryKeyToFormMap all_entries_map; + if (!password_store_->ReadAllLogins(&all_entries_map)) { // Password store often fails to load passwords. Track failures with UMA. // (http://crbug.com/249000) // TODO(wychen): enum uma should be strongly typed. crbug.com/661401 @@ -338,12 +336,11 @@ static_cast<int>(syncer::MODEL_TYPE_COUNT)); return false; } - password_entries->resize(autofillable_entries.size() + - blacklist_entries.size()); - std::move(autofillable_entries.begin(), autofillable_entries.end(), - password_entries->begin()); - std::move(blacklist_entries.begin(), blacklist_entries.end(), - password_entries->begin() + autofillable_entries.size()); + password_entries->clear(); + password_entries->reserve(all_entries_map.size()); + for (auto& pair : all_entries_map) { + password_entries->push_back(std::move(pair.second)); + } if (!passwords_entry_map) return true;
diff --git a/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc b/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc index 5088b717..d8c90f6 100644 --- a/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc +++ b/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc
@@ -119,10 +119,17 @@ Matches(PasswordIs(password))(form))); } -// The argument is std::vector<autofill::PasswordForm*>*. The caller is +// The argument is PrimaryKeyToFormMap*. The caller is // responsible for the lifetime of all the password forms. ACTION_P(AppendForm, form) { - arg0->push_back(std::make_unique<autofill::PasswordForm>(form)); + arg0->emplace(arg0->size() + 1, + std::make_unique<autofill::PasswordForm>(form)); + return true; +} + +ACTION_P2(Append2Forms, form1, form2) { + arg0->emplace(1, std::make_unique<autofill::PasswordForm>(form1)); + arg0->emplace(2, std::make_unique<autofill::PasswordForm>(form2)); return true; } @@ -232,9 +239,7 @@ autofill::PasswordForm new_from_sync = PasswordFromSpecifics(GetPasswordSpecifics(list.back())); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(AppendForm(form)); - EXPECT_CALL(*password_store(), FillBlacklistLogins(_)).WillOnce(Return(true)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(AppendForm(form)); EXPECT_CALL(*password_store(), AddLoginImpl(PasswordIs(new_from_sync))); EXPECT_CALL(*processor_, ProcessSyncChanges( @@ -252,9 +257,8 @@ autofill::PasswordForm new_from_sync = PasswordFromSpecifics(GetPasswordSpecifics(list.back())); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(Return(true)); - EXPECT_CALL(*password_store(), FillBlacklistLogins(_)).WillOnce(Return(true)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(Return(true)); + EXPECT_CALL(*password_store(), AddLoginImpl(PasswordIs(new_from_sync))); EXPECT_CALL(*processor_, ProcessSyncChanges(_, IsEmpty())); @@ -274,9 +278,7 @@ form.federation_origin = url::Origin::Create(GURL(kFederationUrl)); form.username_value = base::ASCIIToUTF16(kUsername); form.password_value = base::ASCIIToUTF16(kPassword); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(AppendForm(form)); - EXPECT_CALL(*password_store(), FillBlacklistLogins(_)).WillOnce(Return(true)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(AppendForm(form)); EXPECT_CALL(*processor_, ProcessSyncChanges( @@ -295,9 +297,7 @@ form.type = kArbitraryType; form.username_value = base::ASCIIToUTF16(kUsername); form.password_value = base::ASCIIToUTF16(kPassword); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(AppendForm(form)); - EXPECT_CALL(*password_store(), FillBlacklistLogins(_)).WillOnce(Return(true)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(AppendForm(form)); EXPECT_CALL(*processor_, ProcessSyncChanges(_, IsEmpty())); @@ -319,9 +319,7 @@ autofill::PasswordForm form2(form1); form2.preferred = false; - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(AppendForm(form1)); - EXPECT_CALL(*password_store(), FillBlacklistLogins(_)).WillOnce(Return(true)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(AppendForm(form1)); EXPECT_CALL(*password_store(), UpdateLoginImpl(PasswordIs(form2))); EXPECT_CALL(*processor_, ProcessSyncChanges(_, IsEmpty())); @@ -336,9 +334,7 @@ // MergeDataAndStartSyncing(). MockSyncChangeProcessor& weak_processor = *processor_; EXPECT_CALL(weak_processor, ProcessSyncChanges(_, IsEmpty())); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(Return(true)); - EXPECT_CALL(*password_store(), FillBlacklistLogins(_)).WillOnce(Return(true)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(Return(true)); service()->MergeDataAndStartSyncing( syncer::PASSWORDS, SyncDataList(), std::move(processor_), std::unique_ptr<syncer::SyncErrorFactory>()); @@ -414,10 +410,8 @@ form2.signon_realm = kSignonRealm2; form2.action = GURL("http://bar.com"); form2.blacklisted_by_user = true; - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(AppendForm(form1)); - EXPECT_CALL(*password_store(), FillBlacklistLogins(_)) - .WillOnce(AppendForm(form2)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)) + .WillOnce(Append2Forms(form1, form2)); SyncDataList actual_list = service()->GetAllSyncData(syncer::PASSWORDS); std::vector<autofill::PasswordForm> actual_form_list; @@ -444,14 +438,9 @@ form2.action = GURL("http://bar.com"); form2.username_value = base::ASCIIToUTF16(kUsername); form2.password_value = base::ASCIIToUTF16(kPassword); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(AppendForm(form1)); - EXPECT_CALL(*password_store(), FillBlacklistLogins(_)).WillOnce(Return(true)); - EXPECT_CALL(*other_service_wrapper.password_store(), - FillAutofillableLogins(_)) + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(AppendForm(form1)); + EXPECT_CALL(*other_service_wrapper.password_store(), ReadAllLogins(_)) .WillOnce(AppendForm(form2)); - EXPECT_CALL(*other_service_wrapper.password_store(), FillBlacklistLogins(_)) - .WillOnce(Return(true)); // This method reads all passwords from the database. Make sure that the // database is not read twice if there was no problem getting all the // passwords during the first read. @@ -498,8 +487,7 @@ syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR, "Failed to get passwords from store.", syncer::PASSWORDS); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(Return(false)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(Return(false)); if (base::FeatureList::IsEnabled(features::kRecoverPasswordsForSyncUsers)) { EXPECT_CALL(*password_store(), DeleteUndecryptableLogins()) .WillOnce(Return(DatabaseCleanupResult::kDatabaseUnavailable)); @@ -533,8 +521,7 @@ EXPECT_CALL(*error_factory, CreateAndUploadError(_, _)) .WillOnce(Return(error)); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(Return(false)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(Return(false)); EXPECT_CALL(*password_store(), DeleteUndecryptableLogins()).Times(0); syncer::SyncMergeResult result = service()->MergeDataAndStartSyncing( @@ -554,13 +541,12 @@ {features::kDeleteCorruptedPasswords}); EXPECT_CALL(*processor_, ProcessSyncChanges(_, IsEmpty())); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) + EXPECT_CALL(*password_store(), ReadAllLogins(_)) .Times(2) .WillOnce(Return(false)) .WillOnce(Return(true)); EXPECT_CALL(*password_store(), DeleteUndecryptableLogins()) .WillOnce(Return(DatabaseCleanupResult::kSuccess)); - EXPECT_CALL(*password_store(), FillBlacklistLogins(_)).WillOnce(Return(true)); syncer::SyncMergeResult result = service()->MergeDataAndStartSyncing( syncer::PASSWORDS, SyncDataList(), std::move(processor_), nullptr); @@ -584,8 +570,7 @@ EXPECT_CALL(*error_factory, CreateAndUploadError(_, _)) .WillOnce(Return(error)); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(Return(false)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(Return(false)); EXPECT_CALL(*password_store(), DeleteUndecryptableLogins()).Times(0); syncer::SyncMergeResult result = service()->MergeDataAndStartSyncing( @@ -608,8 +593,7 @@ EXPECT_CALL(*error_factory, CreateAndUploadError(_, _)) .WillOnce(Return(error)); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(Return(false)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(Return(false)); EXPECT_CALL(*password_store(), DeleteUndecryptableLogins()) .WillOnce(Return(DatabaseCleanupResult::kEncryptionUnavailable)); @@ -630,9 +614,7 @@ new syncer::SyncErrorFactoryMock); syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR, "There is a problem", syncer::PASSWORDS); - EXPECT_CALL(*password_store(), FillAutofillableLogins(_)) - .WillOnce(AppendForm(form)); - EXPECT_CALL(*password_store(), FillBlacklistLogins(_)).WillOnce(Return(true)); + EXPECT_CALL(*password_store(), ReadAllLogins(_)).WillOnce(AppendForm(form)); // ActOnPasswordStoreChanges() below shouldn't generate any changes for Sync. // |processor_| will be destroyed in MergeDataAndStartSyncing().
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc index 47e4705..d6d8848 100644 --- a/components/password_manager/core/browser/test_password_store.cc +++ b/components/password_manager/core/browser/test_password_store.cc
@@ -220,6 +220,17 @@ return true; } +bool TestPasswordStore::ReadAllLogins(PrimaryKeyToFormMap* key_to_form_map) { + NOTIMPLEMENTED(); + return true; +} + +PasswordStoreChangeList TestPasswordStore::RemoveLoginByPrimaryKeySync( + int primary_key) { + NOTIMPLEMENTED(); + return PasswordStoreChangeList(); +} + syncer::SyncMetadataStore* TestPasswordStore::GetMetadataStore() { return nullptr; }
diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h index d5be4bc..a7c6d71b 100644 --- a/components/password_manager/core/browser/test_password_store.h +++ b/components/password_manager/core/browser/test_password_store.h
@@ -90,6 +90,8 @@ // PasswordStoreSync interface. bool BeginTransaction() override; bool CommitTransaction() override; + bool ReadAllLogins(PrimaryKeyToFormMap* key_to_form_map) override; + PasswordStoreChangeList RemoveLoginByPrimaryKeySync(int primary_key) override; syncer::SyncMetadataStore* GetMetadataStore() override; private:
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto index b9c0edb6..6a8612a1 100644 --- a/components/policy/proto/device_management_backend.proto +++ b/components/policy/proto/device_management_backend.proto
@@ -780,6 +780,8 @@ optional string cpu_label = 1; // CPU temperature in Celsius. optional int32 cpu_temp = 2; + // Unix timestamp. + optional int64 timestamp = 3; } // Chrome release channel, shared for different reports. @@ -800,7 +802,9 @@ optional int64 remaining_capacity = 3; // Temperature in Celsius. optional int32 temperature = 4; - // TODO(crbug/916991): We should also include battery charge rate here. + // The battery discharge rate measured in mW. Positive if the battery is being + // discharged, negative if it's being charged. + optional int32 discharge_rate = 5; } // Status of the single battery
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index ae0b0f2e..8294c7b3 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -729,6 +729,230 @@ 'desc': '''Configure <ph name="PLUGIN_VM_NAME">PluginVm</ph> related policies.''', }, { + 'name': 'Signin', + 'type': 'group', + 'caption': '''Sign-in settings''', + 'desc': '''Controls the behavior of the sign-in screen, where users log into their accounts. Settings include who can log in, what type of accounts are allowed, what authentication methods should be used, as well as general accessibility, input method and locale settings.''', + 'policies': [ + 'DeviceGuestModeEnabled', + 'DeviceUserWhitelist', + 'DeviceAllowNewUsers', + 'DeviceLoginScreenDomainAutoComplete', + 'DeviceShowUserNamesOnSignin', + 'DeviceWallpaperImage', + 'DeviceEphemeralUsersEnabled', + 'LoginAuthenticationBehavior', + 'DeviceSamlLoginAuthenticationType', + 'DeviceTransferSAMLCookies', + 'LoginVideoCaptureAllowedUrls', + 'DeviceStartUpFlags', + 'DeviceLoginScreenAppInstallList', + 'DeviceLoginScreenLocales', + 'DeviceLoginScreenInputMethods', + 'DeviceSecondFactorAuthentication', + 'DeviceLoginScreenIsolateOrigins', + 'DeviceLoginScreenSitePerProcess', + 'DeviceLoginScreenAutoSelectCertificateForUrls', + ], + }, + { + 'name': 'UserAndDeviceReporting', + 'type': 'group', + 'caption': '''User and device reporting''', + 'desc': '''Controls what kind of user and device information is reported.''', + 'policies': [ + 'ReportDeviceVersionInfo', + 'ReportDeviceBootMode', + 'ReportDeviceUsers', + 'ReportDeviceActivityTimes', + 'ReportDeviceLocation', + 'ReportDeviceNetworkInterfaces', + 'ReportDeviceHardwareStatus', + 'ReportDeviceSessionStatus', + 'ReportDeviceBoardStatus', + 'ReportDevicePowerStatus', + 'ReportDeviceStorageStatus', + 'ReportUploadFrequency', + 'ReportArcStatusEnabled', + 'HeartbeatEnabled', + 'HeartbeatFrequency', + 'LogUploadEnabled', + 'DeviceMetricsReportingEnabled', + ], + }, + { + 'name': 'Network', + 'type': 'group', + 'caption': '''Network settings''', + 'desc': '''Controls device-wide network configuration.''', + 'policies': [ + 'DeviceOpenNetworkConfiguration', + 'DeviceDataRoamingEnabled', + 'NetworkThrottlingEnabled', + 'DeviceHostnameTemplate', + 'DeviceWiFiFastTransitionEnabled' + ], + }, + { + 'name': 'DeviceUpdate', + 'type': 'group', + 'caption': '''Device update settings''', + 'desc': '''Controls how and when Chrome OS updates are applied.''', + 'policies': [ + 'ChromeOsReleaseChannel', + 'ChromeOsReleaseChannelDelegated', + 'DeviceAutoUpdateDisabled', + 'DeviceAutoUpdateP2PEnabled', + 'DeviceAutoUpdateTimeRestrictions', + 'DeviceTargetVersionPrefix', + 'DeviceUpdateStagingSchedule', + 'DeviceUpdateScatterFactor', + 'DeviceUpdateAllowedConnectionTypes', + 'DeviceUpdateHttpDownloadsEnabled', + 'RebootAfterUpdate', + 'MinimumRequiredChromeVersion', + 'DeviceRollbackToTargetVersion', + 'DeviceRollbackAllowedMilestones', + ], + }, + { + 'name': 'PowerAndShutdown', + 'type': 'group', + 'caption': '''Power and shutdown''', + 'desc': '''Controls settings related to power management and rebooting.''', + 'policies': [ + 'DeviceLoginScreenPowerManagement', + 'UptimeLimit', + 'DeviceRebootOnShutdown', + ], + }, + { + 'name': 'Kiosk', + 'type': 'group', + 'caption': '''Kiosk settings''', + 'desc': '''Controls public session and kiosk account types.''', + 'policies': [ + 'DeviceLocalAccounts', + 'DeviceLocalAccountAutoLoginId', + 'DeviceLocalAccountAutoLoginDelay', + 'DeviceLocalAccountAutoLoginBailoutEnabled', + 'DeviceLocalAccountPromptForNetworkWhenOffline', + 'AllowKioskAppControlChromeVersion', + ], + }, + { + 'name': 'Other', + 'type': 'group', + 'caption': '''Other''', + 'desc': '''Controls miscellaneous settings including USB, bluetooth, policy refresh, developer mode and others.''', + 'policies': [ + 'UsbDetachableWhitelist', + 'DeviceAllowBluetooth', + 'TPMFirmwareUpdateSettings', + 'DeviceEcryptfsMigrationStrategy', + 'DevicePolicyRefreshRate', + 'DeviceBlockDevmode', + 'DeviceAllowRedeemChromeOsRegistrationOffers', + 'DeviceQuirksDownloadEnabled', + 'ExtensionCacheSize', + 'DeviceOffHours' + ], + }, + { + 'name': 'DateAndTime', + 'type': 'group', + 'caption': '''Date and time''', + 'desc': '''Controls clock and time zone settings.''', + 'policies': [ + 'SystemTimezone', + 'SystemTimezoneAutomaticDetection', + 'SystemUse24HourClock', + ] + }, + { + 'name': 'Display', + 'type': 'group', + 'caption': '''Display''', + 'desc': '''Controls display settings.''', + 'policies': [ + 'DeviceDisplayResolution', + 'DisplayRotationDefault', + ] + }, + { + 'name': 'Printing', + 'type': 'group', + 'caption': '''Printing''', + 'desc': '''Controls printing settings.''', + 'policies': [ + 'PrintingEnabled', + 'CloudPrintProxyEnabled', + 'PrintingAllowedColorModes', + 'PrintingAllowedDuplexModes', + 'PrintingAllowedPageSizes', + 'PrintingColorDefault', + 'PrintingDuplexDefault', + 'PrintingSizeDefault', + 'PrintingSendUsernameAndFilenameEnabled', + 'CloudPrintSubmitEnabled', + 'DisablePrintPreview', + 'PrintHeaderFooter', + 'DefaultPrinterSelection', + 'NativePrinters', + 'NativePrintersBulkConfiguration', + 'NativePrintersBulkAccessMode', + 'NativePrintersBulkBlacklist', + 'NativePrintersBulkWhitelist', + 'DeviceNativePrinters', + 'DeviceNativePrintersAccessMode', + 'DeviceNativePrintersBlacklist', + 'DeviceNativePrintersWhitelist', + 'PrintPreviewUseSystemDefaultPrinter', + 'UserNativePrintersAllowed', + ] + }, + { + 'name': 'ActiveDirectoryManagement', + 'type': 'group', + 'caption': '''<ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> management settings''', + 'desc': '''Controls settings specific to <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> managed <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> devices.''', + 'policies': [ + 'DeviceMachinePasswordChangeRate', + 'DeviceUserPolicyLoopbackProcessingMode', + 'DeviceKerberosEncryptionTypes', + 'DeviceGpoCacheLifetime', + 'DeviceAuthDataCacheLifetime', + ] + }, + { + 'name': 'Arc', + 'type': 'group', + 'caption': '''Android settings''', + 'desc': '''Controls settings for the Android container (ARC) and Android apps.''', + 'policies': [ + 'ArcEnabled', + 'UnaffiliatedArcAllowed', + 'ArcPolicy', + 'ArcAppInstallEventLoggingEnabled', + 'ArcBackupRestoreServiceEnabled', + 'ArcGoogleLocationServicesEnabled', + 'ArcCertificatesSyncMode', + 'ArcBackupRestoreEnabled', + 'ArcLocationServiceEnabled' + ] + }, + { + 'name': 'Crostini', + 'type': 'group', + 'caption': '''Linux container''', + 'desc': '''Controls settings for the Linux container (Crostini).''', + 'policies': [ + 'VirtualMachinesAllowed', + 'CrostiniAllowed', + 'DeviceUnaffiliatedCrostiniAllowed', + ] + }, + { 'name': 'HomepageLocation', 'type': 'string', 'schema': { 'type': 'string' }, @@ -4367,9 +4591,16 @@ 'properties': { 'ISSUER': { 'type': 'object', + 'id': 'CertPrincipalFields', 'properties': { 'CN': { 'type': 'string'}, + 'L': { 'type': 'string'}, + 'O': { 'type': 'string'}, + 'OU': { 'type': 'string'}, } + }, + 'SUBJECT': { + '$ref': 'CertPrincipalFields', } } } @@ -4381,13 +4612,13 @@ 'dynamic_refresh': True, 'per_profile': True, }, - 'example_value': ['{"pattern":"https://www.example.com","filter":{"ISSUER":{"CN":"certificate issuer name"}}}'], + 'example_value': ['{"pattern":"https://www.example.com","filter":{"ISSUER":{"CN":"certificate issuer name", "L": "certificate issuer location", "O": "certificate issuer org", "OU": "certificate issuer org unit"}, "SUBJECT":{"CN":"certificate subject name", "L": "certificate subject location", "O": "certificate subject org", "OU": "certificate subject org unit"}}}'], 'id': 102, 'caption': '''Automatically select client certificates for these sites''', 'tags': ['website-sharing'], 'desc': '''Allows you to specify a list of url patterns that specify sites for which <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> should automatically select a client certificate, if the site requests a certificate. - The value must be an array of stringified JSON dictionaries. Each dictionary must have the form { "pattern": "$URL_PATTERN", "filter" : $FILTER }, where $URL_PATTERN is a content setting pattern. $FILTER restricts from which client certificates the browser will automatically select. Independent of the filter, only certificates will be selected that match the server's certificate request. If $FILTER has the form { "ISSUER": { "CN": "$ISSUER_CN" } }, additionally only client certificates are selected that are issued by a certificate with the CommonName $ISSUER_CN. If $FILTER is the empty dictionary {}, the selection of client certificates is not additionally restricted. + The value must be an array of stringified JSON dictionaries. Each dictionary must have the form { "pattern": "$URL_PATTERN", "filter" : $FILTER }, where $URL_PATTERN is a content setting pattern. $FILTER restricts from which client certificates the browser will automatically select. Independent of the filter, only certificates will be selected that match the server's certificate request. For example, if $FILTER has the form { "ISSUER": { "CN": "$ISSUER_CN" } }, additionally only client certificates are selected that are issued by a certificate with the CommonName $ISSUER_CN. If $FILTER contains an "ISSUER" and a "SUBJECT" section, a client certificate must satisfy both conditions to be selected. If $FILTER specifies an organization ("O"), a certificate must have at least one organization which matches the specified value to be selected. If $FILTER specifies an organization unit ("OU"), a certificate must have at least one organization unit which matches the specified value to be selected. If $FILTER is the empty dictionary {}, the selection of client certificates is not additionally restricted. If this policy is left not set, no auto-selection will be done for any site.''', }, @@ -13802,7 +14033,7 @@ 'mode': { 'type': 'string', 'enum': [ - 'drop_down', + 'drop_down', 'pre_mount', ] } }, @@ -13826,7 +14057,7 @@ 'tags': [], 'desc': '''Specifies a list of preconfigued network file shares. - Each list item of the policy is an object with two members: "share_url" and "mode". "share_url" should be the URL of the share and "mode" should be "drop_down" which indicates that "share_url" will be added to the share discovery drop down.''', + Each list item of the policy is an object with two members: "share_url" and "mode". "share_url" should be the URL of the share and "mode" should be either "drop_down" or "pre_mount". "drop_down" mode indicates that "share_url" will be added to the share discovery drop down. "pre_mount" mode indicates that "share_url" will be mounted.''', }, { 'name': 'ScreenBrightnessPercent',
diff --git a/components/previews/content/hint_cache.cc b/components/previews/content/hint_cache.cc index a125f276..72a3cf94 100644 --- a/components/previews/content/hint_cache.cc +++ b/components/previews/content/hint_cache.cc
@@ -74,6 +74,7 @@ HintCacheStore::EntryKey hint_entry_key; if (!FindHintEntryKey(host, &hint_entry_key)) { + std::move(callback).Run(nullptr); return; }
diff --git a/components/previews/content/hint_cache.h b/components/previews/content/hint_cache.h index a30163f..0d820240 100644 --- a/components/previews/content/hint_cache.h +++ b/components/previews/content/hint_cache.h
@@ -63,8 +63,7 @@ bool HasHint(const std::string& host) const; // Requests that hint data for |host| be loaded asynchronously and passed to - // |callback| if/when loaded. |callback| will not be called if no hint data - // is found for |host|. + // |callback| if/when loaded. void LoadHint(const std::string& host, HintLoadedCallback callback); // Returns the hint data for |host| if found in memory, otherwise nullptr.
diff --git a/components/previews/content/previews_optimization_guide.cc b/components/previews/content/previews_optimization_guide.cc index c872c264..cc16e22f 100644 --- a/components/previews/content/previews_optimization_guide.cc +++ b/components/previews/content/previews_optimization_guide.cc
@@ -142,6 +142,11 @@ const optimization_guide::proto::Hint* loaded_hint) const { DCHECK(ui_task_runner_->BelongsToCurrentThread()); + // Record that the hint finished loading. This is used as a signal during + // tests. + LOCAL_HISTOGRAM_BOOLEAN( + kPreviewsOptimizationGuideOnLoadedHintResultHistogramString, loaded_hint); + // Run the callback now that the hint is loaded. This is used as a signal by // tests. std::move(callback).Run();
diff --git a/components/previews/core/previews_constants.cc b/components/previews/core/previews_constants.cc index c6d2a8a0..7597b091 100644 --- a/components/previews/core/previews_constants.cc +++ b/components/previews/core/previews_constants.cc
@@ -9,4 +9,7 @@ const char kPreviewsOptimizationGuideUpdateHintsResultHistogramString[] = "PreviewsOptimizationGuide.UpdateHints.Result"; +const char kPreviewsOptimizationGuideOnLoadedHintResultHistogramString[] = + "PreviewsOptimizationGuide.OnLoadedHint.Result"; + } // namespace previews
diff --git a/components/previews/core/previews_constants.h b/components/previews/core/previews_constants.h index c99eb1e..87216f4 100644 --- a/components/previews/core/previews_constants.h +++ b/components/previews/core/previews_constants.h
@@ -11,6 +11,10 @@ // UpdateHints(). extern const char kPreviewsOptimizationGuideUpdateHintsResultHistogramString[]; +// The local histogram used by PreviewsOptimizationGuide to record that a hint +// finished loading. +extern const char kPreviewsOptimizationGuideOnLoadedHintResultHistogramString[]; + } // namespace previews #endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_CONSTANTS_H_
diff --git a/components/printing/common/print_messages.h b/components/printing/common/print_messages.h index 7dd892f..1802034 100644 --- a/components/printing/common/print_messages.h +++ b/components/printing/common/print_messages.h
@@ -443,19 +443,6 @@ PrintMsg_PrintPages_Params /* settings chosen by the user*/) -#if defined(OS_ANDROID) -// Asks the browser to create a temporary file for the renderer to fill -// in resulting MetafileSkia in printing. -IPC_SYNC_MESSAGE_CONTROL1_2(PrintHostMsg_AllocateTempFileForPrinting, - int /* render_frame_id */, - base::FileDescriptor /* temp file fd */, - int /* fd in browser*/) -IPC_MESSAGE_CONTROL3(PrintHostMsg_TempFileForPrintingWritten, - int /* render_frame_id */, - int /* fd in browser */, - int /* page count */) -#endif // defined(OS_ANDROID) - #if BUILDFLAG(ENABLE_PRINT_PREVIEW) // Asks the browser to do print preview. IPC_MESSAGE_ROUTED1(PrintHostMsg_RequestPrintPreview,
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc index 0af11fb..cd93068 100644 --- a/components/printing/renderer/print_render_frame_helper.cc +++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -1762,12 +1762,10 @@ const PrintMsg_PrintPages_Params& params = *print_pages_params_; const PrintMsg_Print_Params& print_params = params.params; -#if !defined(OS_ANDROID) // TODO(vitalybuka): should be page_count or valid pages from params.pages. // See http://crbug.com/161576 Send(new PrintHostMsg_DidGetPrintedPagesCount( routing_id(), print_params.document_cookie, page_count)); -#endif // !defined(OS_ANDROID) if (print_params.preview_ui_id < 0) { // Printing for system dialog.
diff --git a/components/printing/renderer/print_render_frame_helper_linux.cc b/components/printing/renderer/print_render_frame_helper_linux.cc index 73bf232..9317bf9 100644 --- a/components/printing/renderer/print_render_frame_helper_linux.cc +++ b/components/printing/renderer/print_render_frame_helper_linux.cc
@@ -7,41 +7,13 @@ #include <stddef.h> #include "base/logging.h" +#include "base/process/process_handle.h" #include "build/build_config.h" #include "components/printing/common/print_messages.h" #include "printing/buildflags/buildflags.h" #include "printing/metafile_skia.h" #include "printing/metafile_skia_wrapper.h" -#if defined(OS_ANDROID) -#include "base/file_descriptor_posix.h" -#else -#include "base/process/process_handle.h" -#endif // defined(OS_ANDROID) - -namespace { - -#if defined(OS_ANDROID) -bool SaveToFD(const printing::Metafile& metafile, - const base::FileDescriptor& fd) { - DCHECK_GT(metafile.GetDataSize(), 0U); - - if (fd.fd < 0) { - DLOG(ERROR) << "Invalid file descriptor!"; - return false; - } - base::File file(fd.fd); - bool result = metafile.SaveTo(&file); - DLOG_IF(ERROR, !result) << "Failed to save file with fd " << fd.fd; - - if (!fd.auto_close) - file.TakePlatformFile(); - return result; -} -#endif // defined(OS_ANDROID) - -} // namespace - namespace printing { bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame, @@ -69,21 +41,6 @@ metafile.FinishDocument(); -#if defined(OS_ANDROID) - int sequence_number = -1; - base::FileDescriptor fd; - - // Ask the browser to open a file for us. - Send(new PrintHostMsg_AllocateTempFileForPrinting(routing_id(), &fd, - &sequence_number)); - if (!SaveToFD(metafile, fd)) - return false; - - // Tell the browser we've finished writing the file. - Send(new PrintHostMsg_TempFileForPrintingWritten( - routing_id(), sequence_number, printed_pages.size())); - return true; -#else PrintHostMsg_DidPrintDocument_Params page_params; if (!CopyMetafileDataToReadOnlySharedMem(metafile, &page_params.content)) { return false; @@ -92,7 +49,6 @@ page_params.document_cookie = print_params.document_cookie; Send(new PrintHostMsg_DidPrintDocument(routing_id(), page_params)); return true; -#endif // defined(OS_ANDROID) } } // namespace printing
diff --git a/components/safe_browsing/browser/safe_browsing_network_context.cc b/components/safe_browsing/browser/safe_browsing_network_context.cc index 9388024..5f1f917 100644 --- a/components/safe_browsing/browser/safe_browsing_network_context.cc +++ b/components/safe_browsing/browser/safe_browsing_network_context.cc
@@ -8,6 +8,7 @@ #include <utility> #include "base/bind.h" +#include "base/files/file_util.h" #include "base/task/post_task.h" #include "components/safe_browsing/common/safebrowsing_constants.h" #include "content/public/browser/browser_task_traits.h" @@ -21,6 +22,17 @@ namespace safe_browsing { +namespace { + +void DeleteChannelIDFiles(base::FilePath channel_id_path) { + base::DeleteFile(channel_id_path, false); + base::DeleteFile( + base::FilePath(channel_id_path.value() + FILE_PATH_LITERAL("-journal")), + false); +} + +} // namespace + class SafeBrowsingNetworkContext::SharedURLLoaderFactory : public network::SharedURLLoaderFactory { public: @@ -170,6 +182,16 @@ network_context_params->cookie_path = cookie_path; network_context_params->enable_encrypted_cookies = false; + // TODO(nharper): Remove the following when no longer needed - see + // crbug.com/903642. + base::FilePath::StringType channel_id_path = + base::FilePath::StringType(kSafeBrowsingBaseFilename) + kChannelIDFile; + base::PostTaskWithTraits( + FROM_HERE, + {base::TaskPriority::BEST_EFFORT, base::MayBlock(), + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce(DeleteChannelIDFiles, base::FilePath(channel_id_path))); + return network_context_params; }
diff --git a/components/search_provider_logos/google_logo_api_unittest.cc b/components/search_provider_logos/google_logo_api_unittest.cc index 38e2189..1e63d72 100644 --- a/components/search_provider_logos/google_logo_api_unittest.cc +++ b/components/search_provider_logos/google_logo_api_unittest.cc
@@ -371,6 +371,7 @@ EXPECT_EQ(LogoType::INTERACTIVE, logo->metadata.type); EXPECT_EQ(500, logo->metadata.iframe_width_px); EXPECT_EQ(200, logo->metadata.iframe_height_px); + EXPECT_EQ(nullptr, logo->encoded_image); } TEST(GoogleNewLogoApiTest, ParsesInteractiveDoodleWithNewWindowAsSimple) {
diff --git a/components/search_provider_logos/logo_cache.cc b/components/search_provider_logos/logo_cache.cc index a06f4019..f350805 100644 --- a/components/search_provider_logos/logo_cache.cc +++ b/components/search_provider_logos/logo_cache.cc
@@ -35,6 +35,8 @@ const char kLogUrlKey[] = "log_url"; const char kCtaLogUrlKey[] = "cta_log_url"; const char kShortLinkKey[] = "short_link"; +const char kIframeWidthPx[] = "iframe_width_px"; +const char kIframeHeightPx[] = "iframe_height_px"; const char kShareButtonX[] = "share_button_x"; const char kShareButtonY[] = "share_button_y"; @@ -124,13 +126,16 @@ void LogoCache::SetCachedLogo(const EncodedLogo* logo) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - std::unique_ptr<LogoMetadata> metadata; - if (logo) { - metadata = std::make_unique<LogoMetadata>(logo->metadata); - logo_num_bytes_ = static_cast<int>(logo->encoded_image->size()); + if (!logo) { + UpdateMetadata(nullptr); + DeleteLogoAndMetadata(); + return; } - UpdateMetadata(std::move(metadata)); - WriteLogo(logo ? logo->encoded_image : nullptr); + + logo_num_bytes_ = + logo->encoded_image ? static_cast<int>(logo->encoded_image->size()) : 0; + UpdateMetadata(std::make_unique<LogoMetadata>(logo->metadata)); + WriteLogo(logo->encoded_image); } std::unique_ptr<EncodedLogo> LogoCache::GetCachedLogo() { @@ -140,18 +145,21 @@ if (!metadata_) return nullptr; - scoped_refptr<base::RefCountedString> encoded_image = - new base::RefCountedString(); - if (!base::ReadFileToString(GetLogoPath(), &encoded_image->data())) { - UpdateMetadata(nullptr); - return nullptr; - } + scoped_refptr<base::RefCountedString> encoded_image; + if (logo_num_bytes_ != 0) { + encoded_image = new base::RefCountedString(); - if (encoded_image->size() != static_cast<size_t>(logo_num_bytes_)) { - // Delete corrupt metadata and logo. - DeleteLogoAndMetadata(); - UpdateMetadata(nullptr); - return nullptr; + if (!base::ReadFileToString(GetLogoPath(), &encoded_image->data())) { + UpdateMetadata(nullptr); + return nullptr; + } + + if (encoded_image->size() != static_cast<size_t>(logo_num_bytes_)) { + // Delete corrupt metadata and logo. + DeleteLogoAndMetadata(); + UpdateMetadata(nullptr); + return nullptr; + } } std::unique_ptr<EncodedLogo> logo(new EncodedLogo()); @@ -197,6 +205,8 @@ !dict->GetDouble(kShareButtonOpacity, &metadata->share_button_opacity) || !dict->GetString(kShareButtonIcon, &metadata->share_button_icon) || !dict->GetString(kShareButtonBg, &metadata->share_button_bg) || + !dict->GetInteger(kIframeWidthPx, &metadata->iframe_width_px) || + !dict->GetInteger(kIframeHeightPx, &metadata->iframe_height_px) || !GetTimeValue(*dict, kExpirationTimeKey, &metadata->expiration_time)) { return nullptr; } @@ -236,6 +246,8 @@ dict.SetDouble(kShareButtonOpacity, metadata.share_button_opacity); dict.SetString(kShareButtonIcon, metadata.share_button_icon); dict.SetString(kShareButtonBg, metadata.share_button_bg); + dict.SetInteger(kIframeWidthPx, metadata.iframe_width_px); + dict.SetInteger(kIframeHeightPx, metadata.iframe_height_px); SetTimeValue(dict, kExpirationTimeKey, metadata.expiration_time); base::JSONWriter::Write(dict, str); } @@ -284,7 +296,7 @@ if (!EnsureCacheDirectoryExists()) return; - if (!metadata_ || !encoded_image) { + if (!metadata_) { DeleteLogoAndMetadata(); return; } @@ -298,10 +310,9 @@ if (!base::DeleteFile(metadata_path, false)) return; - if (base::WriteFile( - logo_path, - encoded_image->front_as<char>(), - static_cast<int>(encoded_image->size())) == -1) { + if (encoded_image && + base::WriteFile(logo_path, encoded_image->front_as<char>(), + static_cast<int>(encoded_image->size())) == -1) { base::DeleteFile(logo_path, false); return; }
diff --git a/components/search_provider_logos/logo_cache_unittest.cc b/components/search_provider_logos/logo_cache_unittest.cc index e8122f5..82714fd6 100644 --- a/components/search_provider_logos/logo_cache_unittest.cc +++ b/components/search_provider_logos/logo_cache_unittest.cc
@@ -82,6 +82,13 @@ return logo; } +std::unique_ptr<EncodedLogo> GetExampleLogoWithoutImage() { + auto logo = std::make_unique<EncodedLogo>(); + logo->encoded_image = nullptr; + logo->metadata = GetExampleMetadata2(); + return logo; +} + void ExpectMetadataEqual(const LogoMetadata& expected_metadata, const LogoMetadata& actual_metadata) { EXPECT_EQ(expected_metadata.source_url, actual_metadata.source_url); @@ -155,6 +162,14 @@ } } + void ExpectLogoWithoutImage(const EncodedLogo* expected_logo) { + std::unique_ptr<EncodedLogo> retrieved_logo(cache_->GetCachedLogo()); + ASSERT_TRUE(retrieved_logo.get()); + ASSERT_FALSE(retrieved_logo->encoded_image.get()); + ASSERT_FALSE(expected_logo->encoded_image.get()); + ExpectMetadataEqual(expected_logo->metadata, retrieved_logo->metadata); + } + // Deletes the existing LogoCache and creates a new one. This clears any // logo or metadata cached in memory to simulate restarting Chrome. void SimulateRestart() { @@ -244,6 +259,33 @@ ExpectLogo(logo.get()); } +TEST_F(LogoCacheTest, StoreAndRetrieveLogoWithoutImage) { + // Expect no metadata at first. + ExpectLogo(nullptr); + + // Set initial logo. + std::unique_ptr<EncodedLogo> logo = GetExampleLogoWithoutImage(); + cache_->SetCachedLogo(logo.get()); + ExpectLogoWithoutImage(logo.get()); + + // Update logo to null. + cache_->SetCachedLogo(nullptr); + ExpectLogo(nullptr); + + // Read logo back from disk. + SimulateRestart(); + ExpectLogo(nullptr); + + // Update logo. + logo = GetExampleLogoWithoutImage(); + cache_->SetCachedLogo(logo.get()); + ExpectLogoWithoutImage(logo.get()); + + // Read logo back from disk. + SimulateRestart(); + ExpectLogoWithoutImage(logo.get()); +} + TEST_F(LogoCacheTest, RetrieveCorruptMetadata) { // Set initial logo. std::unique_ptr<EncodedLogo> logo = GetExampleLogo2();
diff --git a/components/search_provider_logos/logo_service_impl.cc b/components/search_provider_logos/logo_service_impl.cc index 105e8d9..e2a2de7c 100644 --- a/components/search_provider_logos/logo_service_impl.cc +++ b/components/search_provider_logos/logo_service_impl.cc
@@ -391,7 +391,7 @@ std::unique_ptr<EncodedLogo> cached_logo) { DCHECK(!is_idle_); - if (cached_logo) { + if (cached_logo && cached_logo->encoded_image) { // Store the value of logo->encoded_image for use below. This ensures that // logo->encoded_image is evaulated before base::Passed(&logo), which sets // logo to NULL. @@ -402,6 +402,8 @@ ImageDecodedHandlerWithTimeout::Wrap(base::BindRepeating( &LogoServiceImpl::OnCachedLogoAvailable, weak_ptr_factory_.GetWeakPtr(), base::Passed(&cached_logo)))); + } else if (cached_logo) { + OnCachedLogoAvailable(std::move(cached_logo), SkBitmap()); } else { OnCachedLogoAvailable({}, SkBitmap()); } @@ -425,7 +427,7 @@ const SkBitmap& image) { DCHECK(!is_idle_); - if (!image.isNull()) { + if (encoded_logo && encoded_logo->encoded_image && !image.isNull()) { cached_logo_.reset(new Logo()); cached_logo_->metadata = encoded_logo->metadata; cached_logo_->image = image; @@ -533,15 +535,24 @@ encoded_logo->metadata.mime_type = cached_logo_->metadata.mime_type; SetCachedMetadata(encoded_logo->metadata); download_outcome = DOWNLOAD_OUTCOME_LOGO_REVALIDATED; - } else if (encoded_logo && image.isNull()) { + } else if (encoded_logo && encoded_logo->encoded_image && image.isNull()) { // Image decoding failed. Do nothing. download_outcome = DOWNLOAD_OUTCOME_DECODING_FAILED; + } else if (encoded_logo && !encoded_logo->encoded_image && + encoded_logo->metadata.type != LogoType::INTERACTIVE) { + download_outcome = DOWNLOAD_OUTCOME_MISSING_REQUIRED_IMAGE; +#if defined(OS_ANDROID) || defined(OS_IOS) + } else if (encoded_logo && !encoded_logo->encoded_image) { + // On Mobile interactive doodles require a static CTA image, on Desktop the + // static image is not required as it's handled by the iframed page. + download_outcome = DOWNLOAD_OUTCOME_MISSING_REQUIRED_IMAGE; +#endif } else { // Check if the server returned a valid, non-empty response. if (encoded_logo) { UMA_HISTOGRAM_BOOLEAN("NewTabPage.LogoImageDownloaded", from_http_cache); - DCHECK(!image.isNull()); + DCHECK(!encoded_logo->encoded_image || !image.isNull()); logo.reset(new Logo()); logo->metadata = encoded_logo->metadata; logo->image = image; @@ -578,10 +589,11 @@ } break; + case DOWNLOAD_OUTCOME_MISSING_REQUIRED_IMAGE: case DOWNLOAD_OUTCOME_DOWNLOAD_FAILED: // In the download failed, don't notify the callback at all, since the // callback should continue to use the cached logo. - DCHECK(!encoded_logo); + DCHECK(!encoded_logo || !encoded_logo->encoded_image); DCHECK(!logo); callback_type = LogoCallbackReason::FAILED; break;
diff --git a/components/search_provider_logos/logo_service_impl.h b/components/search_provider_logos/logo_service_impl.h index ca1e89f..b3fb983 100644 --- a/components/search_provider_logos/logo_service_impl.h +++ b/components/search_provider_logos/logo_service_impl.h
@@ -88,7 +88,7 @@ private: // These values must stay in sync with the NewTabPageLogoDownloadOutcome enum - // in histograms.xml. And any addtion should be treated as append-only! + // in enums.xml. And any addition should be treated as append-only! // Animated doodle is not covered by this enum. enum LogoDownloadOutcome { DOWNLOAD_OUTCOME_NEW_LOGO_SUCCESS, @@ -97,6 +97,7 @@ DOWNLOAD_OUTCOME_PARSING_FAILED, DOWNLOAD_OUTCOME_DECODING_FAILED, DOWNLOAD_OUTCOME_LOGO_REVALIDATED, + DOWNLOAD_OUTCOME_MISSING_REQUIRED_IMAGE, DOWNLOAD_OUTCOME_COUNT, };
diff --git a/components/send_tab_to_self/OWNERS b/components/send_tab_to_self/OWNERS index 434391d..a49acc9 100644 --- a/components/send_tab_to_self/OWNERS +++ b/components/send_tab_to_self/OWNERS
@@ -1,5 +1,6 @@ -jeffreycohen@chromium.org -tgupta@chromium.org hansberry@chromium.org +jeffreycohen@chromium.org +sebsg@chromium.org +tgupta@chromium.org -# COMPONENT: UI>Browser>Mobile>Share +# COMPONENT: UI>Browser>Sharing
diff --git a/components/services/heap_profiling/public/cpp/BUILD.gn b/components/services/heap_profiling/public/cpp/BUILD.gn index 0abfe8504..44606b2e 100644 --- a/components/services/heap_profiling/public/cpp/BUILD.gn +++ b/components/services/heap_profiling/public/cpp/BUILD.gn
@@ -4,8 +4,6 @@ static_library("cpp") { sources = [ - "allocator_shim.cc", - "allocator_shim.h", "client.cc", "client.h", "controller.cc",
diff --git a/components/services/heap_profiling/public/cpp/allocator_shim.cc b/components/services/heap_profiling/public/cpp/allocator_shim.cc deleted file mode 100644 index aa47348..0000000 --- a/components/services/heap_profiling/public/cpp/allocator_shim.cc +++ /dev/null
@@ -1,571 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/services/heap_profiling/public/cpp/allocator_shim.h" - -#include "base/allocator/buildflags.h" -#include "base/atomicops.h" -#include "base/compiler_specific.h" -#include "base/debug/debugging_buildflags.h" -#include "base/debug/stack_trace.h" -#include "base/lazy_instance.h" -#include "base/no_destructor.h" -#include "base/sampling_heap_profiler/poisson_allocation_sampler.h" -#include "base/synchronization/lock.h" -#include "base/threading/thread_id_name_manager.h" -#include "base/threading/thread_local_storage.h" -#include "base/trace_event/heap_profiler_event_filter.h" -#include "base/trace_event/memory_dump_manager.h" -#include "build/build_config.h" - -#if defined(OS_POSIX) -#include <pthread.h> -#endif - -#if defined(OS_LINUX) || defined(OS_ANDROID) -#include <sys/prctl.h> -#endif - -#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \ - defined(OFFICIAL_BUILD) -#include "base/trace_event/cfi_backtrace_android.h" -#endif - -using base::trace_event::AllocationContext; -using base::trace_event::AllocationContextTracker; -using CaptureMode = base::trace_event::AllocationContextTracker::CaptureMode; - -namespace heap_profiling { - -// Allocation logging also requires use of base TLS, so we must also check that -// that is available. This means that allocations that occur after base TLS has -// been torn down will not be logged. -// TODO(alph): Get rid of the class. crbug.com/917476 -class ScopedAllowAlloc { - public: - static inline bool HasTLSBeenDestroyed() { - return UNLIKELY(base::ThreadLocalStorage::HasBeenDestroyed()); - } -}; - -namespace { - -bool g_initialized_ = false; -base::LazyInstance<base::Lock>::Leaky g_on_init_allocator_shim_lock_; -base::LazyInstance<base::OnceClosure>::Leaky g_on_init_allocator_shim_callback_; -base::LazyInstance<scoped_refptr<base::TaskRunner>>::Leaky - g_on_init_allocator_shim_task_runner_; - -SenderPipe* g_sender_pipe = nullptr; - -// In NATIVE stack mode, whether to insert stack names into the backtraces. -bool g_include_thread_names = false; - -// Prime since this is used like a hash table. Numbers of this magnitude seemed -// to provide sufficient parallelism to avoid lock overhead in ad-hoc testing. -constexpr int kNumSendBuffers = 17; - -// If writing to the SenderPipe ever takes longer than 10s, just give up. -constexpr int kTimeoutMs = 10000; - -// The allocator shim needs to retain some additional state for each thread. -struct ShimState { - // The pointer must be valid for the lifetime of the process. - const char* thread_name = nullptr; - - // If we are using pseudo stacks, we need to inform the profiling service of - // the address to string mapping. To avoid a global lock, we keep a - // thread-local unordered_set of every address that has been sent from the - // thread in question. - std::unordered_set<const void*> sent_strings; -}; - -// Technically, this code could be called after Thread destruction and we would -// need to guard this with ThreadLocalStorage::HasBeenDestroyed(), but all calls -// to this are guarded behind ScopedAllowAlloc, which already makes the check. -base::ThreadLocalStorage::Slot& ShimStateTLS() { - static base::NoDestructor<base::ThreadLocalStorage::Slot> shim_state_tls( - [](void* shim_state) { delete static_cast<ShimState*>(shim_state); }); - return *shim_state_tls; -} - -// We don't need to worry about re-entrancy because PoissonAllocationSampler -// already guards against that. -ShimState* GetShimState() { - ShimState* state = static_cast<ShimState*>(ShimStateTLS().Get()); - - if (!state) { - state = new ShimState(); - ShimStateTLS().Set(state); - } - - return state; -} - -// Set the thread name, which is a pointer to a leaked string, to ensure -// validity forever. -void SetCurrentThreadName(const char* name) { - GetShimState()->thread_name = name; -} - -// If a thread name has been set from ThreadIdNameManager, use that. Otherwise, -// gets the thread name from kernel if available or returns a string with id. -// This function intentionally leaks the allocated strings since they are used -// to tag allocations even after the thread dies. -const char* GetAndLeakThreadName() { - const char* thread_name = - base::ThreadIdNameManager::GetInstance()->GetNameForCurrentThread(); - if (thread_name && strcmp(thread_name, "") != 0) - return thread_name; - - // prctl requires 16 bytes, snprintf requires 19, pthread_getname_np requires - // 64 on macOS, see PlatformThread::SetName in platform_thread_mac.mm. - constexpr size_t kBufferLen = 64; - char name[kBufferLen]; -#if defined(OS_LINUX) || defined(OS_ANDROID) - // If the thread name is not set, try to get it from prctl. Thread name might - // not be set in cases where the thread started before heap profiling was - // enabled. - int err = prctl(PR_GET_NAME, name); - if (!err) { - return strdup(name); - } -#elif defined(OS_MACOSX) - int err = pthread_getname_np(pthread_self(), name, kBufferLen); - if (err == 0 && name[0] != '\0') { - return strdup(name); - } -#endif // defined(OS_LINUX) || defined(OS_ANDROID) - - // Use tid if we don't have a thread name. - snprintf(name, sizeof(name), "Thread %lu", - static_cast<unsigned long>(base::PlatformThread::CurrentId())); - return strdup(name); -} - -// Returns the thread name, looking it up if necessary. -const char* GetOrSetThreadName() { - const char* thread_name = GetShimState()->thread_name; - if (UNLIKELY(!thread_name)) { - thread_name = GetAndLeakThreadName(); - GetShimState()->thread_name = thread_name; - } - return thread_name; -} - -class SendBuffer { - public: - SendBuffer() : buffer_(new char[SenderPipe::kPipeSize]) {} - ~SendBuffer() { delete[] buffer_; } - - void Send(const void* data, size_t sz) { - base::AutoLock lock(lock_); - - if (used_ + sz > SenderPipe::kPipeSize) - SendCurrentBuffer(); - - memcpy(&buffer_[used_], data, sz); - used_ += sz; - } - - void Flush() { - base::AutoLock lock(lock_); - if (used_ > 0) - SendCurrentBuffer(); - } - - private: - void SendCurrentBuffer() { - SenderPipe::Result result = g_sender_pipe->Send(buffer_, used_, kTimeoutMs); - used_ = 0; - if (result == SenderPipe::Result::kError) { - FlushBuffersAndClosePipe(); - } - if (result == SenderPipe::Result::kTimeout) { - FlushBuffersAndClosePipe(); - // TODO(erikchen): Emit a histogram. https://crbug.com/777546. - } - } - - base::Lock lock_; - - char* buffer_; - size_t used_ = 0; - - DISALLOW_COPY_AND_ASSIGN(SendBuffer); -}; - -// It's safe to call Read() before Write(). Read() will either return nullptr or -// a valid SendBuffer. -class AtomicallyConsistentSendBufferArray { - public: - void Write(SendBuffer* buffer) { - base::subtle::Release_Store( - &send_buffers, reinterpret_cast<base::subtle::AtomicWord>(buffer)); - } - - SendBuffer* Read() { - return reinterpret_cast<SendBuffer*>( - base::subtle::Acquire_Load(&send_buffers)); - } - - private: - // This class is used as a static global. This will be linker-initialized to - // 0. - base::subtle::AtomicWord send_buffers; -}; - -// The API guarantees that Read() will either return a valid object or a -// nullptr. -AtomicallyConsistentSendBufferArray g_send_buffers; - -size_t HashAddress(const void* address) { - // The multiplicative hashing scheme from [Knuth 1998]. - // |a| is the first prime after 2^17. - const uintptr_t key = reinterpret_cast<uintptr_t>(address); - const uintptr_t a = 131101; - const uintptr_t shift = 15; - const uintptr_t h = (key * a) >> shift; - return h; -} - -// "address" is the address in question, which is used to select which send -// buffer to use. -void DoSend(const void* address, - const void* data, - size_t size, - SendBuffer* send_buffers) { - int bin_to_use = HashAddress(address) % kNumSendBuffers; - send_buffers[bin_to_use].Send(data, size); -} - -// Updates an existing in_memory buffer with frame data. If a frame contains a -// pointer to a cstring rather than an instruction pointer, and the profiling -// service has not yet been informed of that pointer -> cstring mapping, sends a -// StringMappingPacket. -class FrameSerializer { - public: - FrameSerializer(uint64_t* stack, - const void* address, - size_t initial_buffer_size, - SendBuffer* send_buffers) - : stack_(stack), - address_(address), - remaining_buffer_size_(initial_buffer_size), - send_buffers_(send_buffers) {} - - void AddAllFrames(const base::trace_event::Backtrace& backtrace) { - CHECK_LE(backtrace.frame_count, kMaxStackEntries); - size_t required_capacity = backtrace.frame_count * sizeof(uint64_t); - CHECK_LE(required_capacity, remaining_buffer_size_); - remaining_buffer_size_ -= required_capacity; - for (int i = base::checked_cast<int>(backtrace.frame_count) - 1; i >= 0; - --i) { - AddFrame(backtrace.frames[i]); - } - } - - void AddAllInstructionPointers(size_t frame_count, - const void* const* frames) { - CHECK_LE(frame_count, kMaxStackEntries); - size_t required_capacity = frame_count * sizeof(uint64_t); - CHECK_LE(required_capacity, remaining_buffer_size_); - remaining_buffer_size_ -= required_capacity; - // If there are too many frames, keep the ones furthest from main(). - for (size_t i = 0; i < frame_count; i++) - AddInstructionPointer(frames[i]); - } - - void AddCString(const char* c_string) { - // Using a TLS cache of sent_strings avoids lock contention on malloc, which - // would kill performance. - std::unordered_set<const void*>* sent_strings = - &GetShimState()->sent_strings; - - if (sent_strings->find(c_string) == sent_strings->end()) { - // No point in allowing arbitrarily long c-strings, which might cause pipe - // max length issues. Pick a reasonable length like 255. - static const size_t kMaxCStringLen = 255; - - // length does not include the null terminator. - size_t length = strnlen(c_string, kMaxCStringLen); - - char message[sizeof(StringMappingPacket) + kMaxCStringLen]; - StringMappingPacket* string_mapping_packet = - new (&message) StringMappingPacket(); - string_mapping_packet->address = reinterpret_cast<uint64_t>(c_string); - string_mapping_packet->string_len = length; - memcpy(message + sizeof(StringMappingPacket), c_string, length); - DoSend(address_, message, sizeof(StringMappingPacket) + length, - send_buffers_); - sent_strings->insert(c_string); - } - - AddInstructionPointer(c_string); - } - - size_t count() { return count_; } - - private: - void AddFrame(const base::trace_event::StackFrame& frame) { - if (frame.type == base::trace_event::StackFrame::Type::PROGRAM_COUNTER) { - AddInstructionPointer(frame.value); - return; - } - - AddCString(static_cast<const char*>(frame.value)); - } - - void AddInstructionPointer(const void* value) { - *stack_ = reinterpret_cast<uint64_t>(value); - ++stack_; - ++count_; - } - - // The next frame should be written to this memory location. There are both - // static and runtime checks to prevent buffer overrun. - static_assert( - base::trace_event::Backtrace::kMaxFrameCount < kMaxStackEntries, - "Ensure that pseudo-stack frame count won't exceed OOP HP frame buffer."); - uint64_t* stack_; - - // The number of frames that have been written to the stack. - size_t count_ = 0; - - const void* address_; - size_t remaining_buffer_size_; - SendBuffer* send_buffers_; -}; - -} // namespace - -void InitTLSSlot() { - base::PoissonAllocationSampler::Init(); - ignore_result(ShimStateTLS()); -} - -// In order for pseudo stacks to work, trace event filtering must be enabled. -void EnableTraceEventFiltering() { - std::string filter_string = base::JoinString( - {"*", TRACE_DISABLED_BY_DEFAULT("net"), TRACE_DISABLED_BY_DEFAULT("cc"), - base::trace_event::MemoryDumpManager::kTraceCategory}, - ","); - base::trace_event::TraceConfigCategoryFilter category_filter; - category_filter.InitializeFromString(filter_string); - - base::trace_event::TraceConfig::EventFilterConfig heap_profiler_filter_config( - base::trace_event::HeapProfilerEventFilter::kName); - heap_profiler_filter_config.SetCategoryFilter(category_filter); - - base::trace_event::TraceConfig::EventFilters filters; - filters.push_back(heap_profiler_filter_config); - base::trace_event::TraceConfig filtering_trace_config; - filtering_trace_config.SetEventFilters(filters); - - base::trace_event::TraceLog::GetInstance()->SetEnabled( - filtering_trace_config, base::trace_event::TraceLog::FILTERING_MODE); -} - -void InitAllocationRecorder(SenderPipe* sender_pipe, - mojom::ProfilingParamsPtr params) { - // Must be done before hooking any functions that make stack traces. - base::debug::EnableInProcessStackDumping(); - - if (params->stack_mode == mojom::StackMode::NATIVE_WITH_THREAD_NAMES) { - g_include_thread_names = true; - base::ThreadIdNameManager::GetInstance()->InstallSetNameCallback( - base::BindRepeating(&SetCurrentThreadName)); - } - - switch (params->stack_mode) { - case mojom::StackMode::PSEUDO: - EnableTraceEventFiltering(); - AllocationContextTracker::SetCaptureMode(CaptureMode::PSEUDO_STACK); - break; - case mojom::StackMode::MIXED: - EnableTraceEventFiltering(); - AllocationContextTracker::SetCaptureMode(CaptureMode::MIXED_STACK); - break; - case mojom::StackMode::NATIVE_WITH_THREAD_NAMES: - case mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES: - // This would track task contexts only. - AllocationContextTracker::SetCaptureMode(CaptureMode::NATIVE_STACK); - break; - } - - g_send_buffers.Write(new SendBuffer[kNumSendBuffers]); - g_sender_pipe = sender_pipe; -} - -void FlushBuffersAndClosePipe() { - // This ShareBuffer array is leaked on purpose to avoid races on Stop. - g_send_buffers.Write(nullptr); - if (g_sender_pipe) - g_sender_pipe->Close(); -} - -void SerializeFramesFromAllocationContext(FrameSerializer* serializer, - const char** context) { - // Allocation context is tracked in TLS. Return nothing if TLS was destroyed. - if (ScopedAllowAlloc::HasTLSBeenDestroyed()) - return; - auto* tracker = AllocationContextTracker::GetInstanceForCurrentThread(); - if (!tracker) - return; - - AllocationContext allocation_context; - if (!tracker->GetContextSnapshot(&allocation_context)) - return; - - serializer->AddAllFrames(allocation_context.backtrace); - if (!*context) - *context = allocation_context.type_name; -} - -void SerializeFramesFromBacktrace(FrameSerializer* serializer, - const char** context) { - // Skip 3 top frames related to the profiler itself, e.g.: - // base::debug::StackTrace::StackTrace - // heap_profiling::RecordAndSendAlloc - // sampling_heap_profiler::PoissonAllocationSampler::DoRecordAlloc - size_t skip_frames = 3; -#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \ - defined(OFFICIAL_BUILD) - const void* frames[kMaxStackEntries - 1]; - size_t frame_count = - base::trace_event::CFIBacktraceAndroid::GetInitializedInstance()->Unwind( - frames, kMaxStackEntries - 1); -#elif BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) - const void* frames[kMaxStackEntries - 1]; - size_t frame_count = base::debug::TraceStackFramePointers( - frames, kMaxStackEntries - 1, skip_frames); - skip_frames = 0; -#else - // Fall-back to capturing the stack with base::debug::StackTrace, - // which is likely slower, but more reliable. - base::debug::StackTrace stack_trace(kMaxStackEntries - 1); - size_t frame_count = 0u; - const void* const* frames = stack_trace.Addresses(&frame_count); -#endif - - skip_frames = std::min(skip_frames, frame_count); - serializer->AddAllInstructionPointers(frame_count - skip_frames, - frames + skip_frames); - - // Both thread name and task context require access to TLS. - if (ScopedAllowAlloc::HasTLSBeenDestroyed()) - return; - - if (g_include_thread_names) { - const char* thread_name = GetOrSetThreadName(); - serializer->AddCString(thread_name); - } - - if (!*context) { - const auto* tracker = - AllocationContextTracker::GetInstanceForCurrentThread(); - if (tracker) - *context = tracker->TaskContext(); - } -} - -void RecordAndSendAlloc(AllocatorType type, - void* address, - size_t sz, - const char* context) { - SendBuffer* send_buffers = g_send_buffers.Read(); - if (!send_buffers) - return; - - constexpr size_t max_message_size = sizeof(AllocPacket) + - kMaxStackEntries * sizeof(uint64_t) + - kMaxContextLen; - static_assert(max_message_size < SenderPipe::kPipeSize, - "We can't have a message size that exceeds the pipe write " - "buffer size."); - char message[max_message_size]; - // TODO(ajwong) check that this is technically valid. - AllocPacket* alloc_packet = reinterpret_cast<AllocPacket*>(message); - - uint64_t* stack = reinterpret_cast<uint64_t*>(&message[sizeof(AllocPacket)]); - - FrameSerializer serializer( - stack, address, max_message_size - sizeof(AllocPacket), send_buffers); - - CaptureMode capture_mode = AllocationContextTracker::capture_mode(); - if (capture_mode == CaptureMode::PSEUDO_STACK || - capture_mode == CaptureMode::MIXED_STACK) { - SerializeFramesFromAllocationContext(&serializer, &context); - } else { - SerializeFramesFromBacktrace(&serializer, &context); - } - - size_t context_len = context ? strnlen(context, kMaxContextLen) : 0; - - alloc_packet->op = kAllocPacketType; - alloc_packet->allocator = type; - alloc_packet->address = (uint64_t)address; - alloc_packet->size = sz; - alloc_packet->stack_len = static_cast<uint32_t>(serializer.count()); - alloc_packet->context_byte_len = static_cast<uint32_t>(context_len); - - char* message_end = message + sizeof(AllocPacket) + - alloc_packet->stack_len * sizeof(uint64_t); - if (context_len > 0) { - memcpy(message_end, context, context_len); - message_end += context_len; - } - DoSend(address, message, message_end - message, send_buffers); -} - -void RecordAndSendFree(void* address) { - SendBuffer* send_buffers = g_send_buffers.Read(); - if (!send_buffers) - return; - - FreePacket free_packet; - free_packet.op = kFreePacketType; - free_packet.address = (uint64_t)address; - - DoSend(address, &free_packet, sizeof(FreePacket), send_buffers); -} - -void AllocatorShimFlushPipe(uint32_t barrier_id) { - SendBuffer* send_buffers = g_send_buffers.Read(); - if (!send_buffers) - return; - for (int i = 0; i < kNumSendBuffers; i++) - send_buffers[i].Flush(); - - BarrierPacket barrier; - barrier.barrier_id = barrier_id; - SenderPipe::Result result = - g_sender_pipe->Send(&barrier, sizeof(barrier), kTimeoutMs); - if (result != SenderPipe::Result::kSuccess) { - FlushBuffersAndClosePipe(); - // TODO(erikchen): Emit a histogram. https://crbug.com/777546. - } -} - -bool SetOnInitAllocatorShimCallbackForTesting( - base::OnceClosure callback, - scoped_refptr<base::TaskRunner> task_runner) { - base::AutoLock lock(g_on_init_allocator_shim_lock_.Get()); - if (g_initialized_) - return true; - g_on_init_allocator_shim_callback_.Get() = std::move(callback); - g_on_init_allocator_shim_task_runner_.Get() = task_runner; - return false; -} - -void AllocatorHooksHaveBeenInitialized() { - base::AutoLock lock(g_on_init_allocator_shim_lock_.Get()); - g_initialized_ = true; - if (!g_on_init_allocator_shim_callback_.Get()) - return; - g_on_init_allocator_shim_task_runner_.Get()->PostTask( - FROM_HERE, std::move(*g_on_init_allocator_shim_callback_.Pointer())); -} - -} // namespace heap_profiling
diff --git a/components/services/heap_profiling/public/cpp/allocator_shim.h b/components/services/heap_profiling/public/cpp/allocator_shim.h deleted file mode 100644 index 870613a..0000000 --- a/components/services/heap_profiling/public/cpp/allocator_shim.h +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_ALLOCATOR_SHIM_H_ -#define COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_ALLOCATOR_SHIM_H_ - -#include "components/services/heap_profiling/public/cpp/sender_pipe.h" -#include "components/services/heap_profiling/public/cpp/stream.h" -#include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h" - -namespace heap_profiling { - -// Initializes the TLS slot globally. This will be called early in Chrome's -// lifecycle to prevent re-entrancy from occurring while trying to set up the -// TLS slot, which is the entity that's supposed to prevent re-entrancy. -void InitTLSSlot(); - -// This method closes sender pipe. -void FlushBuffersAndClosePipe(); - -// Ensures all send buffers are flushed. The given barrier ID is sent to the -// logging process so it knows when this operation is complete. -void AllocatorShimFlushPipe(uint32_t barrier_id); - -// Initializes allocation recorder. -void InitAllocationRecorder(SenderPipe* sender_pipe, - mojom::ProfilingParamsPtr params); - -// Creates allocation info record, populates it with current call stack, -// thread name, allocator type and sends out to the client. Safe to call this -// method after TLS is destroyed. -void RecordAndSendAlloc(AllocatorType type, - void* address, - size_t sz, - const char* context); - -// Creates the record for free operation and sends it out to the client. Safe -// to call this method after TLS is destroyed. -void RecordAndSendFree(void* address); - -// Exists for testing only. -// A return value of |true| means that the allocator shim was already -// initialized and |callback| will never be called. Otherwise, |callback| will -// be called on |task_runner| after the allocator shim is initialized. -bool SetOnInitAllocatorShimCallbackForTesting( - base::OnceClosure callback, - scoped_refptr<base::TaskRunner> task_runner); - -// Notifies the test clients that allocation hooks have been initialized. -void AllocatorHooksHaveBeenInitialized(); - -} // namespace heap_profiling - -#endif // COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_ALLOCATOR_SHIM_H_
diff --git a/components/services/heap_profiling/public/cpp/client.cc b/components/services/heap_profiling/public/cpp/client.cc index 51c9dda..86f6f86 100644 --- a/components/services/heap_profiling/public/cpp/client.cc +++ b/components/services/heap_profiling/public/cpp/client.cc
@@ -13,7 +13,6 @@ #include "base/task/task_traits.h" #include "base/trace_event/malloc_dump_provider.h" #include "build/build_config.h" -#include "components/services/heap_profiling/public/cpp/allocator_shim.h" #include "components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h" #include "components/services/heap_profiling/public/cpp/sender_pipe.h" #include "components/services/heap_profiling/public/cpp/settings.h" @@ -56,7 +55,7 @@ return; sampling_profiler_->StopProfiling(); - FlushBuffersAndClosePipe(); + SamplingProfilerWrapper::FlushBuffersAndClosePipe(); base::trace_event::MallocDumpProvider::GetInstance()->EnableMetrics(); @@ -125,14 +124,11 @@ } void Client::FlushMemlogPipe(uint32_t barrier_id) { - AllocatorShimFlushPipe(barrier_id); + SamplingProfilerWrapper::FlushPipe(barrier_id); } void Client::StartProfilingInternal(mojom::ProfilingParamsPtr params) { - uint32_t sampling_rate = params->sampling_rate; - InitAllocationRecorder(sender_pipe_.get(), std::move(params)); - sampling_profiler_->StartProfiling(sampling_rate); - AllocatorHooksHaveBeenInitialized(); + sampling_profiler_->StartProfiling(sender_pipe_.get(), std::move(params)); } } // namespace heap_profiling
diff --git a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc index 42829fe6..83bb827 100644 --- a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc +++ b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc
@@ -4,11 +4,578 @@ #include "components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h" -#include "components/services/heap_profiling/public/cpp/allocator_shim.h" +#include "base/allocator/buildflags.h" +#include "base/atomicops.h" +#include "base/compiler_specific.h" +#include "base/debug/debugging_buildflags.h" +#include "base/debug/stack_trace.h" +#include "base/lazy_instance.h" +#include "base/no_destructor.h" +#include "base/sampling_heap_profiler/poisson_allocation_sampler.h" +#include "base/synchronization/lock.h" +#include "base/threading/thread_id_name_manager.h" +#include "base/threading/thread_local_storage.h" +#include "base/trace_event/heap_profiler_event_filter.h" +#include "base/trace_event/memory_dump_manager.h" +#include "build/build_config.h" + +#if defined(OS_POSIX) +#include <pthread.h> +#endif + +#if defined(OS_LINUX) || defined(OS_ANDROID) +#include <sys/prctl.h> +#endif + +#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \ + defined(OFFICIAL_BUILD) +#include "base/trace_event/cfi_backtrace_android.h" +#endif + +using base::trace_event::AllocationContext; +using base::trace_event::AllocationContextTracker; +using CaptureMode = base::trace_event::AllocationContextTracker::CaptureMode; namespace heap_profiling { + +// Allocation logging also requires use of base TLS, so we must also check that +// that is available. This means that allocations that occur after base TLS has +// been torn down will not be logged. +// TODO(alph): Get rid of the class. crbug.com/917476 +class ScopedAllowAlloc { + public: + static inline bool HasTLSBeenDestroyed() { + return UNLIKELY(base::ThreadLocalStorage::HasBeenDestroyed()); + } +}; + namespace { +bool g_initialized_ = false; +base::LazyInstance<base::Lock>::Leaky g_on_init_allocator_shim_lock_; +base::LazyInstance<base::OnceClosure>::Leaky g_on_init_allocator_shim_callback_; +base::LazyInstance<scoped_refptr<base::TaskRunner>>::Leaky + g_on_init_allocator_shim_task_runner_; + +SenderPipe* g_sender_pipe = nullptr; + +// In NATIVE stack mode, whether to insert stack names into the backtraces. +bool g_include_thread_names = false; + +// Prime since this is used like a hash table. Numbers of this magnitude seemed +// to provide sufficient parallelism to avoid lock overhead in ad-hoc testing. +constexpr int kNumSendBuffers = 17; + +// If writing to the SenderPipe ever takes longer than 10s, just give up. +constexpr int kTimeoutMs = 10000; + +// The allocator shim needs to retain some additional state for each thread. +struct ShimState { + // The pointer must be valid for the lifetime of the process. + const char* thread_name = nullptr; + + // If we are using pseudo stacks, we need to inform the profiling service of + // the address to string mapping. To avoid a global lock, we keep a + // thread-local unordered_set of every address that has been sent from the + // thread in question. + std::unordered_set<const void*> sent_strings; +}; + +// Technically, this code could be called after Thread destruction and we would +// need to guard this with ThreadLocalStorage::HasBeenDestroyed(), but all calls +// to this are guarded behind ScopedAllowAlloc, which already makes the check. +base::ThreadLocalStorage::Slot& ShimStateTLS() { + static base::NoDestructor<base::ThreadLocalStorage::Slot> shim_state_tls( + [](void* shim_state) { delete static_cast<ShimState*>(shim_state); }); + return *shim_state_tls; +} + +// We don't need to worry about re-entrancy because PoissonAllocationSampler +// already guards against that. +ShimState* GetShimState() { + ShimState* state = static_cast<ShimState*>(ShimStateTLS().Get()); + + if (!state) { + state = new ShimState(); + ShimStateTLS().Set(state); + } + + return state; +} + +// Set the thread name, which is a pointer to a leaked string, to ensure +// validity forever. +void SetCurrentThreadName(const char* name) { + GetShimState()->thread_name = name; +} + +// If a thread name has been set from ThreadIdNameManager, use that. Otherwise, +// gets the thread name from kernel if available or returns a string with id. +// This function intentionally leaks the allocated strings since they are used +// to tag allocations even after the thread dies. +const char* GetAndLeakThreadName() { + const char* thread_name = + base::ThreadIdNameManager::GetInstance()->GetNameForCurrentThread(); + if (thread_name && strcmp(thread_name, "") != 0) + return thread_name; + + // prctl requires 16 bytes, snprintf requires 19, pthread_getname_np requires + // 64 on macOS, see PlatformThread::SetName in platform_thread_mac.mm. + constexpr size_t kBufferLen = 64; + char name[kBufferLen]; +#if defined(OS_LINUX) || defined(OS_ANDROID) + // If the thread name is not set, try to get it from prctl. Thread name might + // not be set in cases where the thread started before heap profiling was + // enabled. + int err = prctl(PR_GET_NAME, name); + if (!err) { + return strdup(name); + } +#elif defined(OS_MACOSX) + int err = pthread_getname_np(pthread_self(), name, kBufferLen); + if (err == 0 && name[0] != '\0') { + return strdup(name); + } +#endif // defined(OS_LINUX) || defined(OS_ANDROID) + + // Use tid if we don't have a thread name. + snprintf(name, sizeof(name), "Thread %lu", + static_cast<unsigned long>(base::PlatformThread::CurrentId())); + return strdup(name); +} + +// Returns the thread name, looking it up if necessary. +const char* GetOrSetThreadName() { + const char* thread_name = GetShimState()->thread_name; + if (UNLIKELY(!thread_name)) { + thread_name = GetAndLeakThreadName(); + GetShimState()->thread_name = thread_name; + } + return thread_name; +} + +class SendBuffer { + public: + SendBuffer() : buffer_(new char[SenderPipe::kPipeSize]) {} + ~SendBuffer() { delete[] buffer_; } + + void Send(const void* data, size_t sz) { + base::AutoLock lock(lock_); + + if (used_ + sz > SenderPipe::kPipeSize) + SendCurrentBuffer(); + + memcpy(&buffer_[used_], data, sz); + used_ += sz; + } + + void Flush() { + base::AutoLock lock(lock_); + if (used_ > 0) + SendCurrentBuffer(); + } + + private: + void SendCurrentBuffer() { + SenderPipe::Result result = g_sender_pipe->Send(buffer_, used_, kTimeoutMs); + used_ = 0; + if (result == SenderPipe::Result::kError) { + SamplingProfilerWrapper::FlushBuffersAndClosePipe(); + } + if (result == SenderPipe::Result::kTimeout) { + SamplingProfilerWrapper::FlushBuffersAndClosePipe(); + // TODO(erikchen): Emit a histogram. https://crbug.com/777546. + } + } + + base::Lock lock_; + + char* buffer_; + size_t used_ = 0; + + DISALLOW_COPY_AND_ASSIGN(SendBuffer); +}; + +// It's safe to call Read() before Write(). Read() will either return nullptr or +// a valid SendBuffer. +class AtomicallyConsistentSendBufferArray { + public: + void Write(SendBuffer* buffer) { + base::subtle::Release_Store( + &send_buffers, reinterpret_cast<base::subtle::AtomicWord>(buffer)); + } + + SendBuffer* Read() { + return reinterpret_cast<SendBuffer*>( + base::subtle::Acquire_Load(&send_buffers)); + } + + private: + // This class is used as a static global. This will be linker-initialized to + // 0. + base::subtle::AtomicWord send_buffers; +}; + +// The API guarantees that Read() will either return a valid object or a +// nullptr. +AtomicallyConsistentSendBufferArray g_send_buffers; + +size_t HashAddress(const void* address) { + // The multiplicative hashing scheme from [Knuth 1998]. + // |a| is the first prime after 2^17. + const uintptr_t key = reinterpret_cast<uintptr_t>(address); + const uintptr_t a = 131101; + const uintptr_t shift = 15; + const uintptr_t h = (key * a) >> shift; + return h; +} + +// "address" is the address in question, which is used to select which send +// buffer to use. +void DoSend(const void* address, + const void* data, + size_t size, + SendBuffer* send_buffers) { + int bin_to_use = HashAddress(address) % kNumSendBuffers; + send_buffers[bin_to_use].Send(data, size); +} + +// Updates an existing in_memory buffer with frame data. If a frame contains a +// pointer to a cstring rather than an instruction pointer, and the profiling +// service has not yet been informed of that pointer -> cstring mapping, sends a +// StringMappingPacket. +class FrameSerializer { + public: + FrameSerializer(uint64_t* stack, + const void* address, + size_t initial_buffer_size, + SendBuffer* send_buffers) + : stack_(stack), + address_(address), + remaining_buffer_size_(initial_buffer_size), + send_buffers_(send_buffers) {} + + void AddAllFrames(const base::trace_event::Backtrace& backtrace) { + CHECK_LE(backtrace.frame_count, kMaxStackEntries); + size_t required_capacity = backtrace.frame_count * sizeof(uint64_t); + CHECK_LE(required_capacity, remaining_buffer_size_); + remaining_buffer_size_ -= required_capacity; + for (int i = base::checked_cast<int>(backtrace.frame_count) - 1; i >= 0; + --i) { + AddFrame(backtrace.frames[i]); + } + } + + void AddAllInstructionPointers(size_t frame_count, + const void* const* frames) { + CHECK_LE(frame_count, kMaxStackEntries); + size_t required_capacity = frame_count * sizeof(uint64_t); + CHECK_LE(required_capacity, remaining_buffer_size_); + remaining_buffer_size_ -= required_capacity; + // If there are too many frames, keep the ones furthest from main(). + for (size_t i = 0; i < frame_count; i++) + AddInstructionPointer(frames[i]); + } + + void AddCString(const char* c_string) { + // Using a TLS cache of sent_strings avoids lock contention on malloc, which + // would kill performance. + std::unordered_set<const void*>* sent_strings = + &GetShimState()->sent_strings; + + if (sent_strings->find(c_string) == sent_strings->end()) { + // No point in allowing arbitrarily long c-strings, which might cause pipe + // max length issues. Pick a reasonable length like 255. + static const size_t kMaxCStringLen = 255; + + // length does not include the null terminator. + size_t length = strnlen(c_string, kMaxCStringLen); + + char message[sizeof(StringMappingPacket) + kMaxCStringLen]; + StringMappingPacket* string_mapping_packet = + new (&message) StringMappingPacket(); + string_mapping_packet->address = reinterpret_cast<uint64_t>(c_string); + string_mapping_packet->string_len = length; + memcpy(message + sizeof(StringMappingPacket), c_string, length); + DoSend(address_, message, sizeof(StringMappingPacket) + length, + send_buffers_); + sent_strings->insert(c_string); + } + + AddInstructionPointer(c_string); + } + + size_t count() { return count_; } + + private: + void AddFrame(const base::trace_event::StackFrame& frame) { + if (frame.type == base::trace_event::StackFrame::Type::PROGRAM_COUNTER) { + AddInstructionPointer(frame.value); + return; + } + + AddCString(static_cast<const char*>(frame.value)); + } + + void AddInstructionPointer(const void* value) { + *stack_ = reinterpret_cast<uint64_t>(value); + ++stack_; + ++count_; + } + + // The next frame should be written to this memory location. There are both + // static and runtime checks to prevent buffer overrun. + static_assert( + base::trace_event::Backtrace::kMaxFrameCount < kMaxStackEntries, + "Ensure that pseudo-stack frame count won't exceed OOP HP frame buffer."); + uint64_t* stack_; + + // The number of frames that have been written to the stack. + size_t count_ = 0; + + const void* address_; + size_t remaining_buffer_size_; + SendBuffer* send_buffers_; +}; + +} // namespace + +void InitTLSSlot() { + base::PoissonAllocationSampler::Init(); + ignore_result(ShimStateTLS()); +} + +// In order for pseudo stacks to work, trace event filtering must be enabled. +void EnableTraceEventFiltering() { + std::string filter_string = base::JoinString( + {"*", TRACE_DISABLED_BY_DEFAULT("net"), TRACE_DISABLED_BY_DEFAULT("cc"), + base::trace_event::MemoryDumpManager::kTraceCategory}, + ","); + base::trace_event::TraceConfigCategoryFilter category_filter; + category_filter.InitializeFromString(filter_string); + + base::trace_event::TraceConfig::EventFilterConfig heap_profiler_filter_config( + base::trace_event::HeapProfilerEventFilter::kName); + heap_profiler_filter_config.SetCategoryFilter(category_filter); + + base::trace_event::TraceConfig::EventFilters filters; + filters.push_back(heap_profiler_filter_config); + base::trace_event::TraceConfig filtering_trace_config; + filtering_trace_config.SetEventFilters(filters); + + base::trace_event::TraceLog::GetInstance()->SetEnabled( + filtering_trace_config, base::trace_event::TraceLog::FILTERING_MODE); +} + +void InitAllocationRecorder(SenderPipe* sender_pipe, + mojom::ProfilingParamsPtr params) { + // Must be done before hooking any functions that make stack traces. + base::debug::EnableInProcessStackDumping(); + + if (params->stack_mode == mojom::StackMode::NATIVE_WITH_THREAD_NAMES) { + g_include_thread_names = true; + base::ThreadIdNameManager::GetInstance()->InstallSetNameCallback( + base::BindRepeating(&SetCurrentThreadName)); + } + + switch (params->stack_mode) { + case mojom::StackMode::PSEUDO: + EnableTraceEventFiltering(); + AllocationContextTracker::SetCaptureMode(CaptureMode::PSEUDO_STACK); + break; + case mojom::StackMode::MIXED: + EnableTraceEventFiltering(); + AllocationContextTracker::SetCaptureMode(CaptureMode::MIXED_STACK); + break; + case mojom::StackMode::NATIVE_WITH_THREAD_NAMES: + case mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES: + // This would track task contexts only. + AllocationContextTracker::SetCaptureMode(CaptureMode::NATIVE_STACK); + break; + } + + g_send_buffers.Write(new SendBuffer[kNumSendBuffers]); + g_sender_pipe = sender_pipe; +} + +void SamplingProfilerWrapper::FlushBuffersAndClosePipe() { + // This ShareBuffer array is leaked on purpose to avoid races on Stop. + g_send_buffers.Write(nullptr); + if (g_sender_pipe) + g_sender_pipe->Close(); +} + +void SerializeFramesFromAllocationContext(FrameSerializer* serializer, + const char** context) { + // Allocation context is tracked in TLS. Return nothing if TLS was destroyed. + if (ScopedAllowAlloc::HasTLSBeenDestroyed()) + return; + auto* tracker = AllocationContextTracker::GetInstanceForCurrentThread(); + if (!tracker) + return; + + AllocationContext allocation_context; + if (!tracker->GetContextSnapshot(&allocation_context)) + return; + + serializer->AddAllFrames(allocation_context.backtrace); + if (!*context) + *context = allocation_context.type_name; +} + +void SerializeFramesFromBacktrace(FrameSerializer* serializer, + const char** context) { + // Skip 3 top frames related to the profiler itself, e.g.: + // base::debug::StackTrace::StackTrace + // heap_profiling::RecordAndSendAlloc + // sampling_heap_profiler::PoissonAllocationSampler::DoRecordAlloc + size_t skip_frames = 3; +#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \ + defined(OFFICIAL_BUILD) + const void* frames[kMaxStackEntries - 1]; + size_t frame_count = + base::trace_event::CFIBacktraceAndroid::GetInitializedInstance()->Unwind( + frames, kMaxStackEntries - 1); +#elif BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) + const void* frames[kMaxStackEntries - 1]; + size_t frame_count = base::debug::TraceStackFramePointers( + frames, kMaxStackEntries - 1, skip_frames); + skip_frames = 0; +#else + // Fall-back to capturing the stack with base::debug::StackTrace, + // which is likely slower, but more reliable. + base::debug::StackTrace stack_trace(kMaxStackEntries - 1); + size_t frame_count = 0u; + const void* const* frames = stack_trace.Addresses(&frame_count); +#endif + + skip_frames = std::min(skip_frames, frame_count); + serializer->AddAllInstructionPointers(frame_count - skip_frames, + frames + skip_frames); + + // Both thread name and task context require access to TLS. + if (ScopedAllowAlloc::HasTLSBeenDestroyed()) + return; + + if (g_include_thread_names) { + const char* thread_name = GetOrSetThreadName(); + serializer->AddCString(thread_name); + } + + if (!*context) { + const auto* tracker = + AllocationContextTracker::GetInstanceForCurrentThread(); + if (tracker) + *context = tracker->TaskContext(); + } +} + +// Creates allocation info record, populates it with current call stack, +// thread name, allocator type and sends out to the client. Safe to call this +// method after TLS is destroyed. +void RecordAndSendAlloc(AllocatorType type, + void* address, + size_t sz, + const char* context) { + SendBuffer* send_buffers = g_send_buffers.Read(); + if (!send_buffers) + return; + + constexpr size_t max_message_size = sizeof(AllocPacket) + + kMaxStackEntries * sizeof(uint64_t) + + kMaxContextLen; + static_assert(max_message_size < SenderPipe::kPipeSize, + "We can't have a message size that exceeds the pipe write " + "buffer size."); + char message[max_message_size]; + // TODO(ajwong) check that this is technically valid. + AllocPacket* alloc_packet = reinterpret_cast<AllocPacket*>(message); + + uint64_t* stack = reinterpret_cast<uint64_t*>(&message[sizeof(AllocPacket)]); + + FrameSerializer serializer( + stack, address, max_message_size - sizeof(AllocPacket), send_buffers); + + CaptureMode capture_mode = AllocationContextTracker::capture_mode(); + if (capture_mode == CaptureMode::PSEUDO_STACK || + capture_mode == CaptureMode::MIXED_STACK) { + SerializeFramesFromAllocationContext(&serializer, &context); + } else { + SerializeFramesFromBacktrace(&serializer, &context); + } + + size_t context_len = context ? strnlen(context, kMaxContextLen) : 0; + + alloc_packet->op = kAllocPacketType; + alloc_packet->allocator = type; + alloc_packet->address = (uint64_t)address; + alloc_packet->size = sz; + alloc_packet->stack_len = static_cast<uint32_t>(serializer.count()); + alloc_packet->context_byte_len = static_cast<uint32_t>(context_len); + + char* message_end = message + sizeof(AllocPacket) + + alloc_packet->stack_len * sizeof(uint64_t); + if (context_len > 0) { + memcpy(message_end, context, context_len); + message_end += context_len; + } + DoSend(address, message, message_end - message, send_buffers); +} + +// Creates the record for free operation and sends it out to the client. Safe +// to call this method after TLS is destroyed. +void RecordAndSendFree(void* address) { + SendBuffer* send_buffers = g_send_buffers.Read(); + if (!send_buffers) + return; + + FreePacket free_packet; + free_packet.op = kFreePacketType; + free_packet.address = (uint64_t)address; + + DoSend(address, &free_packet, sizeof(FreePacket), send_buffers); +} + +void SamplingProfilerWrapper::FlushPipe(uint32_t barrier_id) { + SendBuffer* send_buffers = g_send_buffers.Read(); + if (!send_buffers) + return; + for (int i = 0; i < kNumSendBuffers; i++) + send_buffers[i].Flush(); + + BarrierPacket barrier; + barrier.barrier_id = barrier_id; + SenderPipe::Result result = + g_sender_pipe->Send(&barrier, sizeof(barrier), kTimeoutMs); + if (result != SenderPipe::Result::kSuccess) { + FlushBuffersAndClosePipe(); + // TODO(erikchen): Emit a histogram. https://crbug.com/777546. + } +} + +bool SetOnInitAllocatorShimCallbackForTesting( + base::OnceClosure callback, + scoped_refptr<base::TaskRunner> task_runner) { + base::AutoLock lock(g_on_init_allocator_shim_lock_.Get()); + if (g_initialized_) + return true; + g_on_init_allocator_shim_callback_.Get() = std::move(callback); + g_on_init_allocator_shim_task_runner_.Get() = task_runner; + return false; +} + +namespace { + +// Notifies the test clients that allocation hooks have been initialized. +void AllocatorHooksHaveBeenInitialized() { + base::AutoLock lock(g_on_init_allocator_shim_lock_.Get()); + g_initialized_ = true; + if (!g_on_init_allocator_shim_callback_.Get()) + return; + g_on_init_allocator_shim_task_runner_.Get()->PostTask( + FROM_HERE, std::move(*g_on_init_allocator_shim_callback_.Pointer())); +} + AllocatorType ConvertType(base::PoissonAllocationSampler::AllocatorType type) { static_assert(static_cast<uint32_t>( base::PoissonAllocationSampler::AllocatorType::kMax) == @@ -37,10 +604,14 @@ base::PoissonAllocationSampler::Get()->RemoveSamplesObserver(this); } -void SamplingProfilerWrapper::StartProfiling(size_t sampling_rate) { +void SamplingProfilerWrapper::StartProfiling(SenderPipe* sender_pipe, + mojom::ProfilingParamsPtr params) { + size_t sampling_rate = params->sampling_rate; + InitAllocationRecorder(sender_pipe, std::move(params)); auto* sampler = base::PoissonAllocationSampler::Get(); sampler->SetSamplingInterval(sampling_rate); sampler->Start(); + AllocatorHooksHaveBeenInitialized(); } void SamplingProfilerWrapper::StopProfiling() {
diff --git a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h index 92626cf..bee5c72 100644 --- a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h +++ b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h
@@ -5,21 +5,45 @@ #ifndef COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SAMPLING_PROFILER_WRAPPER_H_ #define COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SAMPLING_PROFILER_WRAPPER_H_ -#include <memory> - #include "base/sampling_heap_profiler/poisson_allocation_sampler.h" +#include "components/services/heap_profiling/public/cpp/sender_pipe.h" +#include "components/services/heap_profiling/public/cpp/stream.h" +#include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h" namespace heap_profiling { +// Initializes the TLS slot globally. This will be called early in Chrome's +// lifecycle to prevent re-entrancy from occurring while trying to set up the +// TLS slot, which is the entity that's supposed to prevent re-entrancy. +void InitTLSSlot(); + +// Exists for testing only. +// A return value of |true| means that the allocator shim was already +// initialized and |callback| will never be called. Otherwise, |callback| will +// be called on |task_runner| after the allocator shim is initialized. +bool SetOnInitAllocatorShimCallbackForTesting( + base::OnceClosure callback, + scoped_refptr<base::TaskRunner> task_runner); + +// The class listens for allocation samples records the necessary attributes +// and passes allocations down the pipeline. class SamplingProfilerWrapper : private base::PoissonAllocationSampler::SamplesObserver { public: SamplingProfilerWrapper(); ~SamplingProfilerWrapper() override; - void StartProfiling(size_t sampling_rate); + void StartProfiling(SenderPipe* sender_pipe, + mojom::ProfilingParamsPtr params); void StopProfiling(); + // This method closes sender pipe. + static void FlushBuffersAndClosePipe(); + + // Ensures all send buffers are flushed. The given barrier ID is sent to the + // logging process so it knows when this operation is complete. + static void FlushPipe(uint32_t barrier_id); + private: // base::PoissonAllocationSampler::SamplesObserver void SampleAdded(void* address,
diff --git a/components/storage_monitor/image_capture_device_manager_unittest.mm b/components/storage_monitor/image_capture_device_manager_unittest.mm index 02e1726..df88619 100644 --- a/components/storage_monitor/image_capture_device_manager_unittest.mm +++ b/components/storage_monitor/image_capture_device_manager_unittest.mm
@@ -157,8 +157,11 @@ - (instancetype)init:(NSString*)name { if ((self = [super init])) { + base::scoped_nsobject<NSDateFormatter> iso8601day( + [[NSDateFormatter alloc] init]); + [iso8601day setDateFormat:@"yyyy-MM-dd"]; name_.reset([name retain]); - date_.reset([[NSDate dateWithNaturalLanguageString:@"12/12/12"] retain]); + date_.reset([[iso8601day dateFromString:@"2012-12-12"] retain]); } return self; }
diff --git a/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2 b/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2 index 5d416cd..8fdd785 100644 --- a/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2 +++ b/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2
@@ -9,7 +9,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.components_browsertests_apk"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.CAMERA" />
diff --git a/components/translate/core/browser/translate_script_unittest.cc b/components/translate/core/browser/translate_script_unittest.cc index 605cc28..b5596edb 100644 --- a/components/translate/core/browser/translate_script_unittest.cc +++ b/components/translate/core/browser/translate_script_unittest.cc
@@ -14,6 +14,7 @@ #include "build/build_config.h" #include "components/translate/core/browser/translate_download_manager.h" #include "components/translate/core/common/translate_switches.h" +#include "components/variations/variations_http_header_provider.h" #include "net/base/load_flags.h" #include "net/base/url_util.h" #include "net/http/http_request_headers.h" @@ -33,6 +34,7 @@ protected: void SetUp() override { + variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); script_.reset(new TranslateScript); auto* translate_download_manager = TranslateDownloadManager::GetInstance(); translate_download_manager->set_application_locale("en");
diff --git a/components/vector_icons/media_router_active.icon b/components/vector_icons/media_router_active.icon index f8f11a9..cd306d15 100644 --- a/components/vector_icons/media_router_active.icon +++ b/components/vector_icons/media_router_active.icon
@@ -3,18 +3,6 @@ // found in the LICENSE file. CANVAS_DIMENSIONS, 16, -MOVE_TO, 0, 0, -R_H_LINE_TO, 16, -R_V_LINE_TO, 16, -H_LINE_TO, 0, -V_LINE_TO, 0, -CLOSE, -MOVE_TO, 0, 0, -R_H_LINE_TO, 16, -R_V_LINE_TO, 16, -H_LINE_TO, 0, -V_LINE_TO, 0, -CLOSE, MOVE_TO, 14.55f, 1.5f, H_LINE_TO, 1.45f, CUBIC_TO, 0.65f, 1.5f, 0, 2.15f, 0, 2.94f,
diff --git a/components/vector_icons/media_router_error.icon b/components/vector_icons/media_router_error.icon index 45fa96c..146f0b8 100644 --- a/components/vector_icons/media_router_error.icon +++ b/components/vector_icons/media_router_error.icon
@@ -3,18 +3,6 @@ // found in the LICENSE file. CANVAS_DIMENSIONS, 16, -MOVE_TO, 0, 0, -R_H_LINE_TO, 16, -R_V_LINE_TO, 16, -H_LINE_TO, 0, -V_LINE_TO, 0, -CLOSE, -MOVE_TO, 0, 0, -R_H_LINE_TO, 16, -R_V_LINE_TO, 16, -H_LINE_TO, 0, -V_LINE_TO, 0, -CLOSE, MOVE_TO, 14.55f, 1.5f, H_LINE_TO, 1.45f, CUBIC_TO, 0.65f, 1.5f, 0, 2.15f, 0, 2.94f,
diff --git a/components/vector_icons/media_router_idle.icon b/components/vector_icons/media_router_idle.icon index 7976ba8..a71a3b18c 100644 --- a/components/vector_icons/media_router_idle.icon +++ b/components/vector_icons/media_router_idle.icon
@@ -3,18 +3,6 @@ // found in the LICENSE file. CANVAS_DIMENSIONS, 16, -MOVE_TO, 0, 0, -R_H_LINE_TO, 16, -R_V_LINE_TO, 16, -H_LINE_TO, 0, -V_LINE_TO, 0, -CLOSE, -MOVE_TO, 0, 0, -R_H_LINE_TO, 16, -R_V_LINE_TO, 16, -H_LINE_TO, 0, -V_LINE_TO, 0, -CLOSE, MOVE_TO, 14.55f, 1.5f, H_LINE_TO, 1.45f, CUBIC_TO, 0.65f, 1.5f, 0, 2.15f, 0, 2.94f,
diff --git a/components/vector_icons/media_router_warning.icon b/components/vector_icons/media_router_warning.icon index b94dcd7..d5c8ab8 100644 --- a/components/vector_icons/media_router_warning.icon +++ b/components/vector_icons/media_router_warning.icon
@@ -3,18 +3,6 @@ // found in the LICENSE file. CANVAS_DIMENSIONS, 16, -MOVE_TO, 0, 0, -R_H_LINE_TO, 16, -R_V_LINE_TO, 16, -H_LINE_TO, 0, -V_LINE_TO, 0, -CLOSE, -MOVE_TO, 0, 0, -R_H_LINE_TO, 16, -R_V_LINE_TO, 16, -H_LINE_TO, 0, -V_LINE_TO, 0, -CLOSE, MOVE_TO, 14.55f, 1.5f, H_LINE_TO, 1.45f, CUBIC_TO, 0.65f, 1.5f, 0, 2.15f, 0, 2.94f,
diff --git a/components/viz/service/display/display_resource_provider.cc b/components/viz/service/display/display_resource_provider.cc index 691e2903..1dbfcbd9 100644 --- a/components/viz/service/display/display_resource_provider.cc +++ b/components/viz/service/display/display_resource_provider.cc
@@ -15,6 +15,7 @@ #include "components/viz/common/resources/resource_sizes.h" #include "components/viz/service/display/shared_bitmap_manager.h" #include "components/viz/service/display/skia_output_surface.h" +#include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" @@ -460,17 +461,28 @@ // calling LockForRead(). DCHECK_NE(NEEDS_WAIT, resource->synchronization_state()); - if (resource->is_gpu_resource_type() && !resource->gl_id) { + const gpu::Mailbox& mailbox = resource->transferable.mailbox_holder.mailbox; + if (resource->is_gpu_resource_type()) { GLES2Interface* gl = ContextGL(); DCHECK(gl); - resource->gl_id = gl->CreateAndConsumeTextureCHROMIUM( - resource->transferable.mailbox_holder.mailbox.name); - resource->SetLocallyUsed(); + if (!resource->gl_id) { + if (mailbox.IsSharedImage()) { + resource->gl_id = + gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name); + } else { + resource->gl_id = gl->CreateAndConsumeTextureCHROMIUM( + resource->transferable.mailbox_holder.mailbox.name); + } + resource->SetLocallyUsed(); + } + if (mailbox.IsSharedImage()) { + gl->BeginSharedImageAccessDirectCHROMIUM( + resource->gl_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM); + } } if (!resource->shared_bitmap && !resource->is_gpu_resource_type()) { - const SharedBitmapId& shared_bitmap_id = - resource->transferable.mailbox_holder.mailbox; + const SharedBitmapId& shared_bitmap_id = mailbox; std::unique_ptr<SharedBitmap> bitmap = shared_bitmap_manager_->GetSharedBitmapFromId( resource->transferable.size, resource->transferable.format, @@ -504,6 +516,13 @@ ChildResource* resource = &it->second; DCHECK_GT(resource->lock_for_read_count, 0); + if (resource->transferable.mailbox_holder.mailbox.IsSharedImage() && + resource->is_gpu_resource_type()) { + DCHECK(resource->gl_id); + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + gl->EndSharedImageAccessDirectCHROMIUM(resource->gl_id); + } resource->lock_for_read_count--; TryReleaseResource(it); }
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 54e1614..5cea43e 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -57,6 +57,11 @@ // A Skia image that should be sampled from instead of the original // contents. sk_sp<SkImage> filter_image; + // Non-null |color_filter| should be applied when |filter_image| is + // drawn. It is a portion of the image filter DAG that was separated out + // because direct color filter drawing is much faster than a + // colorFilterImageFilter drawing. + sk_sp<SkColorFilter> color_filter; gfx::Point src_offset; gfx::RectF dst_rect; gfx::RectF tex_coord_rect; @@ -922,9 +927,22 @@ *params->filters, gfx::SizeF(content->width(), content->height())); auto filter = paint_filter ? paint_filter->cached_sk_filter_ : nullptr; - // Apply filters to the content texture. - // TODO(xing.xu): Support SkColorFilter here. (https://crbug.com/823182) + // If the first imageFilter is a colorFilterImageFilter, pull it off and store + // it to be used later. Fall through to allow the remainder of the DAG (if + // any) to be applied. Applying the colorFilter as part of the final draw is + // much more efficient than applying it as a colorFilterImageFilter. + if (filter) { + SkColorFilter* colorfilter_rawptr = nullptr; + filter->asColorFilter(&colorfilter_rawptr); + sk_sp<SkColorFilter> color_filter(colorfilter_rawptr); + if (color_filter) { + params->color_filter = color_filter; + filter = sk_ref_sp(filter->getInput(0)); + } + } + + // Apply filters to the content texture. if (filter) { gfx::Rect clip_rect = quad->shared_quad_state->clip_rect; if (clip_rect.IsEmpty()) { @@ -1031,6 +1049,10 @@ if (!can_draw) return; + // Add color filter. + if (params.color_filter) + paint->setColorFilter(params.color_filter); + SkRect content_rect; SkRect dest_visible_rect; if (params.filter_image) {
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc index e301bb5..e58ace1d 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -438,17 +438,18 @@ const ResourceFormat resource_format, std::unique_ptr<gpu::SharedImageRepresentationSkia>* shared_image_out) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (!*shared_image_out && shared_image_representation_factory_->IsSharedImage( - mailbox_holder.mailbox)) { + if (!*shared_image_out && mailbox_holder.mailbox.IsSharedImage()) { std::unique_ptr<gpu::SharedImageRepresentationSkia> shared_image = shared_image_representation_factory_->ProduceSkia( mailbox_holder.mailbox); - DCHECK(shared_image); + if (!shared_image) { + DLOG(ERROR) << "Failed to fulfill the promise texture - SharedImage " + "mailbox not found in SharedImageManager."; + return nullptr; + } *shared_image_out = std::move(shared_image); } if (*shared_image_out) { - DCHECK(shared_image_representation_factory_->IsSharedImage( - mailbox_holder.mailbox)); auto promise_texture = (*shared_image_out)->BeginReadAccess(sk_surface_.get()); DLOG_IF(ERROR, !promise_texture)
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h index 5c382b7..672a4c6 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -18,7 +18,7 @@ #include "components/viz/service/display/output_surface_frame.h" #include "components/viz/service/display/resource_metadata.h" #include "gpu/command_buffer/common/sync_token.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/ipc/common/surface_handle.h" #include "gpu/ipc/in_process_command_buffer.h" #include "gpu/ipc/service/image_transport_surface_delegate.h"
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc b/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc index 4bb754aa..543aa47 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
@@ -4,13 +4,16 @@ #include "components/viz/service/display_embedder/skia_output_surface_impl.h" +#include <memory> +#include <utility> +#include <vector> + #include "base/base64.h" #include "base/test/scoped_feature_list.h" #include "cc/test/fake_output_surface_client.h" #include "cc/test/pixel_test_utils.h" #include "components/viz/common/frame_sinks/copy_output_request.h" #include "components/viz/common/frame_sinks/copy_output_result.h" -#include "components/viz/service/display_embedder/skia_output_surface_impl.h" #include "components/viz/service/gl/gpu_service_impl.h" #include "gpu/command_buffer/service/scheduler.h" #include "gpu/ipc/gpu_in_process_thread_service.h" @@ -100,7 +103,8 @@ ->GetFormat(), gpu_service_->gpu_feature_info(), gpu_service_->gpu_channel_manager()->gpu_preferences(), - gpu_service_->shared_image_manager()); + gpu_service_->shared_image_manager(), + gpu_service_->gpu_channel_manager()->program_cache()); UnblockMainThread(); }
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc index f6ae8566..0f835e1 100644 --- a/components/viz/service/gl/gpu_service_impl.cc +++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -21,8 +21,8 @@ #include "components/viz/common/gpu/vulkan_in_process_context_provider.h" #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" #include "gpu/command_buffer/service/gpu_switches.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" #include "gpu/command_buffer/service/scheduler.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/config/dx_diag_node.h" #include "gpu/config/gpu_info_collector.h"
diff --git a/components/viz/service/main/viz_main_impl.cc b/components/viz/service/main/viz_main_impl.cc index b34e191..543d2dc 100644 --- a/components/viz/service/main/viz_main_impl.cc +++ b/components/viz/service/main/viz_main_impl.cc
@@ -251,7 +251,8 @@ gpu_service_->sync_point_manager(), gpu_service_->mailbox_manager(), gpu_service_->share_group(), format, gpu_service_->gpu_feature_info(), gpu_service_->gpu_channel_manager()->gpu_preferences(), - gpu_service_->shared_image_manager()); + gpu_service_->shared_image_manager(), + gpu_service_->gpu_channel_manager()->program_cache()); viz_compositor_thread_runner_->CreateFrameSinkManager( std::move(params), task_executor_, gpu_service_.get());
diff --git a/components/viz/test/test_context_provider.cc b/components/viz/test/test_context_provider.cc index 9a3b64e..66e828c 100644 --- a/components/viz/test/test_context_provider.cc +++ b/components/viz/test/test_context_provider.cc
@@ -121,7 +121,7 @@ const gfx::Size& size, const gfx::ColorSpace& color_space, uint32_t usage) { - auto mailbox = gpu::Mailbox::Generate(); + auto mailbox = gpu::Mailbox::GenerateForSharedImage(); shared_images_.insert(mailbox); return mailbox; } @@ -132,7 +132,7 @@ const gfx::ColorSpace& color_space, uint32_t usage, base::span<const uint8_t> pixel_data) { - auto mailbox = gpu::Mailbox::Generate(); + auto mailbox = gpu::Mailbox::GenerateForSharedImage(); shared_images_.insert(mailbox); return mailbox; } @@ -142,7 +142,7 @@ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, const gfx::ColorSpace& color_space, uint32_t usage) { - auto mailbox = gpu::Mailbox::Generate(); + auto mailbox = gpu::Mailbox::GenerateForSharedImage(); shared_images_.insert(mailbox); return mailbox; }
diff --git a/components/wifi/wifi_service_mac.mm b/components/wifi/wifi_service_mac.mm index 4f46e1c7..ad40c2a 100644 --- a/components/wifi/wifi_service_mac.mm +++ b/components/wifi/wifi_service_mac.mm
@@ -165,7 +165,7 @@ void WiFiServiceMac::Initialize( scoped_refptr<base::SequencedTaskRunner> task_runner) { task_runner_.swap(task_runner); - interface_.reset([[CWInterface interface] retain]); + interface_.reset([[[CWWiFiClient sharedWiFiClient] interface] retain]); if (!interface_) { DVLOG(1) << "Failed to initialize default interface."; return;
diff --git a/content/BUILD.gn b/content/BUILD.gn index bce6285..8b213a89 100644 --- a/content/BUILD.gn +++ b/content/BUILD.gn
@@ -122,12 +122,6 @@ ] deps = [ "//content/browser/process_internals:mojo_bindings_js", - "//content/public/app:browser_manifest", - "//content/public/app:gpu_manifest", - "//content/public/app:packaged_services_manifest", - "//content/public/app:plugin_manifest", - "//content/public/app:renderer_manifest", - "//content/public/app:utility_manifest", ] }
diff --git a/content/app/strings/content_strings.grd b/content/app/strings/content_strings.grd index 4ca2ad7d..c6ee483 100644 --- a/content/app/strings/content_strings.grd +++ b/content/app/strings/content_strings.grd
@@ -645,11 +645,11 @@ </message> <message name="IDS_AX_MEDIA_CURRENT_TIME_DISPLAY" desc="Accessibility role description for elapsed time display"> - elapsed time + elapsed time: <ph name="ELAPSED_TIME">$1<ex>0:25</ex></ph> </message> <message name="IDS_AX_MEDIA_TIME_REMAINING_DISPLAY" desc="Accessibility role description for time remaining display"> - remaining time + remaining time: <ph name="REMAINING_TIME">$1<ex>3:25</ex></ph> </message> <message name="IDS_AX_MEDIA_ENTER_FULL_SCREEN_BUTTON" desc="Accessibility role description for enter fullscreen button">
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 6666ff1..2f87c627 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -88,6 +88,7 @@ "//content/common", "//content/common:buildflags", "//content/common:mojo_bindings", + "//content/public/app:service_manifests", "//content/public/common:common_sources", "//crypto", "//device/base", @@ -355,6 +356,7 @@ "appcache/appcache_dispatcher_host.cc", "appcache/appcache_dispatcher_host.h", "appcache/appcache_entry.h", + "appcache/appcache_frontend.h", "appcache/appcache_frontend_proxy.cc", "appcache/appcache_frontend_proxy.h", "appcache/appcache_group.cc", @@ -371,6 +373,8 @@ "appcache/appcache_job.h", "appcache/appcache_manifest_parser.cc", "appcache/appcache_manifest_parser.h", + "appcache/appcache_namespace.cc", + "appcache/appcache_namespace.h", "appcache/appcache_navigation_handle.cc", "appcache/appcache_navigation_handle.h", "appcache/appcache_navigation_handle_core.cc", @@ -1167,6 +1171,8 @@ "media/flinging_renderer.h", "media/forwarding_audio_stream_factory.cc", "media/forwarding_audio_stream_factory.h", + "media/hardware_key_media_controller.cc", + "media/hardware_key_media_controller.h", "media/in_process_audio_loopback_stream_creator.cc", "media/in_process_audio_loopback_stream_creator.h", "media/media_devices_permission_checker.cc", @@ -1185,6 +1191,8 @@ "media/media_internals_proxy.h", "media/media_internals_ui.cc", "media/media_internals_ui.h", + "media/media_keys_listener_manager_impl.cc", + "media/media_keys_listener_manager_impl.h", "media/media_web_contents_observer.cc", "media/media_web_contents_observer.h", "media/midi_host.cc",
diff --git a/content/browser/DEPS b/content/browser/DEPS index bcfe526..cbadf36 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS
@@ -29,6 +29,7 @@ "+components/cbor", "+content/app/strings/grit", # For generated headers + "+content/public/app", "+content/public/browser", "+device/base/synchronization", "+device/gamepad", # For gamepad API @@ -133,6 +134,7 @@ "+third_party/blink/public/platform/mime_registry.mojom.h", "+third_party/blink/public/platform/modules/background_sync/background_sync.mojom.h", "+third_party/blink/public/platform/modules/bluetooth/web_bluetooth.mojom.h", + "+third_party/blink/public/platform/modules/broadcastchannel/broadcast_channel.mojom-test-utils.h", "+third_party/blink/public/platform/modules/broadcastchannel/broadcast_channel.mojom.h", "+third_party/blink/public/platform/modules/cookie_store/cookie_store.mojom.h", "+third_party/blink/public/platform/modules/geolocation/geolocation_service.mojom.h",
diff --git a/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/content/browser/accessibility/accessibility_tree_formatter_mac.mm index 28d76d87..2f36e17b 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_mac.mm +++ b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -17,6 +17,11 @@ #include "content/browser/accessibility/browser_accessibility_mac.h" #include "content/browser/accessibility/browser_accessibility_manager.h" +// This file uses the deprecated NSObject accessibility interface. +// TODO(crbug.com/921109): Migrate to the new NSAccessibility interface. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + using base::StringPrintf; using base::SysNSStringToUTF8; using base::SysNSStringToUTF16; @@ -361,3 +366,5 @@ } } // namespace content + +#pragma clang diagnostic pop
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index 9e5070b..d1e7164 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -2787,6 +2787,11 @@ return actions; } +// TODO(crbug.com/921109): Migrate from the NSObject accessibility interface to +// the NSAccessibility one, then remove this suppression. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + // Returns a sub-array of values for the given attribute value, starting at // index, with up to maxCount items. If the given index is out of bounds, // or there are no values for the given attribute, it will return nil. @@ -2823,6 +2828,8 @@ return [fullArray count]; } +#pragma clang diagnostic pop + // Returns the list of accessibility attributes that this object supports. - (NSArray*)accessibilityAttributeNames { if (![self instanceActive])
diff --git a/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm b/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm index 8c0e74be..7ca5a1a 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm
@@ -19,6 +19,11 @@ #include "testing/gtest_mac.h" #include "url/gurl.h" +// This file uses the deprecated NSObject accessibility APIs: +// https://crbug.com/921109 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + namespace content { namespace { @@ -119,3 +124,5 @@ } } // namespace content + +#pragma clang diagnostic pop
diff --git a/content/browser/accessibility/browser_accessibility_mac_unittest.mm b/content/browser/accessibility/browser_accessibility_mac_unittest.mm index cbfcdad..3c611af 100644 --- a/content/browser/accessibility/browser_accessibility_mac_unittest.mm +++ b/content/browser/accessibility/browser_accessibility_mac_unittest.mm
@@ -123,6 +123,11 @@ std::unique_ptr<BrowserAccessibilityManager> manager_; }; +// The next few tests all use the deprecated NSObject accessibility APIs: +// https://crbug.com/921109. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + // Standard hit test. TEST_F(BrowserAccessibilityMacTest, HitTestTest) { BrowserAccessibilityCocoa* firstChild = @@ -186,6 +191,8 @@ [retainedFirstChild release]; } +#pragma clang diagnostic pop + TEST_F(BrowserAccessibilityMacTest, TestComputeTextEdit) { BrowserAccessibility* owner = [accessibility_ owner]; ASSERT_NE(nullptr, owner);
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc index 893ef36..a283d6e 100644 --- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -451,6 +451,11 @@ RunEventTest(FILE_PATH_LITERAL("remove-hidden-attribute.html")); } +IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest, + AccessibilityEventsReportValidityInvalidField) { + RunEventTest(FILE_PATH_LITERAL("report-validity-invalid-field.html")); +} + IN_PROC_BROWSER_TEST_F( DumpAccessibilityEventsTest, AccessibilityEventsRemoveHiddenAttributeSubtree) {
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 7878dc6..94543ce 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -252,6 +252,7 @@ AddFilter(filters, "invalidState=false", Filter::DENY); // Don't show false value AddFilter(filters, "roleDescription=*"); + AddFilter(filters, "errormessageId=*"); // // OS X @@ -1273,6 +1274,11 @@ RunHtmlTest(FILE_PATH_LITERAL("form.html")); } +IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, + AccessibilityFormValidationMessage) { + RunHtmlTest(FILE_PATH_LITERAL("form-validation-message.html")); +} + IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFrameset) { RunHtmlTest(FILE_PATH_LITERAL("frameset.html")); }
diff --git a/content/browser/appcache/appcache.h b/content/browser/appcache/appcache.h index 5457f61..87fd8fa 100644 --- a/content/browser/appcache/appcache.h +++ b/content/browser/appcache/appcache.h
@@ -19,6 +19,7 @@ #include "content/browser/appcache/appcache_database.h" #include "content/browser/appcache/appcache_entry.h" #include "content/browser/appcache/appcache_manifest_parser.h" +#include "content/browser/appcache/appcache_namespace.h" #include "content/common/content_export.h" #include "third_party/blink/public/mojom/appcache/appcache.mojom.h" #include "url/gurl.h"
diff --git a/content/browser/appcache/appcache_database.h b/content/browser/appcache/appcache_database.h index 5aecf70..e52180a 100644 --- a/content/browser/appcache/appcache_database.h +++ b/content/browser/appcache/appcache_database.h
@@ -16,6 +16,7 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/time/time.h" +#include "content/browser/appcache/appcache_namespace.h" #include "content/common/appcache_interfaces.h" #include "content/common/content_export.h" #include "sql/statement_id.h"
diff --git a/content/browser/appcache/appcache_frontend.h b/content/browser/appcache/appcache_frontend.h new file mode 100644 index 0000000..223aea9 --- /dev/null +++ b/content/browser/appcache/appcache_frontend.h
@@ -0,0 +1,55 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_FRONTEND_H_ +#define CONTENT_BROWSER_APPCACHE_APPCACHE_FRONTEND_H_ + +#include <string> +#include <vector> + +#include "base/files/file_path.h" +#include "content/common/appcache_interfaces.h" +#include "content/common/content_export.h" +#include "content/public/common/appcache_info.h" +#include "services/network/public/mojom/url_loader_factory.mojom.h" +#include "third_party/blink/public/mojom/appcache/appcache.mojom.h" +#include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h" + +class GURL; + +namespace content { + +// Interface used by backend (browser-process) to talk to frontend (renderer). +class CONTENT_EXPORT AppCacheFrontend { + public: + virtual ~AppCacheFrontend() = default; + + virtual void OnCacheSelected(int host_id, + const blink::mojom::AppCacheInfo& info) = 0; + virtual void OnStatusChanged(const std::vector<int>& host_ids, + blink::mojom::AppCacheStatus status) = 0; + virtual void OnEventRaised(const std::vector<int>& host_ids, + blink::mojom::AppCacheEventID event_id) = 0; + virtual void OnProgressEventRaised(const std::vector<int>& host_ids, + const GURL& url, + int num_total, + int num_complete) = 0; + virtual void OnErrorEventRaised( + const std::vector<int>& host_ids, + const blink::mojom::AppCacheErrorDetails& details) = 0; + virtual void OnContentBlocked(int host_id, const GURL& manifest_url) = 0; + virtual void OnLogMessage(int host_id, + AppCacheLogLevel log_level, + const std::string& message) = 0; + // In the network service world, we pass the URLLoaderFactory instance to be + // used to issue subresource requeste in the |loader_factory_pipe_handle| + // parameter. + virtual void OnSetSubresourceFactory( + int host_id, + network::mojom::URLLoaderFactoryPtr url_loader_factory) = 0; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_FRONTEND_H_ \ No newline at end of file
diff --git a/content/browser/appcache/appcache_frontend_proxy.h b/content/browser/appcache/appcache_frontend_proxy.h index 98ac1656..1b0e15c1 100644 --- a/content/browser/appcache/appcache_frontend_proxy.h +++ b/content/browser/appcache/appcache_frontend_proxy.h
@@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "content/browser/appcache/appcache_frontend.h" #include "content/common/appcache_interfaces.h" #include "third_party/blink/public/mojom/appcache/appcache.mojom.h" #include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
diff --git a/content/browser/appcache/appcache_group_unittest.cc b/content/browser/appcache/appcache_group_unittest.cc index 7930fb6..ea174a1 100644 --- a/content/browser/appcache/appcache_group_unittest.cc +++ b/content/browser/appcache/appcache_group_unittest.cc
@@ -8,6 +8,7 @@ #include "base/test/scoped_task_environment.h" #include "content/browser/appcache/appcache.h" +#include "content/browser/appcache/appcache_frontend.h" #include "content/browser/appcache/appcache_group.h" #include "content/browser/appcache/appcache_host.h" #include "content/browser/appcache/appcache_update_job.h"
diff --git a/content/browser/appcache/appcache_host.cc b/content/browser/appcache/appcache_host.cc index a1660ba2..077926d 100644 --- a/content/browser/appcache/appcache_host.cc +++ b/content/browser/appcache/appcache_host.cc
@@ -12,6 +12,7 @@ #include "base/strings/stringprintf.h" #include "content/browser/appcache/appcache.h" #include "content/browser/appcache/appcache_backend_impl.h" +#include "content/browser/appcache/appcache_frontend.h" #include "content/browser/appcache/appcache_policy.h" #include "content/browser/appcache/appcache_request.h" #include "content/browser/appcache/appcache_request_handler.h"
diff --git a/content/browser/appcache/appcache_host_unittest.cc b/content/browser/appcache/appcache_host_unittest.cc index 49c7e6e..18d63af 100644 --- a/content/browser/appcache/appcache_host_unittest.cc +++ b/content/browser/appcache/appcache_host_unittest.cc
@@ -13,6 +13,7 @@ #include "base/test/scoped_task_environment.h" #include "content/browser/appcache/appcache.h" #include "content/browser/appcache/appcache_backend_impl.h" +#include "content/browser/appcache/appcache_frontend.h" #include "content/browser/appcache/appcache_group.h" #include "content/browser/appcache/mock_appcache_policy.h" #include "content/browser/appcache/mock_appcache_service.h"
diff --git a/content/browser/appcache/appcache_manifest_parser.h b/content/browser/appcache/appcache_manifest_parser.h index f427247e..88e0aeb 100644 --- a/content/browser/appcache/appcache_manifest_parser.h +++ b/content/browser/appcache/appcache_manifest_parser.h
@@ -36,6 +36,7 @@ #include <unordered_set> #include <vector> +#include "content/browser/appcache/appcache_namespace.h" #include "content/common/appcache_interfaces.h" #include "content/common/content_export.h"
diff --git a/content/browser/appcache/appcache_namespace.cc b/content/browser/appcache/appcache_namespace.cc new file mode 100644 index 0000000..9ea5bdc --- /dev/null +++ b/content/browser/appcache/appcache_namespace.cc
@@ -0,0 +1,41 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/appcache/appcache_namespace.h" + +#include <string> + +#include "base/strings/pattern.h" +#include "base/strings/string_util.h" + +namespace content { + +AppCacheNamespace::AppCacheNamespace() + : type(APPCACHE_FALLBACK_NAMESPACE), is_pattern(false) {} + +AppCacheNamespace::AppCacheNamespace(AppCacheNamespaceType type, + const GURL& url, + const GURL& target, + bool is_pattern) + : type(type), + namespace_url(url), + target_url(target), + is_pattern(is_pattern) {} + +AppCacheNamespace::~AppCacheNamespace() = default; + +bool AppCacheNamespace::IsMatch(const GURL& url) const { + if (is_pattern) { + // We have to escape '?' characters since MatchPattern also treats those + // as wildcards which we don't want here, we only do '*'s. + std::string pattern = namespace_url.spec(); + if (namespace_url.has_query()) + base::ReplaceSubstringsAfterOffset(&pattern, 0, "?", "\\?"); + return base::MatchPattern(url.spec(), pattern); + } + return base::StartsWith(url.spec(), namespace_url.spec(), + base::CompareCase::SENSITIVE); +} + +} // namespace content \ No newline at end of file
diff --git a/content/browser/appcache/appcache_namespace.h b/content/browser/appcache/appcache_namespace.h new file mode 100644 index 0000000..709d5ce1 --- /dev/null +++ b/content/browser/appcache/appcache_namespace.h
@@ -0,0 +1,37 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_NAMESPACE_H_ +#define CONTENT_BROWSER_APPCACHE_APPCACHE_NAMESPACE_H_ + +#include "content/common/content_export.h" +#include "url/gurl.h" + +namespace content { + +enum AppCacheNamespaceType { + APPCACHE_FALLBACK_NAMESPACE, + APPCACHE_INTERCEPT_NAMESPACE, + APPCACHE_NETWORK_NAMESPACE, +}; + +struct CONTENT_EXPORT AppCacheNamespace { + AppCacheNamespace(); // Type is APPCACHE_FALLBACK_NAMESPACE by default. + AppCacheNamespace(AppCacheNamespaceType type, + const GURL& url, + const GURL& target, + bool is_pattern); + ~AppCacheNamespace(); + + bool IsMatch(const GURL& url) const; + + AppCacheNamespaceType type; + GURL namespace_url; + GURL target_url; + bool is_pattern; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_NAMESPACE_H_ \ No newline at end of file
diff --git a/content/browser/appcache/appcache_navigation_handle_core.h b/content/browser/appcache/appcache_navigation_handle_core.h index b67013a..5c2408b 100644 --- a/content/browser/appcache/appcache_navigation_handle_core.h +++ b/content/browser/appcache/appcache_navigation_handle_core.h
@@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "content/browser/appcache/appcache_frontend.h" #include "content/common/appcache_interfaces.h" #include "third_party/blink/public/mojom/appcache/appcache.mojom.h" #include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
diff --git a/content/browser/appcache/appcache_request_handler_unittest.cc b/content/browser/appcache/appcache_request_handler_unittest.cc index c764dd6..1bae813 100644 --- a/content/browser/appcache/appcache_request_handler_unittest.cc +++ b/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -27,6 +27,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "content/browser/appcache/appcache.h" #include "content/browser/appcache/appcache_backend_impl.h" +#include "content/browser/appcache/appcache_frontend.h" #include "content/browser/appcache/appcache_job.h" #include "content/browser/appcache/appcache_url_loader_job.h" #include "content/browser/appcache/appcache_url_loader_request.h"
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc index 10307b8..a45f1c4 100644 --- a/content/browser/appcache/appcache_storage_impl_unittest.cc +++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -28,6 +28,7 @@ #include "content/browser/appcache/appcache_backend_impl.h" #include "content/browser/appcache/appcache_database.h" #include "content/browser/appcache/appcache_entry.h" +#include "content/browser/appcache/appcache_frontend.h" #include "content/browser/appcache/appcache_group.h" #include "content/browser/appcache/appcache_host.h" #include "content/browser/appcache/appcache_interceptor.h"
diff --git a/content/browser/appcache/appcache_unittest.cc b/content/browser/appcache/appcache_unittest.cc index 2c6f284..569e1566 100644 --- a/content/browser/appcache/appcache_unittest.cc +++ b/content/browser/appcache/appcache_unittest.cc
@@ -9,6 +9,7 @@ #include "base/test/scoped_task_environment.h" #include "content/browser/appcache/appcache.h" +#include "content/browser/appcache/appcache_frontend.h" #include "content/browser/appcache/appcache_host.h" #include "content/browser/appcache/mock_appcache_service.h" #include "content/common/appcache_interfaces.h"
diff --git a/content/browser/appcache/appcache_update_job.cc b/content/browser/appcache/appcache_update_job.cc index 14545ad..4a8f056 100644 --- a/content/browser/appcache/appcache_update_job.cc +++ b/content/browser/appcache/appcache_update_job.cc
@@ -12,6 +12,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h" +#include "content/browser/appcache/appcache_frontend.h" #include "content/browser/appcache/appcache_group.h" #include "content/browser/appcache/appcache_histograms.h" #include "content/browser/appcache/appcache_update_request_base.h"
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc index a65073a2..5485251 100644 --- a/content/browser/appcache/appcache_update_job_unittest.cc +++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -23,6 +23,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" +#include "content/browser/appcache/appcache_frontend.h" #include "content/browser/appcache/appcache_group.h" #include "content/browser/appcache/appcache_host.h" #include "content/browser/appcache/appcache_response.h"
diff --git a/content/browser/appcache/appcache_url_request_job.cc b/content/browser/appcache/appcache_url_request_job.cc index 906af55..ee1d4aa 100644 --- a/content/browser/appcache/appcache_url_request_job.cc +++ b/content/browser/appcache/appcache_url_request_job.cc
@@ -16,6 +16,7 @@ #include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h" #include "content/browser/appcache/appcache.h" +#include "content/browser/appcache/appcache_frontend.h" #include "content/browser/appcache/appcache_group.h" #include "content/browser/appcache/appcache_histograms.h" #include "content/browser/appcache/appcache_host.h"
diff --git a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc index b011a2ff..07defde3 100644 --- a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc +++ b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
@@ -454,9 +454,11 @@ CacheStorageHandle cache_storage = background_fetch_data_manager_->cache_manager()->OpenCacheStorage( origin(), CacheStorageOwner::kBackgroundFetch); + auto match_params = blink::mojom::QueryParams::New(); + match_params->ignore_search = true; cache_storage.value()->MatchCache( kExampleUniqueId, BackgroundFetchSettledFetch::CloneRequest(request), - /* match_params= */ nullptr, + std::move(match_params), base::BindOnce(&BackgroundFetchDataManagerTest::DidMatchCache, base::Unretained(this), run_loop.QuitClosure(), &result)); @@ -490,7 +492,8 @@ blink::mojom::OperationType::kDelete; operation_ptr_vec[0]->request = BackgroundFetchSettledFetch::CloneRequest(request); - + operation_ptr_vec[0]->match_params = blink::mojom::QueryParams::New(); + operation_ptr_vec[0]->match_params->ignore_search = true; handle.value()->BatchOperation( std::move(operation_ptr_vec), /* fail_on_duplicates= */ true, base::BindOnce(&BackgroundFetchDataManagerTest::DidDeleteFromCache, @@ -1941,11 +1944,91 @@ &settled_fetches); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); - // If the ASSERT below fails, the Cache Storage API implementation has likely - // changed to distinguish keys by request data other than just the URL. - // Thank you! Please can you update the 1u below to 2u, or file a bug against - // component Background Fetch to do so. - ASSERT_EQ(settled_fetches.size(), 1u); + ASSERT_EQ(settled_fetches.size(), 2u); +} + +TEST_F(BackgroundFetchDataManagerTest, MatchRequestsWithDuplicates) { + int64_t sw_id = RegisterServiceWorker(); + ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id); + + std::vector<blink::mojom::FetchAPIRequestPtr> requests; + const std::string base_path = "https://example.com/foo"; + + // Add base request. + { + auto request = blink::mojom::FetchAPIRequest::New(); + request->url = GURL(base_path); + request->method = "GET"; + request->referrer = blink::mojom::Referrer::New(); + requests.push_back(BackgroundFetchSettledFetch::CloneRequest(request)); + requests.push_back(BackgroundFetchSettledFetch::CloneRequest(request)); + } + + // Add base request with a query. + { + auto request = blink::mojom::FetchAPIRequest::New(); + request->method = "GET"; + request->url = GURL(base_path + "?a=b"); + request->referrer = blink::mojom::Referrer::New(); + requests.push_back(BackgroundFetchSettledFetch::CloneRequest(request)); + requests.push_back(BackgroundFetchSettledFetch::CloneRequest(request)); + request->url = GURL(base_path + "?c=d"); + requests.push_back(BackgroundFetchSettledFetch::CloneRequest(request)); + } + + // Add base request with different method. + { + auto request = blink::mojom::FetchAPIRequest::New(); + request->url = GURL(base_path); + request->method = "POST"; + request->referrer = blink::mojom::Referrer::New(); + requests.push_back(BackgroundFetchSettledFetch::CloneRequest(request)); + requests.push_back(BackgroundFetchSettledFetch::CloneRequest(request)); + } + + blink::mojom::BackgroundFetchError error; + BackgroundFetchRegistrationId registration_id( + sw_id, origin(), kExampleDeveloperId, kExampleUniqueId); + + { + auto options = blink::mojom::BackgroundFetchOptions::New(); + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _, _)); + + CreateRegistration(registration_id, CloneRequestVector(requests), + std::move(options), SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } + + std::vector<blink::mojom::BackgroundFetchSettledFetchPtr> settled_fetches; + auto request_to_match = + BackgroundFetchSettledFetch::CloneRequest(requests[0]); + auto query_params = blink::mojom::QueryParams::New(); + + MatchRequests(registration_id, + BackgroundFetchSettledFetch::CloneRequest(request_to_match), + query_params->Clone(), /* match_all= */ true, &error, + &settled_fetches); + EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + // Match only the GETs with the same url. + EXPECT_EQ(settled_fetches.size(), 2u); + + query_params->ignore_search = true; + MatchRequests(registration_id, + BackgroundFetchSettledFetch::CloneRequest(request_to_match), + query_params->Clone(), /* match_all= */ true, &error, + &settled_fetches); + EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + // Match only the GETs with the same url path. + EXPECT_EQ(settled_fetches.size(), 5u); + + query_params->ignore_method = true; + MatchRequests(registration_id, + BackgroundFetchSettledFetch::CloneRequest(request_to_match), + query_params->Clone(), /* match_all= */ true, &error, + &settled_fetches); + EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + // Match everything. + EXPECT_EQ(settled_fetches.size(), requests.size()); } TEST_F(BackgroundFetchDataManagerTest, Cleanup) {
diff --git a/content/browser/background_fetch/background_fetch_request_match_params.h b/content/browser/background_fetch/background_fetch_request_match_params.h index 3eab4913..8dab5fe 100644 --- a/content/browser/background_fetch/background_fetch_request_match_params.h +++ b/content/browser/background_fetch/background_fetch_request_match_params.h
@@ -28,6 +28,10 @@ return request_to_match_; } + const blink::mojom::QueryParamsPtr& cache_query_params() const { + return cache_query_params_; + } + blink::mojom::QueryParamsPtr cloned_cache_query_params() const { if (!cache_query_params_) return nullptr;
diff --git a/content/browser/background_fetch/background_fetch_service_unittest.cc b/content/browser/background_fetch/background_fetch_service_unittest.cc index 3c2204e..d93e1e1c 100644 --- a/content/browser/background_fetch/background_fetch_service_unittest.cc +++ b/content/browser/background_fetch/background_fetch_service_unittest.cc
@@ -200,8 +200,8 @@ base::RunLoop run_loop; service_->MatchRequests( service_worker_registration_id, developer_id, unique_id, - blink::mojom::FetchAPIRequest::New() /* request_to_match*/, - nullptr /* cache_query_params*/, /* match_all= */ true, + /* request_to_match= */ nullptr, + /* cache_query_params= */ nullptr, /* match_all= */ true, base::BindOnce(&BackgroundFetchServiceTest::DidMatchAllRequests, base::Unretained(this), run_loop.QuitClosure(), out_fetches));
diff --git a/content/browser/background_fetch/storage/create_metadata_task.cc b/content/browser/background_fetch/storage/create_metadata_task.cc index d28d6ca..79e36b30 100644 --- a/content/browser/background_fetch/storage/create_metadata_task.cc +++ b/content/browser/background_fetch/storage/create_metadata_task.cc
@@ -382,10 +382,12 @@ // Create batch PUT operations instead of putting them one-by-one. std::vector<blink::mojom::BatchOperationPtr> operations; operations.reserve(requests_.size()); - for (auto& request : requests_) { + for (size_t i = 0; i < requests_.size(); i++) { auto operation = blink::mojom::BatchOperation::New(); operation->operation_type = blink::mojom::OperationType::kPut; - operation->request = std::move(request); + requests_[i]->url = + MakeCacheUrlUnique(requests_[i]->url, registration_id_.unique_id(), i); + operation->request = std::move(requests_[i]); // Empty response. operation->response = blink::mojom::FetchAPIResponse::New(); operations.push_back(std::move(operation));
diff --git a/content/browser/background_fetch/storage/database_helpers.cc b/content/browser/background_fetch/storage/database_helpers.cc index 41ed22f4..2071d04 100644 --- a/content/browser/background_fetch/storage/database_helpers.cc +++ b/content/browser/background_fetch/storage/database_helpers.cc
@@ -165,6 +165,34 @@ return false; } +GURL MakeCacheUrlUnique(const GURL& url, + const std::string& unique_id, + int request_index) { + std::string query = url.query(); + query += unique_id + base::NumberToString(request_index); + + GURL::Replacements replacements; + replacements.SetQueryStr(query); + + return url.ReplaceComponents(replacements); +} + +GURL RemoveUniqueParamFromCacheURL(const GURL& url, + const std::string& unique_id) { + std::vector<std::string> split = base::SplitStringUsingSubstr( + url.query(), unique_id, base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + + GURL::Replacements replacements; + if (split.size() == 1u) + replacements.ClearQuery(); + else if (split.size() == 2u) + replacements.SetQueryStr(split[0]); + else + NOTREACHED(); + + return url.ReplaceComponents(replacements); +} + } // namespace background_fetch } // namespace content
diff --git a/content/browser/background_fetch/storage/database_helpers.h b/content/browser/background_fetch/storage/database_helpers.h index 4a43dc7..61e76cb 100644 --- a/content/browser/background_fetch/storage/database_helpers.h +++ b/content/browser/background_fetch/storage/database_helpers.h
@@ -72,6 +72,16 @@ proto_failure_reason, blink::mojom::BackgroundFetchFailureReason* failure_reason); +// Utility functions to make sure the request URLs are unique, since +// Cache Storage does not support duplicate URLs yet. +// Use `MakeCacheUrlUnique` before writing to the cache, and +// `RemoveUniqueParamFromCacheURL` when querying from the cache. +CONTENT_EXPORT GURL MakeCacheUrlUnique(const GURL& url, + const std::string& unique_id, + int request_index); +CONTENT_EXPORT GURL RemoveUniqueParamFromCacheURL(const GURL& url, + const std::string& unique_id); + } // namespace background_fetch } // namespace content
diff --git a/content/browser/background_fetch/storage/database_helpers_unittest.cc b/content/browser/background_fetch/storage/database_helpers_unittest.cc new file mode 100644 index 0000000..44346895 --- /dev/null +++ b/content/browser/background_fetch/storage/database_helpers_unittest.cc
@@ -0,0 +1,39 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/background_fetch/storage/database_helpers.h" + +#include <string> + +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace content { +namespace background_fetch { +namespace { + +constexpr char kExampleUniqueId[] = "7e57ab1e-c0de-a150-ca75-1e75f005ba11"; + +bool CacheUrlRoundTrip(const std::string& url) { + GURL gurl(url); + GURL round_trip_url = RemoveUniqueParamFromCacheURL( + MakeCacheUrlUnique(gurl, kExampleUniqueId, 0), kExampleUniqueId); + return round_trip_url == gurl; +} + +TEST(BackgroundFetchDatabaseHelpers, CacheUrlRoundTrip) { + EXPECT_TRUE(CacheUrlRoundTrip("https://example.com")); + EXPECT_TRUE(CacheUrlRoundTrip("https://example.com/")); + EXPECT_TRUE(CacheUrlRoundTrip("https://example.com?a=b")); + EXPECT_TRUE(CacheUrlRoundTrip("https://example.com?a=b&c=d")); + EXPECT_TRUE(CacheUrlRoundTrip("https://example.com/path")); + EXPECT_TRUE(CacheUrlRoundTrip("https://example.com/path/")); + EXPECT_TRUE(CacheUrlRoundTrip("https://example.com/path1/path2")); + EXPECT_TRUE(CacheUrlRoundTrip("https://example.com/path?a=b&c=d")); + EXPECT_TRUE(CacheUrlRoundTrip("https://example.com/path/?a=b&c=d")); +} + +} // namespace +} // namespace background_fetch +} // namespace content
diff --git a/content/browser/background_fetch/storage/mark_request_complete_task.cc b/content/browser/background_fetch/storage/mark_request_complete_task.cc index 899e8f8..ac5dcc5 100644 --- a/content/browser/background_fetch/storage/mark_request_complete_task.cc +++ b/content/browser/background_fetch/storage/mark_request_complete_task.cc
@@ -187,6 +187,9 @@ BackgroundFetchSettledFetch::CloneRequest( request_info_->fetch_request_ptr()); + request->url = MakeCacheUrlUnique(request->url, registration_id_.unique_id(), + request_info_->request_index()); + // TODO(crbug.com/774054): The request blob stored in the cache is being // overwritten here, it should be written back. handle.value()->Put(
diff --git a/content/browser/background_fetch/storage/match_requests_task.cc b/content/browser/background_fetch/storage/match_requests_task.cc index c82ae86e..7600f4c2 100644 --- a/content/browser/background_fetch/storage/match_requests_task.cc +++ b/content/browser/background_fetch/storage/match_requests_task.cc
@@ -56,8 +56,20 @@ request = blink::mojom::FetchAPIRequest::New(); } + auto query_params = match_params_->cloned_cache_query_params(); + if (!query_params) + query_params = blink::mojom::QueryParams::New(); + + // Ignore the search params since we added query params to make the URL + // unique. + query_params->ignore_search = true; + + // Ignore the method since Cache Storage assumes the request being matched + // against is a GET. + query_params->ignore_method = true; + handle_.value()->GetAllMatchedEntries( - std::move(request), match_params_->cloned_cache_query_params(), + std::move(request), std::move(query_params), base::BindOnce(&MatchRequestsTask::DidGetAllMatchedEntries, weak_factory_.GetWeakPtr())); } @@ -79,13 +91,14 @@ return; } - size_t size = match_params_->match_all() ? entries.size() : 1u; - settled_fetches_.reserve(size); - - for (size_t i = 0; i < size; i++) { - auto& entry = entries[i]; + for (auto& entry : entries) { auto settled_fetch = blink::mojom::BackgroundFetchSettledFetch::New(); settled_fetch->request = std::move(entry.first); + settled_fetch->request->url = RemoveUniqueParamFromCacheURL( + settled_fetch->request->url, registration_id_.unique_id()); + + if (!ShouldMatchRequest(settled_fetch->request)) + continue; if (entry.second && entry.second->url_list.empty()) { // We didn't process this empty response, so we should expose it @@ -96,11 +109,36 @@ } settled_fetches_.push_back(std::move(settled_fetch)); + if (!match_params_->match_all()) + break; } FinishWithError(blink::mojom::BackgroundFetchError::NONE); } +bool MatchRequestsTask::ShouldMatchRequest( + const blink::mojom::FetchAPIRequestPtr& request) { + // We were supposed to match everything anyway. + if (!match_params_->FilterByRequest()) + return true; + + // Ignore the request if the methods don't match. + if ((!match_params_->cache_query_params() || + !match_params_->cache_query_params()->ignore_method) && + request->method != match_params_->request_to_match()->method) { + return false; + } + + // Ignore the request if the queries don't match. + if ((!match_params_->cache_query_params() || + !match_params_->cache_query_params()->ignore_search) && + request->url.query() != match_params_->request_to_match()->url.query()) { + return false; + } + + return true; +} + void MatchRequestsTask::FinishWithError( blink::mojom::BackgroundFetchError error) { if (HasStorageError())
diff --git a/content/browser/background_fetch/storage/match_requests_task.h b/content/browser/background_fetch/storage/match_requests_task.h index 2e2e686..b1059fa 100644 --- a/content/browser/background_fetch/storage/match_requests_task.h +++ b/content/browser/background_fetch/storage/match_requests_task.h
@@ -47,6 +47,9 @@ blink::mojom::CacheStorageError error, std::vector<CacheStorageCache::CacheEntry> entries); + // Checks whether |request| shuld be matched given the provided query params. + bool ShouldMatchRequest(const blink::mojom::FetchAPIRequestPtr& request); + void FinishWithError(blink::mojom::BackgroundFetchError error) override; std::string HistogramName() const override;
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index a69d86af..946743a40 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -79,6 +79,7 @@ #include "content/browser/loader_delegate_impl.h" #include "content/browser/media/capture/audio_mirroring_manager.h" #include "content/browser/media/media_internals.h" +#include "content/browser/media/media_keys_listener_manager_impl.h" #include "content/browser/memory/swap_metrics_delegate_uma.h" #include "content/browser/net/browser_online_state_observer.h" #include "content/browser/renderer_host/media/media_stream_manager.h" @@ -119,6 +120,7 @@ #include "media/audio/audio_system.h" #include "media/audio/audio_thread_impl.h" #include "media/base/media.h" +#include "media/base/media_switches.h" #include "media/base/user_input_monitor.h" #include "media/media_buildflags.h" #include "media/midi/midi_service.h" @@ -1452,6 +1454,14 @@ } #endif +#if !defined(OS_CHROMEOS) + if (base::FeatureList::IsEnabled(media::kHardwareMediaKeyHandling)) { + media_keys_listener_manager_ = + std::make_unique<MediaKeysListenerManagerImpl>( + content::ServiceManagerConnection::GetForProcess()->GetConnector()); + } +#endif + #if defined(OS_MACOSX) ThemeHelperMac::GetInstance(); SystemHotkeyHelperMac::GetInstance()->DeferredLoadSystemHotkeys();
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h index 9390c615..9561013 100644 --- a/content/browser/browser_main_loop.h +++ b/content/browser/browser_main_loop.h
@@ -93,6 +93,7 @@ class BrowserOnlineStateObserver; class BrowserThreadImpl; class LoaderDelegateImpl; +class MediaKeysListenerManagerImpl; class MediaStreamManager; class ResourceDispatcherHostImpl; class SaveFileManager; @@ -177,6 +178,9 @@ net::NetworkChangeNotifier* network_change_notifier() const { return network_change_notifier_.get(); } + MediaKeysListenerManagerImpl* media_keys_listener_manager() const { + return media_keys_listener_manager_.get(); + } #if defined(OS_CHROMEOS) KeyboardMicRegistration* keyboard_mic_registration() { @@ -359,6 +363,7 @@ // Members initialized in |BrowserThreadsStarted()| -------------------------- std::unique_ptr<mojo::core::ScopedIPCSupport> mojo_ipc_support_; + std::unique_ptr<MediaKeysListenerManagerImpl> media_keys_listener_manager_; // |user_input_monitor_| has to outlive |audio_manager_|, so declared first. std::unique_ptr<media::UserInputMonitor> user_input_monitor_;
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc index 25a0ecd..0e69ac4 100644 --- a/content/browser/child_process_security_policy_impl.cc +++ b/content/browser/child_process_security_policy_impl.cc
@@ -496,16 +496,16 @@ pending_remove_state_[child_id] = std::move(state->second); security_state_.erase(child_id); - // |child_id| could be inside tasks that are on the UI thread and IO thread - // task queues. We need to keep the |pending_remove_state_| entry around - // until we have successfully executed a task on the IO thread followed by - // a task on the UI thread. This should ensure that any pending tasks on - // either thread will have completed before we remove the entry. - base::PostTaskWithTraitsAndReply( - FROM_HERE, {BrowserThread::IO}, base::DoNothing(), + // |child_id| could be inside tasks that are on the IO thread task queues. We + // need to keep the |pending_remove_state_| entry around until we have + // successfully executed a task on the IO thread. This should ensure that any + // pending tasks on the IO thread will have completed before we remove the + // entry. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, base::BindOnce( [](ChildProcessSecurityPolicyImpl* policy, int child_id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); base::AutoLock lock(policy->lock_); policy->pending_remove_state_.erase(child_id); }, @@ -1498,11 +1498,13 @@ return itr->second.get(); // Check to see if |child_id| is in the pending removal map since this - // may be a call that was already on the IO or UI thread's task queue when the + // may be a call that was already on the IO thread's task queue when the // Remove() call occurred. - itr = pending_remove_state_.find(child_id); - if (itr != pending_remove_state_.end()) - return itr->second.get(); + if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { + itr = pending_remove_state_.find(child_id); + if (itr != pending_remove_state_.end()) + return itr->second.get(); + } return nullptr; }
diff --git a/content/browser/child_process_security_policy_impl.h b/content/browser/child_process_security_policy_impl.h index fa3c693..93af81e 100644 --- a/content/browser/child_process_security_policy_impl.h +++ b/content/browser/child_process_security_policy_impl.h
@@ -168,14 +168,14 @@ // this method exactly once. void Add(int child_id); - // Upon destruction, child processess should unregister themselves by caling + // Upon destruction, child processes should unregister themselves by calling // this method exactly once. // - // Note: Pre-Remove() permissions remain in effect until the task posted - // to the IO thread by this call runs AND the task posted, by that IO thread - // task, to the UI thread removes the entry from |pending_remove_state_|. - // This UI -> IO -> UI task sequence ensures that any pending tasks on either - // thread for this |child_id| are allowed to run before access is completely + // Note: Pre-Remove() permissions remain in effect on the IO thread until + // the task posted to the IO thread by this call runs and removes the entry + // from |pending_remove_state_|. + // This UI -> IO task sequence ensures that any pending tasks, on the IO + // thread, for this |child_id| are allowed to run before access is completely // revoked. void Remove(int child_id); @@ -469,10 +469,9 @@ // This map holds the SecurityState for a child process after Remove() // is called on the UI thread. An entry stays in this map until a task has - // run on the IO thread and then a task posted from there runs on the UI - // thread. This is necessary to provide consistent security decisions and - // avoid races between the UI & IO threads during child process shutdown. - // This separate map is used to preserve SecurityState info AND + // run on the IO thread. This is necessary to provide consistent security + // decisions and avoid races between the UI & IO threads during child process + // shutdown. This separate map is used to preserve SecurityState info AND // preventing mutation of that state after Remove() is called. SecurityStateMap pending_remove_state_ GUARDED_BY(lock_);
diff --git a/content/browser/child_process_security_policy_unittest.cc b/content/browser/child_process_security_policy_unittest.cc index 932f390a..5dd2f94 100644 --- a/content/browser/child_process_security_policy_unittest.cc +++ b/content/browser/child_process_security_policy_unittest.cc
@@ -1052,8 +1052,7 @@ // Tests behavior of CanAccessDataForOrigin() during race conditions that // can occur during Remove(). It verifies that permissions for a child ID are // preserved after a Remove() call until the task, that Remove() has posted to -// the IO thread, has run AND the task posted back to the UI thread has also -// run. +// the IO thread, has run. // // We use a combination of waitable events and extra tasks posted to the // threads to capture permission state from the UI & IO threads during the @@ -1151,16 +1150,15 @@ after_remove_complete_event.Wait(); // Verify expected states at various parts of the removal. - // Note: UI & IO threads are expected to keep pre-Remove() permissions until - // the task Remove() posted runs on the IO thread and the task posted from - // the IO thread runs on the UI thread. + // Note: IO thread is expected to keep pre-Remove() permissions until + // the task Remove() posted runs on the IO thread. EXPECT_TRUE(io_before_remove); EXPECT_TRUE(io_while_io_task_pending); - EXPECT_TRUE(io_after_io_task_completed); + EXPECT_FALSE(io_after_io_task_completed); EXPECT_TRUE(ui_before_remove); - EXPECT_TRUE(ui_while_io_task_pending); - EXPECT_TRUE(ui_after_io_task_completed); + EXPECT_FALSE(ui_while_io_task_pending); + EXPECT_FALSE(ui_after_io_task_completed); EXPECT_FALSE(ui_after_remove_complete); EXPECT_FALSE(io_after_remove_complete);
diff --git a/content/browser/contacts/contacts_provider_android.cc b/content/browser/contacts/contacts_provider_android.cc index 0b501f24..f698eda 100644 --- a/content/browser/contacts/contacts_provider_android.cc +++ b/content/browser/contacts/contacts_provider_android.cc
@@ -103,4 +103,11 @@ std::move(callback_).Run(std::move(contacts_)); } +void ContactsProviderAndroid::EndWithPermissionDenied( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj) { + DCHECK(callback_); + std::move(callback_).Run(base::nullopt); +} + } // namespace content
diff --git a/content/browser/contacts/contacts_provider_android.h b/content/browser/contacts/contacts_provider_android.h index bdb7787..9276052 100644 --- a/content/browser/contacts/contacts_provider_android.h +++ b/content/browser/contacts/contacts_provider_android.h
@@ -28,7 +28,8 @@ blink::mojom::ContactsManager::SelectCallback callback) override; // Adds one contact to the list of contacts selected. Note, EndContactsList - // must be called to signal the end of the construction of the contacts list. + // (or EndWithPermissionDenied) must be called to signal the end of the + // construction of the contacts list. void AddContact(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, jboolean includeNames, @@ -43,6 +44,10 @@ void EndContactsList(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); + // Signals the end (due to a permission error). + void EndWithPermissionDenied(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj); + private: base::android::ScopedJavaGlobalRef<jobject> dialog_;
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc index d82370f5..6ff1be0ae 100644 --- a/content/browser/devtools/protocol/network_handler.cc +++ b/content/browser/devtools/protocol/network_handler.cc
@@ -1797,7 +1797,6 @@ signed_exchange_info->SetHeader( Network::SignedExchangeHeader::Create() .SetRequestUrl(envelope->request_url().url.spec()) - .SetRequestMethod(envelope->request_method()) .SetResponseCode(envelope->response_code()) .SetResponseHeaders(Object::fromValue(headers_dict.get(), nullptr)) .SetSignatures(std::move(signatures))
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc index 1e2fc1d..4a2b9d6a 100644 --- a/content/browser/frame_host/navigation_controller_impl.cc +++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -2194,6 +2194,7 @@ /* params.navigation_ui_data: skip */ /* params.input_start: skip */ params.was_activated = WasActivatedOption::kUnknown; + /* params.reload_type: skip */ std::unique_ptr<NavigationRequest> request = CreateNavigationRequestFromLoadParams( @@ -2656,8 +2657,9 @@ // expect to see treated as reload, and it only works because they pass a // FrameTreeNode id in their LoadURLParams. Change this once they no longer do // that. See https://crbug.com/850926. - ReloadType reload_type = ReloadType::NONE; - if (ShouldTreatNavigationAsReload( + ReloadType reload_type = params.reload_type; + if (reload_type == ReloadType::NONE && + ShouldTreatNavigationAsReload( params.url, pending_entry_->GetVirtualURL(), params.base_url_for_data_url, params.transition_type, params.frame_tree_node_id == RenderFrameHost::kNoFrameTreeNodeId, @@ -2780,6 +2782,7 @@ entry->set_should_clear_history_list(params.should_clear_history_list); entry->SetIsOverridingUserAgent(override_user_agent); entry->set_has_user_gesture(has_user_gesture); + entry->set_reload_type(params.reload_type); switch (params.load_type) { case LOAD_TYPE_DEFAULT:
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc index b902831..309ecef 100644 --- a/content/browser/frame_host/navigation_controller_impl_unittest.cc +++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -269,12 +269,14 @@ explicit LoadCommittedDetailsObserver(WebContents* web_contents) : WebContentsObserver(web_contents), navigation_type_(NAVIGATION_TYPE_UNKNOWN), + reload_type_(ReloadType::NONE), is_same_document_(false), is_main_frame_(false), did_replace_entry_(false) {} NavigationType navigation_type() { return navigation_type_; } const GURL& previous_url() { return previous_url_; } + ReloadType reload_type() { return reload_type_; } bool is_same_document() { return is_same_document_; } bool is_main_frame() { return is_main_frame_; } bool did_replace_entry() { return did_replace_entry_; } @@ -288,6 +290,7 @@ navigation_type_ = static_cast<NavigationHandleImpl*>(navigation_handle) ->navigation_type(); previous_url_ = navigation_handle->GetPreviousURL(); + reload_type_ = navigation_handle->GetReloadType(); is_same_document_ = navigation_handle->IsSameDocument(); is_main_frame_ = navigation_handle->IsInMainFrame(); did_replace_entry_ = navigation_handle->DidReplaceEntry(); @@ -296,6 +299,7 @@ NavigationType navigation_type_; GURL previous_url_; + ReloadType reload_type_; bool is_same_document_; bool is_main_frame_; bool did_replace_entry_; @@ -610,6 +614,7 @@ EXPECT_EQ(should_override, entry->GetIsOverridingUserAgent()); } EXPECT_EQ(load_params.post_data, entry->GetPostData()); + EXPECT_EQ(load_params.reload_type, entry->reload_type()); } TEST_F(NavigationControllerTest, LoadURLWithParams) { @@ -648,6 +653,29 @@ CheckNavigationEntryMatchLoadParams(load_url_params, entry); } +TEST_F(NavigationControllerTest, LoadURLWithParams_Reload) { + NavigationControllerImpl& controller = controller_impl(); + GURL url("https://reload"); + + auto navigation = + NavigationSimulatorImpl::CreateBrowserInitiated(url, contents()); + NavigationController::LoadURLParams load_url_params(url); + load_url_params.initiator_origin = url::Origin::Create(url); + load_url_params.referrer = Referrer(GURL("http://referrer"), + network::mojom::ReferrerPolicy::kDefault); + load_url_params.transition_type = ui::PAGE_TRANSITION_GENERATED; + load_url_params.extra_headers = "content-type: text/plain;\nX-Foo: Bar"; + load_url_params.load_type = NavigationController::LOAD_TYPE_DEFAULT; + load_url_params.is_renderer_initiated = true; + load_url_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE; + load_url_params.reload_type = ReloadType::BYPASSING_CACHE; + navigation->SetLoadURLParams(&load_url_params); + navigation->Start(); + + NavigationEntryImpl* entry = controller.GetPendingEntry(); + CheckNavigationEntryMatchLoadParams(load_url_params, entry); +} + TEST_F(NavigationControllerTest, LoadURLWithExtraParams_Data) { NavigationControllerImpl& controller = controller_impl(); GURL url("data:text/html,dataurl"); @@ -5209,6 +5237,22 @@ EXPECT_TRUE(observer.has_navigation_ui_data()); } +// Tests that ReloadType has been passed to the NavigationHandle. +TEST_F(NavigationControllerTest, MainFrameNavigationReloadType) { + LoadCommittedDetailsObserver observer(contents()); + const GURL url1("http://foo1"); + + auto navigation = + NavigationSimulatorImpl::CreateBrowserInitiated(url1, contents()); + NavigationController::LoadURLParams load_url_params(url1); + load_url_params.reload_type = ReloadType::BYPASSING_CACHE; + navigation->SetLoadURLParams(&load_url_params); + navigation->Commit(); + + EXPECT_TRUE(observer.is_main_frame()); + EXPECT_EQ(observer.reload_type(), ReloadType::BYPASSING_CACHE); +} + // Tests calling LoadURLParams with NavigationUIData and for a sub frame. TEST_F(NavigationControllerTest, SubFrameNavigationUIData) { // Navigate to a page.
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc index 198b6444..c108626d 100644 --- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc +++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -44,6 +44,7 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" #include "services/network/public/cpp/features.h" +#include "services/service_manager/public/mojom/interface_provider.mojom-test-utils.h" #include "testing/gmock/include/gmock/gmock.h" namespace content {
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc index 0e48fa7..e86cb15 100644 --- a/content/browser/indexed_db/indexed_db_backing_store.cc +++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -9,6 +9,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/files/important_file_writer.h" #include "base/format_macros.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" @@ -55,6 +56,7 @@ #include "third_party/leveldatabase/env_chromium.h" using base::FilePath; +using base::ImportantFileWriter; using base::StringPiece; using blink::IndexedDBDatabaseMetadata; using blink::IndexedDBKey; @@ -852,13 +854,8 @@ root_dict.SetString("message", message); std::string output_js; base::JSONWriter::Write(root_dict, &output_js); - - base::File file(info_path, - base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); - if (!file.IsValid()) - return false; - int written = file.Write(0, output_js.c_str(), output_js.length()); - return size_t(written) == output_js.length(); + return base::ImportantFileWriter::WriteFileAtomically(info_path, + output_js.c_str()); } void IndexedDBBackingStore::GrantChildProcessPermissions(int child_process_id) {
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc index 3e9e078..c4fdd51 100644 --- a/content/browser/isolated_origin_browsertest.cc +++ b/content/browser/isolated_origin_browsertest.cc
@@ -34,6 +34,8 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "services/network/public/cpp/features.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/mojom/dom_storage/storage_partition_service.mojom-test-utils.h" +#include "third_party/blink/public/platform/modules/broadcastchannel/broadcast_channel.mojom-test-utils.h" #include "third_party/blink/public/platform/modules/broadcastchannel/broadcast_channel.mojom.h" #include "url/gurl.h"
diff --git a/content/browser/media/flinging_renderer_unittest.cc b/content/browser/media/flinging_renderer_unittest.cc index 8bb499d..af57fbb 100644 --- a/content/browser/media/flinging_renderer_unittest.cc +++ b/content/browser/media/flinging_renderer_unittest.cc
@@ -9,6 +9,7 @@ #include "base/time/time.h" #include "base/version.h" #include "media/base/media_controller.h" +#include "media/base/mock_filters.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -27,20 +28,6 @@ MOCK_METHOD1(Seek, void(base::TimeDelta)); }; -class MockRendererClient : public media::RendererClient { - public: - MOCK_METHOD1(OnError, void(media::PipelineStatus)); - MOCK_METHOD0(OnEnded, void()); - MOCK_METHOD1(OnStatisticsUpdate, void(const media::PipelineStatistics&)); - MOCK_METHOD1(OnBufferingStateChange, void(media::BufferingState)); - MOCK_METHOD1(OnWaiting, void(media::WaitingReason)); - MOCK_METHOD1(OnAudioConfigChange, void(const media::AudioDecoderConfig&)); - MOCK_METHOD1(OnVideoConfigChange, void(const media::VideoDecoderConfig&)); - MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&)); - MOCK_METHOD1(OnVideoOpacityChange, void(bool)); - MOCK_METHOD1(OnDurationChange, void(base::TimeDelta)); -}; - class MockFlingingController : public media::FlingingController { public: explicit MockFlingingController(media::MediaController* media_controller) @@ -72,7 +59,7 @@ } protected: - NiceMock<MockRendererClient> renderer_client_; + NiceMock<media::MockRendererClient> renderer_client_; std::unique_ptr<MockMediaController> media_controller_; StrictMock<MockFlingingController>* flinging_controller_; std::unique_ptr<FlingingRenderer> renderer_;
diff --git a/content/browser/media/hardware_key_media_controller.cc b/content/browser/media/hardware_key_media_controller.cc new file mode 100644 index 0000000..26be8a4 --- /dev/null +++ b/content/browser/media/hardware_key_media_controller.cc
@@ -0,0 +1,178 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/media/hardware_key_media_controller.h" + +#include <algorithm> +#include <utility> +#include <vector> + +#include "content/public/browser/media_keys_listener_manager.h" +#include "services/media_session/public/mojom/constants.mojom.h" +#include "services/service_manager/public/cpp/connector.h" +#include "ui/base/accelerators/accelerator.h" + +namespace content { + +using media_session::mojom::MediaSessionAction; + +HardwareKeyMediaController::HardwareKeyMediaController( + service_manager::Connector* connector) { + // |connector| can be null in tests. + if (!connector) + return; + + // Connect to the MediaControllerManager and create a MediaController that + // controls the active session. + media_session::mojom::MediaControllerManagerPtr controller_manager_ptr; + connector->BindInterface(media_session::mojom::kServiceName, + mojo::MakeRequest(&controller_manager_ptr)); + controller_manager_ptr->CreateActiveMediaController( + mojo::MakeRequest(&media_controller_ptr_)); + + // Observe the active media session for changes to playback state and + // supported actions. + media_session::mojom::MediaSessionObserverPtr media_session_observer; + media_session_observer_binding_.Bind( + mojo::MakeRequest(&media_session_observer)); + media_controller_ptr_->AddObserver(std::move(media_session_observer)); +} + +HardwareKeyMediaController::~HardwareKeyMediaController() = default; + +void HardwareKeyMediaController::MediaSessionInfoChanged( + media_session::mojom::MediaSessionInfoPtr session_info) { + session_info_ = std::move(session_info); +} + +void HardwareKeyMediaController::MediaSessionActionsChanged( + const std::vector<MediaSessionAction>& actions) { + MediaKeysListenerManager* media_keys_listener_manager = + MediaKeysListenerManager::GetInstance(); + DCHECK(media_keys_listener_manager); + + // Stop listening to any keys that are currently being watched, but aren't in + // |actions|. + for (const MediaSessionAction& action : actions_) { + base::Optional<ui::KeyboardCode> action_key_code = + MediaSessionActionToKeyCode(action); + + // We only store supported actions in |actions_|, so we should always get a + // value from |MediaSessionActionToKeyCode()| here. + DCHECK(action_key_code.has_value()); + if (std::find(actions.begin(), actions.end(), action) == actions.end()) + media_keys_listener_manager->StopWatchingMediaKey(*action_key_code, this); + } + + // Populate |actions_| with the new MediaSessionActions and start listening + // to necessary media keys. + actions_.clear(); + for (const MediaSessionAction& action : actions) { + base::Optional<ui::KeyboardCode> action_key_code = + MediaSessionActionToKeyCode(action); + if (action_key_code.has_value()) { + // It's okay to call this even on keys we're already listening to, since + // it's a no-op in that case. + if (media_keys_listener_manager->StartWatchingMediaKey(*action_key_code, + this)) { + actions_.insert(action); + } + } + } +} + +void HardwareKeyMediaController::FlushForTesting() { + media_controller_ptr_.FlushForTesting(); +} + +void HardwareKeyMediaController::OnMediaKeysAccelerator( + const ui::Accelerator& accelerator) { + // Ignore key released events. + if (accelerator.key_state() == ui::Accelerator::KeyState::RELEASED) + return; + + MediaSessionAction action = + KeyCodeToMediaSessionAction(accelerator.key_code()); + + // Ignore if we don't support the action. + if (!SupportsAction(action)) + return; + + PerformAction(action); +} + +bool HardwareKeyMediaController::SupportsAction( + MediaSessionAction action) const { + return actions_.contains(action); +} + +void HardwareKeyMediaController::PerformAction(MediaSessionAction action) { + DCHECK(SupportsAction(action)); + switch (action) { + case MediaSessionAction::kPreviousTrack: + media_controller_ptr_->PreviousTrack(); + return; + case MediaSessionAction::kPlay: + media_controller_ptr_->Resume(); + return; + case MediaSessionAction::kPause: + media_controller_ptr_->Suspend(); + return; + case MediaSessionAction::kNextTrack: + media_controller_ptr_->NextTrack(); + return; + case MediaSessionAction::kStop: + media_controller_ptr_->Stop(); + return; + case MediaSessionAction::kSeekBackward: + case MediaSessionAction::kSeekForward: + case MediaSessionAction::kSkipAd: + NOTREACHED(); + return; + } +} + +MediaSessionAction HardwareKeyMediaController::KeyCodeToMediaSessionAction( + ui::KeyboardCode key_code) const { + switch (key_code) { + case ui::KeyboardCode::VKEY_MEDIA_PLAY_PAUSE: + if (session_info_ && + session_info_->playback_state == + media_session::mojom::MediaPlaybackState::kPlaying) { + return MediaSessionAction::kPause; + } + return MediaSessionAction::kPlay; + case ui::KeyboardCode::VKEY_MEDIA_STOP: + return MediaSessionAction::kStop; + case ui::KeyboardCode::VKEY_MEDIA_NEXT_TRACK: + return MediaSessionAction::kNextTrack; + case ui::KeyboardCode::VKEY_MEDIA_PREV_TRACK: + return MediaSessionAction::kPreviousTrack; + default: + NOTREACHED(); + return MediaSessionAction::kPlay; + } +} + +base::Optional<ui::KeyboardCode> +HardwareKeyMediaController::MediaSessionActionToKeyCode( + MediaSessionAction action) const { + switch (action) { + case MediaSessionAction::kPlay: + case MediaSessionAction::kPause: + return ui::KeyboardCode::VKEY_MEDIA_PLAY_PAUSE; + case MediaSessionAction::kStop: + return ui::KeyboardCode::VKEY_MEDIA_STOP; + case MediaSessionAction::kNextTrack: + return ui::KeyboardCode::VKEY_MEDIA_NEXT_TRACK; + case MediaSessionAction::kPreviousTrack: + return ui::KeyboardCode::VKEY_MEDIA_PREV_TRACK; + case MediaSessionAction::kSeekBackward: + case MediaSessionAction::kSeekForward: + case MediaSessionAction::kSkipAd: + return base::nullopt; + } +} + +} // namespace content \ No newline at end of file
diff --git a/content/browser/media/hardware_key_media_controller.h b/content/browser/media/hardware_key_media_controller.h new file mode 100644 index 0000000..1e5d40e --- /dev/null +++ b/content/browser/media/hardware_key_media_controller.h
@@ -0,0 +1,84 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MEDIA_HARDWARE_KEY_MEDIA_CONTROLLER_H_ +#define CONTENT_BROWSER_MEDIA_HARDWARE_KEY_MEDIA_CONTROLLER_H_ + +#include <utility> +#include <vector> + +#include "base/containers/flat_set.h" +#include "base/optional.h" +#include "content/common/content_export.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "services/media_session/public/mojom/media_controller.mojom.h" +#include "services/media_session/public/mojom/media_session.mojom.h" +#include "ui/base/accelerators/media_keys_listener.h" +#include "ui/events/keycodes/keyboard_codes.h" + +namespace service_manager { +class Connector; +} // namespace service_manager + +namespace content { + +// HardwareKeyMediaController controls media sessions via hardware media keys. +class CONTENT_EXPORT HardwareKeyMediaController + : public media_session::mojom::MediaSessionObserver, + public ui::MediaKeysListener::Delegate { + public: + explicit HardwareKeyMediaController(service_manager::Connector* connector); + ~HardwareKeyMediaController() override; + + // media_session::mojom::MediaSessionObserver: + void MediaSessionInfoChanged( + media_session::mojom::MediaSessionInfoPtr session_info) override; + void MediaSessionMetadataChanged( + const base::Optional<media_session::MediaMetadata>& metadata) override {} + void MediaSessionActionsChanged( + const std::vector<media_session::mojom::MediaSessionAction>& actions) + override; + + // ui::MediaKeysListener::Delegate: + void OnMediaKeysAccelerator(const ui::Accelerator& accelerator) override; + + void FlushForTesting(); + void SetMediaControllerForTesting( + media_session::mojom::MediaControllerPtr controller) { + media_controller_ptr_ = std::move(controller); + } + + private: + // Used for converting between MediaSessionAction and KeyboardCode. + media_session::mojom::MediaSessionAction KeyCodeToMediaSessionAction( + ui::KeyboardCode key_code) const; + + // Returns nullopt if the action is not supported via hardware keys (e.g. + // SeekBackward). + base::Optional<ui::KeyboardCode> MediaSessionActionToKeyCode( + media_session::mojom::MediaSessionAction action) const; + + bool SupportsAction(media_session::mojom::MediaSessionAction action) const; + void PerformAction(media_session::mojom::MediaSessionAction action); + + // Used to control the active session. + media_session::mojom::MediaControllerPtr media_controller_ptr_; + + // Used to check whether a play/pause key should play or pause (based on + // current playback state). + media_session::mojom::MediaSessionInfoPtr session_info_; + + // Used to check which actions are currently supported. + base::flat_set<media_session::mojom::MediaSessionAction> actions_; + + // Used to receive updates to the active MediaSession. + mojo::Binding<media_session::mojom::MediaSessionObserver> + media_session_observer_binding_{this}; + + DISALLOW_COPY_AND_ASSIGN(HardwareKeyMediaController); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_HARDWARE_KEY_MEDIA_CONTROLLER_H_ \ No newline at end of file
diff --git a/content/browser/media/media_keys_listener_manager_impl.cc b/content/browser/media/media_keys_listener_manager_impl.cc new file mode 100644 index 0000000..48b8e68 --- /dev/null +++ b/content/browser/media/media_keys_listener_manager_impl.cc
@@ -0,0 +1,185 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/media/media_keys_listener_manager_impl.h" + +#include <memory> +#include <utility> + +#include "content/browser/browser_main_loop.h" +#include "content/browser/media/hardware_key_media_controller.h" +#include "ui/base/accelerators/accelerator.h" + +namespace content { + +MediaKeysListenerManagerImpl::ListeningData::ListeningData() + : hardware_key_media_controller_listening(false) {} + +MediaKeysListenerManagerImpl::ListeningData::~ListeningData() = default; + +// static +MediaKeysListenerManager* MediaKeysListenerManager::GetInstance() { + if (!BrowserMainLoop::GetInstance()) + return nullptr; + + return BrowserMainLoop::GetInstance()->media_keys_listener_manager(); +} + +MediaKeysListenerManagerImpl::MediaKeysListenerManagerImpl( + service_manager::Connector* connector) + : hardware_key_media_controller_( + std::make_unique<HardwareKeyMediaController>(connector)), + media_key_handling_enabled_(true) { + DCHECK(!MediaKeysListenerManager::GetInstance()); +} + +MediaKeysListenerManagerImpl::~MediaKeysListenerManagerImpl() = default; + +bool MediaKeysListenerManagerImpl::StartWatchingMediaKey( + ui::KeyboardCode key_code, + ui::MediaKeysListener::Delegate* delegate) { + DCHECK(ui::MediaKeysListener::IsMediaKeycode(key_code)); + DCHECK(delegate); + EnsureMediaKeysListener(); + + // We don't want to start watching the key for the HardwareKeyMediaController + // if the HardwareKeyMediaController won't receive events. + bool is_hardware_key_media_controller = + delegate == hardware_key_media_controller_.get(); + bool should_start_watching = !is_hardware_key_media_controller || + CanHardwareKeyMediaControllerReceiveEvents(); + + // Tell the underlying MediaKeysListener to listen for the key. + if (should_start_watching && + !media_keys_listener_->StartWatchingMediaKey(key_code)) { + return false; + } + + ListeningData* listening_data = GetOrCreateListeningData(key_code); + + // If this is the HardwareKeyMediaController, just update the flag. + if (is_hardware_key_media_controller) { + listening_data->hardware_key_media_controller_listening = true; + return true; + } + + // Add the delegate to the list of listening delegates if necessary. + if (!listening_data->listeners.HasObserver(delegate)) + listening_data->listeners.AddObserver(delegate); + + // Update listeners, as some HardwareKeyMediaController listeners may no + // longer be needed. + UpdateKeyListening(); + + return true; +} + +void MediaKeysListenerManagerImpl::StopWatchingMediaKey( + ui::KeyboardCode key_code, + ui::MediaKeysListener::Delegate* delegate) { + DCHECK(ui::MediaKeysListener::IsMediaKeycode(key_code)); + DCHECK(delegate); + EnsureMediaKeysListener(); + + // Find or create the list of listening delegates for this key code. + ListeningData* listening_data = GetOrCreateListeningData(key_code); + + // Update the listening data to remove this delegate. + if (delegate == hardware_key_media_controller_.get()) { + listening_data->hardware_key_media_controller_listening = false; + if (!ShouldListenToKey(*listening_data)) + media_keys_listener_->StopWatchingMediaKey(key_code); + } else { + listening_data->listeners.RemoveObserver(delegate); + UpdateKeyListening(); + } +} + +void MediaKeysListenerManagerImpl::DisableInternalMediaKeyHandling() { + media_key_handling_enabled_ = false; + UpdateKeyListening(); +} + +void MediaKeysListenerManagerImpl::EnableInternalMediaKeyHandling() { + media_key_handling_enabled_ = true; + UpdateKeyListening(); +} + +void MediaKeysListenerManagerImpl::OnMediaKeysAccelerator( + const ui::Accelerator& accelerator) { + // We should never receive an accelerator that was never registered. + DCHECK(delegate_map_.contains(accelerator.key_code())); + + ListeningData* listening_data = delegate_map_[accelerator.key_code()].get(); + + // If the HardwareKeyMediaController is listening and is allowed to listen, + // notify it of the media key press. + if (listening_data->hardware_key_media_controller_listening && + CanHardwareKeyMediaControllerReceiveEvents()) { + hardware_key_media_controller_->OnMediaKeysAccelerator(accelerator); + return; + } + + // Otherwise, notify delegates. + for (auto& delegate : listening_data->listeners) + delegate.OnMediaKeysAccelerator(accelerator); +} + +void MediaKeysListenerManagerImpl::EnsureMediaKeysListener() { + if (media_keys_listener_) + return; + + media_keys_listener_ = ui::MediaKeysListener::Create( + this, ui::MediaKeysListener::Scope::kGlobal); + DCHECK(media_keys_listener_); +} + +MediaKeysListenerManagerImpl::ListeningData* +MediaKeysListenerManagerImpl::GetOrCreateListeningData( + ui::KeyboardCode key_code) { + auto listening_data_itr = delegate_map_.find(key_code); + if (listening_data_itr == delegate_map_.end()) { + listening_data_itr = + delegate_map_ + .insert(std::make_pair(key_code, std::make_unique<ListeningData>())) + .first; + } + return listening_data_itr->second.get(); +} + +void MediaKeysListenerManagerImpl::UpdateKeyListening() { + EnsureMediaKeysListener(); + + for (const auto& key_code_listening_data : delegate_map_) { + const ui::KeyboardCode& key_code = key_code_listening_data.first; + const ListeningData* listening_data = key_code_listening_data.second.get(); + + if (ShouldListenToKey(*listening_data)) + media_keys_listener_->StartWatchingMediaKey(key_code); + else + media_keys_listener_->StopWatchingMediaKey(key_code); + } +} + +bool MediaKeysListenerManagerImpl::ShouldListenToKey( + const ListeningData& listening_data) const { + return listening_data.listeners.might_have_observers() || + (listening_data.hardware_key_media_controller_listening && + CanHardwareKeyMediaControllerReceiveEvents()); +} + +bool MediaKeysListenerManagerImpl::AnyDelegatesListening() const { + for (const auto& key_code_listening_data : delegate_map_) { + if (key_code_listening_data.second->listeners.might_have_observers()) + return true; + } + return false; +} + +bool MediaKeysListenerManagerImpl::CanHardwareKeyMediaControllerReceiveEvents() + const { + return media_key_handling_enabled_ && !AnyDelegatesListening(); +} + +} // namespace content \ No newline at end of file
diff --git a/content/browser/media/media_keys_listener_manager_impl.h b/content/browser/media/media_keys_listener_manager_impl.h new file mode 100644 index 0000000..d3312b7 --- /dev/null +++ b/content/browser/media/media_keys_listener_manager_impl.h
@@ -0,0 +1,105 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MEDIA_MEDIA_KEYS_LISTENER_MANAGER_IMPL_H_ +#define CONTENT_BROWSER_MEDIA_MEDIA_KEYS_LISTENER_MANAGER_IMPL_H_ + +#include <memory> +#include <utility> + +#include "base/containers/flat_map.h" +#include "base/observer_list.h" +#include "content/common/content_export.h" +#include "content/public/browser/media_keys_listener_manager.h" +#include "ui/base/accelerators/media_keys_listener.h" +#include "ui/events/keycodes/keyboard_codes.h" + +namespace service_manager { +class Connector; +} // namespace service_manager + +namespace content { + +class HardwareKeyMediaController; + +// Listens for media keys and decides which listeners receive which events. In +// particular, it owns one of its delegates (HardwareKeyMediaController), and +// only propagates to the HardwareKeyMediaController if no other delegates are +// listening to a particular media key. +class CONTENT_EXPORT MediaKeysListenerManagerImpl + : public MediaKeysListenerManager, + public ui::MediaKeysListener::Delegate { + public: + explicit MediaKeysListenerManagerImpl(service_manager::Connector* connector); + ~MediaKeysListenerManagerImpl() override; + + // MediaKeysListenerManager implementation. + bool StartWatchingMediaKey( + ui::KeyboardCode key_code, + ui::MediaKeysListener::Delegate* delegate) override; + void StopWatchingMediaKey(ui::KeyboardCode key_code, + ui::MediaKeysListener::Delegate* delegate) override; + void DisableInternalMediaKeyHandling() override; + void EnableInternalMediaKeyHandling() override; + + // ui::MediaKeysListener::Delegate: + void OnMediaKeysAccelerator(const ui::Accelerator& accelerator) override; + + HardwareKeyMediaController* hardware_key_media_controller_for_testing() { + return hardware_key_media_controller_.get(); + } + void SetMediaKeysListenerForTesting( + std::unique_ptr<ui::MediaKeysListener> media_keys_listener) { + media_keys_listener_ = std::move(media_keys_listener); + } + + private: + // ListeningData tracks which delegates are listening to a particular key. We + // track the HardwareKeyMediaController separately from the other listeners as + // it is treated differently. + struct ListeningData { + ListeningData(); + ~ListeningData(); + + // True if the HardwareKeyMediaController is listening for this key. + bool hardware_key_media_controller_listening; + + // Contains non-HardwareKeyMediaController listeners. + base::ObserverList<ui::MediaKeysListener::Delegate> listeners; + + private: + DISALLOW_COPY_AND_ASSIGN(ListeningData); + }; + + void EnsureMediaKeysListener(); + ListeningData* GetOrCreateListeningData(ui::KeyboardCode key_code); + + // Starts/stops watching media keys based on the current state. + void UpdateKeyListening(); + + // True if we should listen for a key with the given listening data. + bool ShouldListenToKey(const ListeningData& listening_data) const; + + // True if any delegates besides the HardwareKeyMediaController are listening + // to any media keys. + bool AnyDelegatesListening() const; + + // True if the HardwareKeyMediaController is allowed to receive events. + bool CanHardwareKeyMediaControllerReceiveEvents() const; + + base::flat_map<ui::KeyboardCode, std::unique_ptr<ListeningData>> + delegate_map_; + std::unique_ptr<ui::MediaKeysListener> media_keys_listener_; + std::unique_ptr<HardwareKeyMediaController> hardware_key_media_controller_; + + // False if media key handling has been explicitly disabled by a call to + // |DisableInternalMediaKeyHandling()|. + bool media_key_handling_enabled_; + + DISALLOW_COPY_AND_ASSIGN(MediaKeysListenerManagerImpl); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_MEDIA_KEYS_LISTENER_MANAGER_IMPL_H_ \ No newline at end of file
diff --git a/content/browser/media/media_keys_listener_manager_impl_browsertest.cc b/content/browser/media/media_keys_listener_manager_impl_browsertest.cc new file mode 100644 index 0000000..080921c --- /dev/null +++ b/content/browser/media/media_keys_listener_manager_impl_browsertest.cc
@@ -0,0 +1,334 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/media/media_keys_listener_manager_impl.h" + +#include "base/containers/flat_set.h" +#include "base/test/scoped_feature_list.h" +#include "content/browser/browser_main_loop.h" +#include "content/browser/media/hardware_key_media_controller.h" +#include "content/public/test/content_browser_test.h" +#include "media/base/media_switches.h" +#include "services/media_session/public/cpp/test/test_media_controller.h" +#include "services/media_session/public/mojom/media_session.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/accelerators/media_keys_listener.h" + +namespace content { + +using media_session::mojom::MediaPlaybackState; +using media_session::mojom::MediaSessionAction; +using media_session::mojom::MediaSessionInfo; +using media_session::mojom::MediaSessionInfoPtr; +using media_session::test::TestMediaController; + +namespace { + +class MockMediaKeysListener : public ui::MediaKeysListener { + public: + explicit MockMediaKeysListener(ui::MediaKeysListener::Delegate* delegate) + : delegate_(delegate) {} + ~MockMediaKeysListener() override = default; + + // MediaKeysListener implementation. + bool StartWatchingMediaKey(ui::KeyboardCode key_code) override { + key_codes_.insert(key_code); + return true; + } + void StopWatchingMediaKey(ui::KeyboardCode key_code) override { + key_codes_.erase(key_code); + } + + void SimulateAccelerator(ui::Accelerator accelerator) { + if (IsWatching(accelerator.key_code())) + delegate_->OnMediaKeysAccelerator(accelerator); + } + + bool IsWatching(ui::KeyboardCode key_code) { + return key_codes_.contains(key_code); + } + + private: + ui::MediaKeysListener::Delegate* delegate_; + base::flat_set<ui::KeyboardCode> key_codes_; + + DISALLOW_COPY_AND_ASSIGN(MockMediaKeysListener); +}; + +class MockMediaKeysListenerDelegate : public ui::MediaKeysListener::Delegate { + public: + MockMediaKeysListenerDelegate() = default; + ~MockMediaKeysListenerDelegate() override = default; + + // MediaKeysListener::Delegate implementation. + void OnMediaKeysAccelerator(const ui::Accelerator& accelerator) override { + received_keys_.push_back(accelerator.key_code()); + } + + // Expect that we have received the correct number of key events. + void ExpectReceivedKeysCount(uint32_t count) { + EXPECT_EQ(count, received_keys_.size()); + } + + // Expect that the key event received at |index| has the specified key code. + void ExpectReceivedKey(uint32_t index, ui::KeyboardCode code) { + ASSERT_LT(index, received_keys_.size()); + EXPECT_EQ(code, received_keys_[index]); + } + + private: + std::vector<ui::KeyboardCode> received_keys_; + + DISALLOW_COPY_AND_ASSIGN(MockMediaKeysListenerDelegate); +}; + +} // anonymous namespace + +class MediaKeysListenerManagerImplTest : public ContentBrowserTest { + public: + MediaKeysListenerManagerImplTest() = default; + ~MediaKeysListenerManagerImplTest() override = default; + + protected: + void SetUpCommandLine(base::CommandLine* command_line) override { + ContentBrowserTest::SetUpCommandLine(command_line); + scoped_feature_list_.InitAndEnableFeature(media::kHardwareMediaKeyHandling); + } + + void SetUpOnMainThread() override { + media_keys_listener_manager_ = + BrowserMainLoop::GetInstance()->media_keys_listener_manager(); + + std::unique_ptr<MockMediaKeysListener> listener = + std::make_unique<MockMediaKeysListener>(media_keys_listener_manager_); + media_keys_listener_ = listener.get(); + media_keys_listener_manager_->SetMediaKeysListenerForTesting( + std::move(listener)); + + media_controller_ = std::make_unique<TestMediaController>(); + media_keys_listener_manager_->hardware_key_media_controller_for_testing() + ->SetMediaControllerForTesting( + media_controller_->CreateMediaControllerPtr()); + + ContentBrowserTest::SetUpOnMainThread(); + } + + void SetMediaSessionInfo(MediaSessionInfoPtr session_info) { + media_keys_listener_manager_->hardware_key_media_controller_for_testing() + ->MediaSessionInfoChanged(std::move(session_info)); + } + void SetSupportedMediaSessionActions( + const std::vector<MediaSessionAction>& actions) { + media_keys_listener_manager_->hardware_key_media_controller_for_testing() + ->MediaSessionActionsChanged(actions); + } + void FlushForTesting() { + media_keys_listener_manager_->hardware_key_media_controller_for_testing() + ->FlushForTesting(); + } + + MediaKeysListenerManagerImpl* media_keys_listener_manager() { + return media_keys_listener_manager_; + } + MockMediaKeysListener* media_keys_listener() { return media_keys_listener_; } + TestMediaController* media_controller() { return media_controller_.get(); } + + private: + base::test::ScopedFeatureList scoped_feature_list_; + MediaKeysListenerManagerImpl* media_keys_listener_manager_; + MockMediaKeysListener* media_keys_listener_; + std::unique_ptr<TestMediaController> media_controller_; + + DISALLOW_COPY_AND_ASSIGN(MediaKeysListenerManagerImplTest); +}; + +IN_PROC_BROWSER_TEST_F(MediaKeysListenerManagerImplTest, PressPlayPauseKey) { + // Tell the HardwareKeyMediaController that there is media playing that can be + // paused. + { + MediaSessionInfoPtr session_info(MediaSessionInfo::New()); + session_info->playback_state = MediaPlaybackState::kPlaying; + SetMediaSessionInfo(std::move(session_info)); + SetSupportedMediaSessionActions({MediaSessionAction::kPause}); + } + + // There should not have been any calls to the media controller yet. + EXPECT_EQ(0, media_controller()->suspend_count()); + EXPECT_EQ(0, media_controller()->resume_count()); + + // Press the play/pause media key. + media_keys_listener()->SimulateAccelerator( + ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, 0)); + FlushForTesting(); + + // The media controller should have been told to pause. + EXPECT_EQ(1, media_controller()->suspend_count()); + EXPECT_EQ(0, media_controller()->resume_count()); + + // Tell the HardwareKeyMediaController that the media is now paused and can be + // played. + { + MediaSessionInfoPtr session_info(MediaSessionInfo::New()); + session_info->playback_state = MediaPlaybackState::kPaused; + SetMediaSessionInfo(std::move(session_info)); + SetSupportedMediaSessionActions({MediaSessionAction::kPlay}); + } + + // Press play/pause. + media_keys_listener()->SimulateAccelerator( + ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, 0)); + FlushForTesting(); + + // The media controller should have been told to play. + EXPECT_EQ(1, media_controller()->suspend_count()); + EXPECT_EQ(1, media_controller()->resume_count()); +} + +IN_PROC_BROWSER_TEST_F(MediaKeysListenerManagerImplTest, + ListensToTheCorrectMediaKeys) { + // Before any media session starts, we should not be listening for key input. + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PLAY_PAUSE)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_STOP)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_NEXT_TRACK)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PREV_TRACK)); + + // Tell the HardwareKeyMediaController that there is media playing that can be + // paused. + { + MediaSessionInfoPtr session_info(MediaSessionInfo::New()); + session_info->playback_state = MediaPlaybackState::kPlaying; + SetMediaSessionInfo(std::move(session_info)); + SetSupportedMediaSessionActions({MediaSessionAction::kPause}); + } + + // We should now be listening for the play/pause key, but no others. + EXPECT_TRUE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PLAY_PAUSE)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_STOP)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_NEXT_TRACK)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PREV_TRACK)); + + // Update the list of supported actions. + SetSupportedMediaSessionActions({MediaSessionAction::kPause, + MediaSessionAction::kStop, + MediaSessionAction::kNextTrack}); + + // We should now be listening for the correct media keys. + EXPECT_TRUE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PLAY_PAUSE)); + EXPECT_TRUE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_STOP)); + EXPECT_TRUE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_NEXT_TRACK)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PREV_TRACK)); + + // Update the list of supported actions. + SetSupportedMediaSessionActions({MediaSessionAction::kStop}); + + // We should now be listening for the correct media keys. + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PLAY_PAUSE)); + EXPECT_TRUE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_STOP)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_NEXT_TRACK)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PREV_TRACK)); + + // Disable media key handling for the HardwareKeyMediaController. + media_keys_listener_manager()->DisableInternalMediaKeyHandling(); + + // We should no longer be listening for key input. + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PLAY_PAUSE)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_STOP)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_NEXT_TRACK)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PREV_TRACK)); + + // Re-enable media key handling for the HardwareKeyMediaController. + media_keys_listener_manager()->EnableInternalMediaKeyHandling(); + + // We should now be listening for the correct media keys. + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PLAY_PAUSE)); + EXPECT_TRUE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_STOP)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_NEXT_TRACK)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PREV_TRACK)); + + // Have a different delegate besides the HardwareKeyMediaController request + // keys. + MockMediaKeysListenerDelegate delegate; + media_keys_listener_manager()->StartWatchingMediaKey( + ui::VKEY_MEDIA_PLAY_PAUSE, &delegate); + + // We should now be listening for only the new delegate's keys. + EXPECT_TRUE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PLAY_PAUSE)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_STOP)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_NEXT_TRACK)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PREV_TRACK)); + + // Unregister the delegate. + media_keys_listener_manager()->StopWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE, + &delegate); + + // We should now be listening for the HardwareKeyMediaController's keys. + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PLAY_PAUSE)); + EXPECT_TRUE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_STOP)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_NEXT_TRACK)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PREV_TRACK)); + + // Tell the HardwareKeyMediaController there is no longer an active session. + SetMediaSessionInfo(nullptr); + SetSupportedMediaSessionActions({}); + + // We should no longer be listening for key input. + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PLAY_PAUSE)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_STOP)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_NEXT_TRACK)); + EXPECT_FALSE(media_keys_listener()->IsWatching(ui::VKEY_MEDIA_PREV_TRACK)); +} + +IN_PROC_BROWSER_TEST_F(MediaKeysListenerManagerImplTest, + OtherDelegatesPreemptHardwareKeyMediaController) { + // Tell the HardwareKeyMediaController that there is media playing that can be + // paused or sent to the next track. + { + MediaSessionInfoPtr session_info(MediaSessionInfo::New()); + session_info->playback_state = MediaPlaybackState::kPlaying; + SetMediaSessionInfo(std::move(session_info)); + SetSupportedMediaSessionActions({MediaSessionAction::kPause}); + } + + // Set up a delegate that listens to Play/Pause. + MockMediaKeysListenerDelegate delegate; + media_keys_listener_manager()->StartWatchingMediaKey( + ui::VKEY_MEDIA_PLAY_PAUSE, &delegate); + + // There should not have been any calls to the media controller or the + // delegate yet. + EXPECT_EQ(0, media_controller()->suspend_count()); + EXPECT_EQ(0, media_controller()->next_track_count()); + delegate.ExpectReceivedKeysCount(0); + + // Press play/pause. + media_keys_listener()->SimulateAccelerator( + ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, 0)); + FlushForTesting(); + + // The media controller should not have been told to pause. + EXPECT_EQ(0, media_controller()->suspend_count()); + EXPECT_EQ(0, media_controller()->next_track_count()); + + // The delegate should have received the event instead. + delegate.ExpectReceivedKeysCount(1); + delegate.ExpectReceivedKey(/*index=*/0, ui::VKEY_MEDIA_PLAY_PAUSE); + + // Unregister the delegate. + media_keys_listener_manager()->StopWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE, + &delegate); + + // Press play/pause. + media_keys_listener()->SimulateAccelerator( + ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, 0)); + FlushForTesting(); + + // The media controller should have been told to pause. + EXPECT_EQ(1, media_controller()->suspend_count()); + + // The delegate should not have been told to pause, since it was unregistered. + delegate.ExpectReceivedKeysCount(1); +} + +} // namespace content
diff --git a/content/browser/network_service_client.cc b/content/browser/network_service_client.cc index b5cf4548..6fd435a 100644 --- a/content/browser/network_service_client.cc +++ b/content/browser/network_service_client.cc
@@ -27,11 +27,13 @@ #include "content/public/common/network_service_util.h" #include "content/public/common/resource_type.h" #include "mojo/public/cpp/bindings/strong_binding.h" +#include "net/http/http_auth_preferences.h" #include "net/ssl/client_cert_store.h" #include "services/network/public/mojom/network_context.mojom.h" #if defined(OS_ANDROID) #include "base/android/content_uri_utils.h" +#include "net/android/http_auth_negotiate_android.h" #endif namespace content { @@ -412,6 +414,17 @@ cert_info); // deletes self } +#if defined(OS_ANDROID) +void FinishGenerateNegotiateAuthToken( + std::unique_ptr<net::android::HttpAuthNegotiateAndroid> auth_negotiate, + std::unique_ptr<std::string> auth_token, + std::unique_ptr<net::HttpAuthPreferences> prefs, + NetworkServiceClient::OnGenerateHttpNegotiateAuthTokenCallback callback, + int result) { + std::move(callback).Run(result, *auth_token); +} +#endif + } // namespace NetworkServiceClient::NetworkServiceClient( @@ -615,4 +628,33 @@ network_traffic_annotation_id_hash, recv_bytes, sent_bytes); } +#if defined(OS_ANDROID) +void NetworkServiceClient::OnGenerateHttpNegotiateAuthToken( + const std::string& server_auth_token, + bool can_delegate, + const std::string& auth_negotiate_android_account_type, + const std::string& spn, + OnGenerateHttpNegotiateAuthTokenCallback callback) { + // The callback takes ownership of these unique_ptrs and destroys them when + // run. + auto prefs = std::make_unique<net::HttpAuthPreferences>(); + prefs->set_auth_android_negotiate_account_type( + auth_negotiate_android_account_type); + + auto auth_negotiate = + std::make_unique<net::android::HttpAuthNegotiateAndroid>(prefs.get()); + net::android::HttpAuthNegotiateAndroid* auth_negotiate_raw = + auth_negotiate.get(); + auth_negotiate->set_server_auth_token(server_auth_token); + auth_negotiate->set_can_delegate(can_delegate); + + auto auth_token = std::make_unique<std::string>(); + auth_negotiate_raw->GenerateAuthToken( + nullptr, spn, std::string(), auth_token.get(), + base::BindOnce(&FinishGenerateNegotiateAuthToken, + std::move(auth_negotiate), std::move(auth_token), + std::move(prefs), std::move(callback))); +} +#endif + } // namespace content
diff --git a/content/browser/network_service_client.h b/content/browser/network_service_client.h index 044aedf..2962736d 100644 --- a/content/browser/network_service_client.h +++ b/content/browser/network_service_client.h
@@ -86,6 +86,14 @@ void OnDataUseUpdate(int32_t network_traffic_annotation_id_hash, int64_t recv_bytes, int64_t sent_bytes) override; +#if defined(OS_ANDROID) + void OnGenerateHttpNegotiateAuthToken( + const std::string& server_auth_token, + bool can_delegate, + const std::string& auth_negotiate_android_account_type, + const std::string& spn, + OnGenerateHttpNegotiateAuthTokenCallback callback) override; +#endif // net::CertDatabase::Observer implementation: void OnCertDBChanged() override;
diff --git a/content/browser/portal/portal_browsertest.cc b/content/browser/portal/portal_browsertest.cc index 141d9555c..7d35f324 100644 --- a/content/browser/portal/portal_browsertest.cc +++ b/content/browser/portal/portal_browsertest.cc
@@ -11,6 +11,7 @@ #include "content/browser/frame_host/render_frame_proxy_host.h" #include "content/browser/portal/portal.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/common/frame.mojom-test-utils.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" @@ -23,6 +24,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/mojom/portal/portal.mojom-test-utils.h" #include "third_party/blink/public/mojom/portal/portal.mojom.h" #include "url/url_constants.h"
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index e552c2cc..9cd93e5 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -135,6 +135,8 @@ uint32_t frame_token, const gfx::PresentationFeedback& feedback) override {} void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override {} + void DidGenerateLocalSurfaceIdAllocation( + const viz::LocalSurfaceIdAllocation& allocation) override {} // LayerTreeHostSingleThreadClient implementation. void DidSubmitCompositorFrame() override;
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc index ecc0e45..c1c993d 100644 --- a/content/browser/renderer_host/delegated_frame_host.cc +++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -476,17 +476,6 @@ //////////////////////////////////////////////////////////////////////////////// // DelegatedFrameHost, ui::CompositorObserver implementation: -void DelegatedFrameHost::OnCompositingDidCommit(ui::Compositor* compositor) { -} - -void DelegatedFrameHost::OnCompositingStarted(ui::Compositor* compositor, - base::TimeTicks start_time) {} - -void DelegatedFrameHost::OnCompositingEnded(ui::Compositor* compositor) {} - -void DelegatedFrameHost::OnCompositingChildResizing( - ui::Compositor* compositor) {} - void DelegatedFrameHost::OnCompositingShuttingDown(ui::Compositor* compositor) { DCHECK_EQ(compositor, compositor_); DetachFromCompositor();
diff --git a/content/browser/renderer_host/delegated_frame_host.h b/content/browser/renderer_host/delegated_frame_host.h index e22ddf5..050fc843 100644 --- a/content/browser/renderer_host/delegated_frame_host.h +++ b/content/browser/renderer_host/delegated_frame_host.h
@@ -76,11 +76,6 @@ ~DelegatedFrameHost() override; // ui::CompositorObserver implementation. - void OnCompositingDidCommit(ui::Compositor* compositor) override; - void OnCompositingStarted(ui::Compositor* compositor, - base::TimeTicks start_time) override; - void OnCompositingEnded(ui::Compositor* compositor) override; - void OnCompositingChildResizing(ui::Compositor* compositor) override; void OnCompositingShuttingDown(ui::Compositor* compositor) override; // ui::ContextFactoryObserver implementation.
diff --git a/content/browser/renderer_host/media/video_capture_browsertest.cc b/content/browser/renderer_host/media/video_capture_browsertest.cc index 7b46af2..362dd81 100644 --- a/content/browser/renderer_host/media/video_capture_browsertest.cc +++ b/content/browser/renderer_host/media/video_capture_browsertest.cc
@@ -253,12 +253,6 @@ #endif IN_PROC_BROWSER_TEST_P(VideoCaptureBrowserTest, MAYBE_ReceiveFramesFromFakeCaptureDevice) { -#if defined(OS_ANDROID) - // TODO(chfremer): This test case is flaky on Android. Find out cause of - // flakiness and then re-enable. See https://crbug.com/709039. - if (params_.exercise_accelerated_jpeg_decoding) - return; -#endif // Only fake device with index 2 delivers MJPEG. if (params_.exercise_accelerated_jpeg_decoding && params_.device_index_to_use != 2) {
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 7b7389dc..c6bbddf 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -532,6 +532,8 @@ (!command_line.HasSwitch(switches::kDisableSmoothScrolling) && gfx::Animation::ScrollAnimationsEnabledBySystem()); + prefs.prefers_reduced_motion = gfx::Animation::PrefersReducedMotion(); + if (ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( GetProcess()->GetID())) { prefs.loads_images_automatically = true;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index 780842d..f11808b 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -2858,25 +2858,18 @@ // Cause a conflicting viz::LocalSurfaceId allocation aura_test_helper_->test_screen()->SetDeviceScaleFactor(2.0f); - viz::LocalSurfaceIdAllocation local_surface_id_allocation3( - view_->GetLocalSurfaceIdAllocation()); - EXPECT_NE(local_surface_id_allocation1, local_surface_id_allocation3); - - viz::LocalSurfaceIdAllocation local_surface_id_allocation4( - view_->GetLocalSurfaceIdAllocation()); - EXPECT_NE(local_surface_id_allocation1, local_surface_id_allocation4); - EXPECT_NE(local_surface_id_allocation2, local_surface_id_allocation4); viz::LocalSurfaceIdAllocation merged_local_surface_id_allocation( - viz::LocalSurfaceId( - local_surface_id_allocation2.local_surface_id() - .parent_sequence_number() + - 1, - local_surface_id_allocation2.local_surface_id() - .child_sequence_number(), - local_surface_id_allocation2.local_surface_id().embed_token()), - base::TimeTicks::Now()); - EXPECT_EQ(local_surface_id_allocation4.local_surface_id(), - merged_local_surface_id_allocation.local_surface_id()); + view_->GetLocalSurfaceIdAllocation()); + EXPECT_NE(local_surface_id_allocation1, merged_local_surface_id_allocation); + EXPECT_NE(local_surface_id_allocation2, merged_local_surface_id_allocation); + EXPECT_GT( + merged_local_surface_id_allocation.local_surface_id() + .parent_sequence_number(), + local_surface_id_allocation2.local_surface_id().parent_sequence_number()); + EXPECT_EQ( + merged_local_surface_id_allocation.local_surface_id() + .child_sequence_number(), + local_surface_id_allocation2.local_surface_id().child_sequence_number()); } // Checks that WidgetInputHandler::CursorVisibilityChange IPC messages are
diff --git a/content/browser/renderer_host/render_widget_host_view_cocoa.mm b/content/browser/renderer_host/render_widget_host_view_cocoa.mm index 57a608c..673c7dac 100644 --- a/content/browser/renderer_host/render_widget_host_view_cocoa.mm +++ b/content/browser/renderer_host/render_widget_host_view_cocoa.mm
@@ -1381,6 +1381,11 @@ return client_; } +// TODO(crbug.com/921109): Migrate from the NSObject accessibility API to the +// NSAccessibility API, then remove this suppression. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + - (NSArray*)accessibilityArrayAttributeValues:(NSString*)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount { @@ -1451,6 +1456,8 @@ return clientHelper_->GetFocusedBrowserAccessibilityElement(); } +#pragma clang diagnostic pop + // Below is our NSTextInputClient implementation. // // When WebHTMLView receives a NSKeyDown event, WebHTMLView calls the following
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc index 8d01f4e..04c35ffe 100644 --- a/content/browser/security_exploit_browsertest.cc +++ b/content/browser/security_exploit_browsertest.cc
@@ -65,6 +65,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/mojom/blob/blob_url_store.mojom-test-utils.h" #include "third_party/blink/public/web/web_triggering_event_info.h" using IPC::IpcSecurityTestUtil;
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc index fccb454..9462ede7 100644 --- a/content/browser/service_manager/service_manager_context.cc +++ b/content/browser/service_manager/service_manager_context.cc
@@ -13,7 +13,6 @@ #include "base/command_line.h" #include "base/deferred_sequenced_task_runner.h" #include "base/feature_list.h" -#include "base/json/json_reader.h" #include "base/lazy_instance.h" #include "base/macros.h" #include "base/memory/scoped_refptr.h" @@ -35,7 +34,12 @@ #include "content/browser/utility_process_host_client.h" #include "content/browser/wake_lock/wake_lock_context_host.h" #include "content/common/service_manager/service_manager_connection_impl.h" -#include "content/grit/content_resources.h" +#include "content/public/app/content_browser_manifest.h" +#include "content/public/app/content_gpu_manifest.h" +#include "content/public/app/content_packaged_services_manifest.h" +#include "content/public/app/content_plugin_manifest.h" +#include "content/public/app/content_renderer_manifest.h" +#include "content/public/app/content_utility_manifest.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_data.h" @@ -81,7 +85,6 @@ #include "services/service_manager/sandbox/sandbox_type.h" #include "services/service_manager/service_manager.h" #include "services/shape_detection/public/mojom/constants.mojom.h" -#include "services/tracing/manifest.h" #include "services/tracing/public/mojom/constants.mojom.h" #include "services/tracing/tracing_service.h" #include "services/video_capture/public/mojom/constants.mojom.h" @@ -216,36 +219,6 @@ std::move(pid_receiver)); } -service_manager::Manifest LoadServiceManifest(base::StringPiece service_name, - int resource_id) { - std::string contents = - GetContentClient() - ->GetDataResource(resource_id, ui::ScaleFactor::SCALE_FACTOR_NONE) - .as_string(); - DCHECK(!contents.empty()); - - service_manager::Manifest manifest = - service_manager::Manifest::FromValueDeprecated( - base::JSONReader::Read(contents)); - base::Optional<service_manager::Manifest> overlay = - GetContentClient()->browser()->GetServiceManifestOverlay(service_name); - if (overlay) - manifest.Amend(*overlay); - - if (service_name == mojom::kPackagedServicesServiceName) - manifest.packaged_services.push_back(tracing::GetManifest()); - - if (!manifest.preloaded_files.empty()) { - std::map<std::string, base::FilePath> preloaded_files_map; - for (const auto& info : manifest.preloaded_files) - preloaded_files_map.emplace(info.key, info.path); - ChildProcessLauncher::SetRegisteredFilesForService( - service_name.as_string(), std::move(preloaded_files_map)); - } - - return manifest; -} - class NullServiceProcessLauncherFactory : public service_manager::ServiceProcessLauncherFactory { public: @@ -554,29 +527,28 @@ packaged_services_request = service_manager::GetServiceRequestFromCommandLine(&invitation); } else { - static const struct ManifestInfo { - const char* name; - int resource_id; - } kManifestInfo[] = { - {mojom::kBrowserServiceName, IDR_MOJO_CONTENT_BROWSER_MANIFEST}, - {mojom::kGpuServiceName, IDR_MOJO_CONTENT_GPU_MANIFEST}, - {mojom::kPackagedServicesServiceName, - IDR_MOJO_CONTENT_PACKAGED_SERVICES_MANIFEST}, - {mojom::kPluginServiceName, IDR_MOJO_CONTENT_PLUGIN_MANIFEST}, - {mojom::kRendererServiceName, IDR_MOJO_CONTENT_RENDERER_MANIFEST}, - {mojom::kUtilityServiceName, IDR_MOJO_CONTENT_UTILITY_MANIFEST}, + std::vector<service_manager::Manifest> manifests{ + GetContentBrowserManifest(), GetContentGpuManifest(), + GetContentPackagedServicesManifest(), GetContentPluginManifest(), + GetContentRendererManifest(), GetContentUtilityManifest(), }; - std::vector<service_manager::Manifest> manifests; - for (const auto& manifest_info : kManifestInfo) { - manifests.push_back( - LoadServiceManifest(manifest_info.name, manifest_info.resource_id)); + for (auto& manifest : manifests) { + base::Optional<service_manager::Manifest> overlay = + GetContentClient()->browser()->GetServiceManifestOverlay( + manifest.service_name); + if (overlay) + manifest.Amend(*overlay); + if (!manifest.preloaded_files.empty()) { + std::map<std::string, base::FilePath> preloaded_files_map; + for (const auto& info : manifest.preloaded_files) + preloaded_files_map.emplace(info.key, info.path); + ChildProcessLauncher::SetRegisteredFilesForService( + manifest.service_name, std::move(preloaded_files_map)); + } } - for (const auto& info : + for (auto& extra_manifest : GetContentClient()->browser()->GetExtraServiceManifests()) { - if (info.resource_id != -1) - manifests.push_back(LoadServiceManifest(info.name, info.resource_id)); - else - manifests.push_back(info.manifest); + manifests.emplace_back(std::move(extra_manifest)); } in_process_context_ = new InProcessServiceManagerContext(service_manager_thread_task_runner_);
diff --git a/content/browser/service_worker/service_worker_client_utils.cc b/content/browser/service_worker/service_worker_client_utils.cc index 00728df..0589a70 100644 --- a/content/browser/service_worker/service_worker_client_utils.cc +++ b/content/browser/service_worker/service_worker_client_utils.cc
@@ -128,8 +128,6 @@ // for a frame that is actually being navigated and isn't exactly what we are // expecting. PageVisibilityState visibility = render_frame_host->GetVisibilityState(); - // Service workers do no prerender, this would be an invalid visibility state. - DCHECK_NE(visibility, PageVisibilityState::kPrerender); bool page_hidden = visibility != PageVisibilityState::kVisible; return blink::mojom::ServiceWorkerClientInfo::New( render_frame_host->GetLastCommittedURL(),
diff --git a/content/browser/service_worker/service_worker_installed_script_loader.h b/content/browser/service_worker/service_worker_installed_script_loader.h index 863c90e..c88bf5e 100644 --- a/content/browser/service_worker/service_worker_installed_script_loader.h +++ b/content/browser/service_worker/service_worker_installed_script_loader.h
@@ -12,6 +12,7 @@ #include "mojo/public/cpp/system/data_pipe.h" #include "mojo/public/cpp/system/data_pipe_drainer.h" #include "services/network/public/mojom/url_loader.mojom.h" +#include "services/network/public/mojom/url_loader_factory.mojom.h" namespace content {
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc index 61c6f13..3e8bc1c8 100644 --- a/content/browser/site_per_process_hit_test_browsertest.cc +++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -26,6 +26,7 @@ #include "content/browser/renderer_host/render_widget_host_input_event_router.h" #include "content/browser/renderer_host/render_widget_host_view_child_frame.h" #include "content/common/frame_messages.h" +#include "content/common/input/input_handler.mojom-test-utils.h" #include "content/common/view_messages.h" #include "content/common/widget_messages.h" #include "content/public/browser/browser_task_traits.h"
diff --git a/content/browser/streams/stream.cc b/content/browser/streams/stream.cc index a0dcc1c..1ac6ef6 100644 --- a/content/browser/streams/stream.cc +++ b/content/browser/streams/stream.cc
@@ -20,7 +20,7 @@ namespace { // Start throttling the connection at about 1MB. const size_t kDeferSizeThreshold = 40 * 32768; -} +} // namespace namespace content { @@ -61,12 +61,12 @@ } void Stream::RemoveReadObserver(StreamReadObserver* observer) { - DCHECK(observer == read_observer_); + DCHECK_EQ(observer, read_observer_); read_observer_ = nullptr; } void Stream::RemoveWriteObserver(StreamWriteObserver* observer) { - DCHECK(observer == write_observer_); + DCHECK_EQ(observer, write_observer_); write_observer_ = nullptr; } @@ -114,16 +114,6 @@ can_add_data_ = writer_->Write(buffer, size); } -void Stream::AddData(const char* data, size_t size) { - if (!writer_.get()) - return; - - scoped_refptr<net::IOBuffer> io_buffer = - base::MakeRefCounted<net::IOBuffer>(size); - memcpy(io_buffer->data(), data, size); - AddData(io_buffer, size); -} - void Stream::Flush() { if (!writer_.get()) return;
diff --git a/content/browser/streams/stream.h b/content/browser/streams/stream.h index c46963b..1c6309e 100644 --- a/content/browser/streams/stream.h +++ b/content/browser/streams/stream.h
@@ -7,6 +7,8 @@ #include <stddef.h> +#include <memory> + #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -75,9 +77,6 @@ // Adds the data in |buffer| to the stream. Takes ownership of |buffer|. void AddData(scoped_refptr<net::IOBuffer> buffer, size_t size); - // Adds data of |size| at |data| to the stream. This method creates a copy - // of the data, and then passes it to |writer_|. - void AddData(const char* data, size_t size); // Flushes contents buffered in the stream to the corresponding reader. void Flush(); @@ -123,7 +122,7 @@ bool can_add_data_; - GURL url_; + const GURL url_; // Buffer for storing data read from |reader_| but not yet read out from this // Stream by ReadRawData() method. @@ -149,6 +148,7 @@ std::unique_ptr<StreamMetadata> metadata_; base::WeakPtrFactory<Stream> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(Stream); };
diff --git a/content/browser/web_contents/web_contents_ns_view_bridge.mm b/content/browser/web_contents/web_contents_ns_view_bridge.mm index d959209..44204e22b 100644 --- a/content/browser/web_contents/web_contents_ns_view_bridge.mm +++ b/content/browser/web_contents/web_contents_ns_view_bridge.mm
@@ -14,6 +14,7 @@ : client_(std::move(client)) { cocoa_view_.reset( [[WebContentsViewCocoa alloc] initWithWebContentsViewMac:nullptr]); + [cocoa_view_ setClient:client_.get()]; view_id_ = std::make_unique<ui::ScopedNSViewIdMapping>(view_id, cocoa_view_.get()); }
diff --git a/content/browser/web_contents/web_contents_view_cocoa.h b/content/browser/web_contents/web_contents_view_cocoa.h index a0103f4e..5b44f03 100644 --- a/content/browser/web_contents/web_contents_view_cocoa.h +++ b/content/browser/web_contents/web_contents_view_cocoa.h
@@ -35,6 +35,9 @@ BOOL mouseDownCanMoveWindow_; } +// The mojo interface through which to communicate with the browser process. +@property(nonatomic, assign) content::mojom::WebContentsNSViewClient* client; + - (void)setMouseDownCanMoveWindow:(BOOL)canMove; // Sets |accessibilityParent| as the object returned when the
diff --git a/content/browser/web_contents/web_contents_view_cocoa.mm b/content/browser/web_contents/web_contents_view_cocoa.mm index 3791788..c83ae296 100644 --- a/content/browser/web_contents/web_contents_view_cocoa.mm +++ b/content/browser/web_contents/web_contents_view_cocoa.mm
@@ -28,11 +28,12 @@ @implementation WebContentsViewCocoa +@synthesize client = client_; + - (id)initWithWebContentsViewMac:(WebContentsViewMac*)w { self = [super initWithFrame:NSZeroRect]; if (self != nil) { webContentsView_ = w; - client_ = w; [self registerDragTypes]; [[NSNotificationCenter defaultCenter]
diff --git a/content/browser/web_contents/web_contents_view_mac.h b/content/browser/web_contents/web_contents_view_mac.h index 18fbea9..c0c5530 100644 --- a/content/browser/web_contents/web_contents_view_mac.h +++ b/content/browser/web_contents/web_contents_view_mac.h
@@ -112,11 +112,11 @@ void OnMenuClosed() override; // ViewsHostableView: - void OnViewsHostableAttached(ViewsHostableView::Host* host) override; - void OnViewsHostableDetached() override; - void OnViewsHostableShow(const gfx::Rect& bounds_in_window) override; - void OnViewsHostableHide() override; - void OnViewsHostableMakeFirstResponder() override; + void ViewsHostableAttach(ViewsHostableView::Host* host) override; + void ViewsHostableDetach() override; + void ViewsHostableSetBounds(const gfx::Rect& bounds_in_window) override; + void ViewsHostableSetVisible(bool visible) override; + void ViewsHostableMakeFirstResponder() override; // A helper method for closing the tab in the // CloseTabAfterEventTracking() implementation.
diff --git a/content/browser/web_contents/web_contents_view_mac.mm b/content/browser/web_contents/web_contents_view_mac.mm index 64a33bc..d4f6a36d 100644 --- a/content/browser/web_contents/web_contents_view_mac.mm +++ b/content/browser/web_contents/web_contents_view_mac.mm
@@ -305,6 +305,7 @@ const gfx::Size& initial_size, gfx::NativeView context) { ns_view_bridge_local_ = std::make_unique<WebContentsNSViewBridge>(ns_view_id_, this); + [cocoa_view() setClient:this]; drag_dest_.reset([[WebDragDest alloc] initWithWebContentsImpl:web_contents_]); if (delegate_) @@ -475,11 +476,6 @@ break; } - // TODO(ccameron): Communicate window visibility and occlusion from the remote - // process (for now, always treat remote windows as visible). - if (ns_view_bridge_remote_) - visibility = Visibility::VISIBLE; - web_contents_->UpdateWebContentsVisibility(visibility); } @@ -535,11 +531,10 @@ //////////////////////////////////////////////////////////////////////////////// // WebContentsViewMac, ViewsHostableView: -void WebContentsViewMac::OnViewsHostableAttached( - ViewsHostableView::Host* host) { +void WebContentsViewMac::ViewsHostableAttach(ViewsHostableView::Host* host) { views_host_ = host; - [cocoa_view() - setAccessibilityParentElement:views_host_->GetAccessibilityElement()]; + std::vector<uint8_t> token = ui::RemoteAccessibility::GetTokenForLocalElement( + views_host_->GetAccessibilityElement()); // Create an NSView in the target process, if one exists. uint64_t factory_host_id = views_host_->GetViewsFactoryHostId(); @@ -554,17 +549,16 @@ factory_host->GetFactory()->CreateWebContentsNSViewBridge( ns_view_id_, client.PassInterface(), std::move(bridge_request)); - std::vector<uint8_t> token = - ui::RemoteAccessibility::GetTokenForLocalElement( - views_host_->GetAccessibilityElement()); ns_view_bridge_remote_->SetParentNSView(views_host_->GetNSViewId(), token); - // TODO(ccameron): Communicate window visibility and occlusion from the - // remote process (for now, always treat remote windows as visible). - OnWindowVisibilityChanged(mojom::Visibility::kVisible); + // Because this view is being displayed from a remote process, reset the + // in-process NSView's client pointer, so that the in-process NSView will + // not call back into |this|. + [cocoa_view() setClient:nullptr]; } else if (factory_host_id != NSViewBridgeFactoryHost::kLocalDirectHostId) { LOG(ERROR) << "Failed to look up NSViewBridgeFactoryHost!"; } + ns_view_bridge_local_->SetParentNSView(views_host_->GetNSViewId(), token); for (auto* rwhv_mac : GetChildViews()) { rwhv_mac->MigrateNSViewBridge(factory_host, ns_view_id_); @@ -572,17 +566,8 @@ } } -void WebContentsViewMac::OnViewsHostableDetached() { +void WebContentsViewMac::ViewsHostableDetach() { DCHECK(views_host_); - views_host_ = nullptr; - - for (auto* rwhv_mac : GetChildViews()) { - rwhv_mac->MigrateNSViewBridge(nullptr, 0); - rwhv_mac->SetParentUiLayer(nullptr); - } - - [cocoa_view() setAccessibilityParentElement:nil]; - // Disconnect from the remote bridge, if it exists. This will have the effect // of destroying the associated bridge instance with its NSView. if (ns_view_bridge_remote_) { @@ -590,25 +575,40 @@ ns_view_bridge_remote_->ResetParentNSView(); ns_view_client_binding_.Close(); ns_view_bridge_remote_.reset(); + // Permit the in-process NSView to call back into |this| again. + [cocoa_view() setClient:this]; + } + ns_view_bridge_local_->SetVisible(false); + ns_view_bridge_local_->ResetParentNSView(); + views_host_ = nullptr; + + for (auto* rwhv_mac : GetChildViews()) { + rwhv_mac->MigrateNSViewBridge(nullptr, 0); + rwhv_mac->SetParentUiLayer(nullptr); } } -void WebContentsViewMac::OnViewsHostableShow( +void WebContentsViewMac::ViewsHostableSetBounds( const gfx::Rect& bounds_in_window) { - if (ns_view_bridge_remote_) { - ns_view_bridge_remote_->SetBounds(bounds_in_window); - ns_view_bridge_remote_->SetVisible(true); - } -} - -void WebContentsViewMac::OnViewsHostableHide() { + // Update both the in-process and out-of-process NSViews' bounds. + ns_view_bridge_local_->SetBounds(bounds_in_window); if (ns_view_bridge_remote_) - ns_view_bridge_remote_->SetVisible(false); + ns_view_bridge_remote_->SetBounds(bounds_in_window); } -void WebContentsViewMac::OnViewsHostableMakeFirstResponder() { +void WebContentsViewMac::ViewsHostableSetVisible(bool visible) { + // Update both the in-process and out-of-process NSViews' visibility. + ns_view_bridge_local_->SetVisible(visible); + if (ns_view_bridge_remote_) + ns_view_bridge_remote_->SetVisible(visible); +} + +void WebContentsViewMac::ViewsHostableMakeFirstResponder() { + // Only make the true NSView become the first responder. if (ns_view_bridge_remote_) ns_view_bridge_remote_->MakeFirstResponder(); + else + ns_view_bridge_local_->MakeFirstResponder(); } } // namespace content
diff --git a/content/browser/web_contents/web_contents_view_mac_unittest.mm b/content/browser/web_contents/web_contents_view_mac_unittest.mm index 17786bc..cf322960 100644 --- a/content/browser/web_contents/web_contents_view_mac_unittest.mm +++ b/content/browser/web_contents/web_contents_view_mac_unittest.mm
@@ -39,6 +39,10 @@ [view draggingSourceOperationMaskForLocal:NO]); } +// This test uses deprecated NSObject accessibility APIs - see +// https://crbug.com/921109. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" TEST_F(WebContentsViewCocoaTest, AccessibilityParentTest) { // The designated initializer is private but init should be fine in this case. base::scoped_nsobject<WebContentsViewCocoa> view( @@ -60,6 +64,7 @@ EXPECT_NSEQ([view accessibilityAttributeValue:NSAccessibilityParentAttribute], parent_view); } +#pragma clang diagnostic pop namespace {
diff --git a/content/browser/web_package/mock_signed_exchange_handler.cc b/content/browser/web_package/mock_signed_exchange_handler.cc index 808e695e..8c1fc89f 100644 --- a/content/browser/web_package/mock_signed_exchange_handler.cc +++ b/content/browser/web_package/mock_signed_exchange_handler.cc
@@ -33,7 +33,7 @@ } base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(headers_callback), result, error, - request_url, "GET", head, std::move(body))); + request_url, head, std::move(body))); } MockSignedExchangeHandler::~MockSignedExchangeHandler() {}
diff --git a/content/browser/web_package/signed_exchange_certificate_chain.cc b/content/browser/web_package/signed_exchange_certificate_chain.cc index 4eb95db..8b667cb 100644 --- a/content/browser/web_package/signed_exchange_certificate_chain.cc +++ b/content/browser/web_package/signed_exchange_certificate_chain.cc
@@ -18,12 +18,9 @@ namespace { // https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#cert-chain-format -std::unique_ptr<SignedExchangeCertificateChain> ParseB2( +std::unique_ptr<SignedExchangeCertificateChain> ParseCertChain( base::span<const uint8_t> message, SignedExchangeDevToolsProxy* devtools_proxy) { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"), - "SignedExchangeCertificateChain::ParseB2"); - cbor::Reader::DecoderError error; base::Optional<cbor::Value> value = cbor::Reader::Read(message, &error); if (!value.has_value()) { @@ -158,7 +155,9 @@ SignedExchangeCertificateChain::Parse( base::span<const uint8_t> cert_response_body, SignedExchangeDevToolsProxy* devtools_proxy) { - return ParseB2(cert_response_body, devtools_proxy); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"), + "SignedExchangeCertificateChain::Parse"); + return ParseCertChain(cert_response_body, devtools_proxy); } SignedExchangeCertificateChain::SignedExchangeCertificateChain(
diff --git a/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc b/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc index 825630d..7e5a3df 100644 --- a/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc +++ b/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc
@@ -27,13 +27,13 @@ } // namespace -TEST(SignedExchangeCertificateParseB2Test, Empty) { +TEST(SignedExchangeCertificateParseTest, Empty) { auto parsed = SignedExchangeCertificateChain::Parse( base::span<const uint8_t>(), nullptr); EXPECT_FALSE(parsed); } -TEST(SignedExchangeCertificateParseB2Test, EmptyChain) { +TEST(SignedExchangeCertificateParseTest, EmptyChain) { cbor::Value::ArrayValue cbor_array; cbor_array.push_back(cbor::Value(u8"\U0001F4DC\u26D3")); @@ -45,7 +45,7 @@ EXPECT_FALSE(parsed); } -TEST(SignedExchangeCertificateParseB2Test, MissingCert) { +TEST(SignedExchangeCertificateParseTest, MissingCert) { cbor::Value::MapValue cbor_map; cbor_map[cbor::Value("sct")] = CBORByteString("SCT"); cbor_map[cbor::Value("ocsp")] = CBORByteString("OCSP"); @@ -62,7 +62,7 @@ EXPECT_FALSE(parsed); } -TEST(SignedExchangeCertificateParseB2Test, OneCert) { +TEST(SignedExchangeCertificateParseTest, OneCert) { net::CertificateList certs; ASSERT_TRUE( net::LoadCertificateFiles({"subjectAltName_sanity_check.pem"}, &certs)); @@ -92,7 +92,7 @@ EXPECT_EQ(parsed->sct(), base::make_optional<std::string>("SCT")); } -TEST(SignedExchangeCertificateParseB2Test, MissingOCSPInFirstCert) { +TEST(SignedExchangeCertificateParseTest, MissingOCSPInFirstCert) { net::CertificateList certs; ASSERT_TRUE( net::LoadCertificateFiles({"subjectAltName_sanity_check.pem"}, &certs)); @@ -116,7 +116,7 @@ EXPECT_FALSE(parsed); } -TEST(SignedExchangeCertificateParseB2Test, TwoCerts) { +TEST(SignedExchangeCertificateParseTest, TwoCerts) { net::CertificateList certs; ASSERT_TRUE(net::LoadCertificateFiles( {"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs)); @@ -154,7 +154,7 @@ EXPECT_EQ(parsed->sct(), base::make_optional<std::string>("SCT")); } -TEST(SignedExchangeCertificateParseB2Test, HavingOCSPInSecondCert) { +TEST(SignedExchangeCertificateParseTest, HavingOCSPInSecondCert) { net::CertificateList certs; ASSERT_TRUE(net::LoadCertificateFiles( {"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs)); @@ -186,7 +186,7 @@ EXPECT_FALSE(parsed); } -TEST(SignedExchangeCertificateParseB2Test, ParseGoldenFile) { +TEST(SignedExchangeCertificateParseTest, ParseGoldenFile) { base::FilePath path; base::PathService::Get(content::DIR_TEST_DATA, &path); path =
diff --git a/content/browser/web_package/signed_exchange_envelope.cc b/content/browser/web_package/signed_exchange_envelope.cc index f1e479c..4c86839 100644 --- a/content/browser/web_package/signed_exchange_envelope.cc +++ b/content/browser/web_package/signed_exchange_envelope.cc
@@ -293,8 +293,6 @@ ret.set_cbor_header(cbor_header); ret.set_request_url(request_url); - ret.set_request_method("GET"); - if (!ParseResponseMap(*value, &ret, devtools_proxy)) { signed_exchange_utils::ReportErrorAndTraceEvent( devtools_proxy, "Failed to parse response map.");
diff --git a/content/browser/web_package/signed_exchange_envelope.h b/content/browser/web_package/signed_exchange_envelope.h index 1803e36..0031315 100644 --- a/content/browser/web_package/signed_exchange_envelope.h +++ b/content/browser/web_package/signed_exchange_envelope.h
@@ -64,11 +64,6 @@ request_url_ = url; } - const std::string& request_method() const { return request_method_; } - void set_request_method(base::StringPiece s) { - s.CopyToString(&request_method_); - } - net::HttpStatusCode response_code() const { return response_code_; } void set_response_code(net::HttpStatusCode c) { response_code_ = c; } @@ -86,8 +81,6 @@ std::vector<uint8_t> cbor_header_; signed_exchange_utils::URLWithRawString request_url_; - std::string request_method_; - net::HttpStatusCode response_code_; HeaderMap response_headers_; SignedExchangeSignatureHeaderField::Signature signature_;
diff --git a/content/browser/web_package/signed_exchange_envelope_unittest.cc b/content/browser/web_package/signed_exchange_envelope_unittest.cc index ee07eb9..17e0286c 100644 --- a/content/browser/web_package/signed_exchange_envelope_unittest.cc +++ b/content/browser/web_package/signed_exchange_envelope_unittest.cc
@@ -102,7 +102,6 @@ ASSERT_TRUE(envelope.has_value()); EXPECT_EQ(envelope->request_url().url, GURL("https://test.example.org/test/")); - EXPECT_EQ(envelope->request_method(), "GET"); EXPECT_EQ(envelope->response_code(), static_cast<net::HttpStatusCode>(200u)); EXPECT_EQ(envelope->response_headers().size(), 3u); EXPECT_EQ(envelope->response_headers().find("content-encoding")->second, @@ -115,7 +114,6 @@ {{kStatusKey, "200"}, {"content-type", "text/html"}}); ASSERT_TRUE(header.has_value()); EXPECT_EQ(header->request_url().url, GURL("https://test.example.org/test/")); - EXPECT_EQ(header->request_method(), "GET"); EXPECT_EQ(header->response_code(), static_cast<net::HttpStatusCode>(200u)); EXPECT_EQ(header->response_headers().size(), 1u); }
diff --git a/content/browser/web_package/signed_exchange_handler.cc b/content/browser/web_package/signed_exchange_handler.cc index 9b4f91bb..9b2d779 100644 --- a/content/browser/web_package/signed_exchange_handler.cc +++ b/content/browser/web_package/signed_exchange_handler.cc
@@ -4,6 +4,8 @@ #include "content/browser/web_package/signed_exchange_handler.h" +#include <utility> + #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" @@ -455,8 +457,8 @@ nullptr); } std::move(headers_callback_) - .Run(result, error, GetFallbackUrl(), std::string(), - network::ResourceResponseHead(), nullptr); + .Run(result, error, GetFallbackUrl(), network::ResourceResponseHead(), + nullptr); state_ = State::kHeadersCallbackCalled; } @@ -674,8 +676,7 @@ response_head.ssl_info = std::move(ssl_info); std::move(headers_callback_) .Run(SignedExchangeLoadResult::kSuccess, net::OK, - envelope_->request_url().url, envelope_->request_method(), - response_head, std::move(mi_stream)); + envelope_->request_url().url, response_head, std::move(mi_stream)); state_ = State::kHeadersCallbackCalled; }
diff --git a/content/browser/web_package/signed_exchange_handler.h b/content/browser/web_package/signed_exchange_handler.h index 50608961..fc9dcade 100644 --- a/content/browser/web_package/signed_exchange_handler.h +++ b/content/browser/web_package/signed_exchange_handler.h
@@ -59,8 +59,7 @@ // validated against a verified certificate, or on failure. // On success: // - |result| is kSuccess. - // - |request_url| and |request_method| are the exchange's request's URL and - // method. + // - |request_url| is the exchange's request's URL. // - |resource_response| contains inner response's headers. // - The payload stream can be read from |payload_stream|. // On failure: @@ -71,7 +70,6 @@ SignedExchangeLoadResult result, net::Error error, const GURL& request_url, - const std::string& request_method, const network::ResourceResponseHead& resource_response, std::unique_ptr<net::SourceStream> payload_stream)>;
diff --git a/content/browser/web_package/signed_exchange_handler_unittest.cc b/content/browser/web_package/signed_exchange_handler_unittest.cc index 4c0c6b9..f2b83405 100644 --- a/content/browser/web_package/signed_exchange_handler_unittest.cc +++ b/content/browser/web_package/signed_exchange_handler_unittest.cc
@@ -316,7 +316,6 @@ void OnHeaderFound(SignedExchangeLoadResult result, net::Error error, const GURL& url, - const std::string&, const network::ResourceResponseHead& resource_response, std::unique_ptr<net::SourceStream> payload_stream) { read_header_ = true;
diff --git a/content/browser/web_package/signed_exchange_loader.cc b/content/browser/web_package/signed_exchange_loader.cc index 54534c1d..a453d3d 100644 --- a/content/browser/web_package/signed_exchange_loader.cc +++ b/content/browser/web_package/signed_exchange_loader.cc
@@ -266,7 +266,6 @@ SignedExchangeLoadResult result, net::Error error, const GURL& request_url, - const std::string& request_method, const network::ResourceResponseHead& resource_response, std::unique_ptr<net::SourceStream> payload_stream) { UMA_HISTOGRAM_ENUMERATION(kLoadResultHistogram, result); @@ -297,7 +296,6 @@ } inner_request_url_ = request_url; - // TODO(https://crbug.com/803774): Handle no-GET request_method as a error. DCHECK(outer_response_timing_info_); forwarding_client_->OnReceiveRedirect( CreateRedirectInfo(request_url, outer_request_, outer_response_),
diff --git a/content/browser/web_package/signed_exchange_loader.h b/content/browser/web_package/signed_exchange_loader.h index 175542e5..7346ab5 100644 --- a/content/browser/web_package/signed_exchange_loader.h +++ b/content/browser/web_package/signed_exchange_loader.h
@@ -110,7 +110,6 @@ SignedExchangeLoadResult result, net::Error error, const GURL& request_url, - const std::string& request_method, const network::ResourceResponseHead& resource_response, std::unique_ptr<net::SourceStream> payload_stream);
diff --git a/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc b/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc index 1b08ae07..896df52 100644 --- a/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc +++ b/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
@@ -237,7 +237,6 @@ ASSERT_EQ(1u, certlist.size()); SignedExchangeEnvelope envelope; - envelope.set_request_method("GET"); envelope.set_request_url(signed_exchange_utils::URLWithRawString( "https://test.example.org/test/")); envelope.set_response_code(net::HTTP_OK); @@ -265,7 +264,6 @@ ASSERT_EQ(1u, certlist.size()); SignedExchangeEnvelope envelope; - envelope.set_request_method("GET"); envelope.set_request_url(signed_exchange_utils::URLWithRawString( "https://test.example.org/test/")); envelope.set_response_code(net::HTTP_OK);
diff --git a/content/browser/webauth/authenticator_impl.cc b/content/browser/webauth/authenticator_impl.cc index 498167b..4241adbf 100644 --- a/content/browser/webauth/authenticator_impl.cc +++ b/content/browser/webauth/authenticator_impl.cc
@@ -488,8 +488,10 @@ } // caBLE is independent of the BLE transport. - transports.insert( - device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy); + if (base::FeatureList::IsEnabled(features::kWebAuthCable)) { + transports.insert( + device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy); + } return transports; }
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc index 7d26e6f..52243ac 100644 --- a/content/browser/webauth/authenticator_impl_unittest.cc +++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -989,6 +989,14 @@ device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy)); } +TEST_F(AuthenticatorImplTest, TestCableDiscoveryDisabledWithFlag) { + DisableFeature(features::kWebAuthCable); + + auto authenticator = ConnectToAuthenticator(); + EXPECT_FALSE(SupportsTransportProtocol( + device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy)); +} + #if defined(OS_WIN) TEST_F(AuthenticatorImplTest, TestCableDiscoveryEnabled) { auto authenticator = ConnectToAuthenticator();
diff --git a/content/common/appcache_interfaces.cc b/content/common/appcache_interfaces.cc index c07a2b7..7be1c80 100644 --- a/content/common/appcache_interfaces.cc +++ b/content/common/appcache_interfaces.cc
@@ -6,8 +6,6 @@ #include <set> -#include "base/strings/pattern.h" -#include "base/strings/string_util.h" #include "content/public/common/url_constants.h" #include "url/gurl.h" #include "url/url_constants.h" @@ -17,34 +15,6 @@ const char kHttpGETMethod[] = "GET"; const char kHttpHEADMethod[] = "HEAD"; -AppCacheNamespace::AppCacheNamespace() - : type(APPCACHE_FALLBACK_NAMESPACE), is_pattern(false) {} - -AppCacheNamespace::AppCacheNamespace(AppCacheNamespaceType type, - const GURL& url, - const GURL& target, - bool is_pattern) - : type(type), - namespace_url(url), - target_url(target), - is_pattern(is_pattern) {} - -AppCacheNamespace::~AppCacheNamespace() { -} - -bool AppCacheNamespace::IsMatch(const GURL& url) const { - if (is_pattern) { - // We have to escape '?' characters since MatchPattern also treats those - // as wildcards which we don't want here, we only do '*'s. - std::string pattern = namespace_url.spec(); - if (namespace_url.has_query()) - base::ReplaceSubstringsAfterOffset(&pattern, 0, "?", "\\?"); - return base::MatchPattern(url.spec(), pattern); - } - return base::StartsWith(url.spec(), namespace_url.spec(), - base::CompareCase::SENSITIVE); -} - bool IsSchemeSupportedForAppCache(const GURL& url) { bool supported = url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kHttpsScheme) ||
diff --git a/content/common/appcache_interfaces.h b/content/common/appcache_interfaces.h index 4b378096..b01e211 100644 --- a/content/common/appcache_interfaces.h +++ b/content/common/appcache_interfaces.h
@@ -5,20 +5,10 @@ #ifndef CONTENT_COMMON_APPCACHE_INTERFACES_H_ #define CONTENT_COMMON_APPCACHE_INTERFACES_H_ -#include <stdint.h> - #include <string> -#include "base/files/file_path.h" #include "content/common/content_export.h" #include "content/public/common/appcache_info.h" -#include "mojo/public/cpp/system/message_pipe.h" -#include "third_party/blink/public/mojom/appcache/appcache.mojom.h" -#include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h" - -namespace net { -class URLRequest; -} namespace content { @@ -30,62 +20,12 @@ APPCACHE_LOG_ERROR }; -enum AppCacheNamespaceType { - APPCACHE_FALLBACK_NAMESPACE, - APPCACHE_INTERCEPT_NAMESPACE, - APPCACHE_NETWORK_NAMESPACE -}; - -struct CONTENT_EXPORT AppCacheNamespace { - AppCacheNamespace(); // Type is APPCACHE_FALLBACK_NAMESPACE by default. - AppCacheNamespace(AppCacheNamespaceType type, const GURL& url, - const GURL& target, bool is_pattern); - ~AppCacheNamespace(); - - bool IsMatch(const GURL& url) const; - - AppCacheNamespaceType type; - GURL namespace_url; - GURL target_url; - bool is_pattern; -}; - -// Interface used by backend (browser-process) to talk to frontend (renderer). -class CONTENT_EXPORT AppCacheFrontend { - public: - virtual void OnCacheSelected(int host_id, - const blink::mojom::AppCacheInfo& info) = 0; - virtual void OnStatusChanged(const std::vector<int>& host_ids, - blink::mojom::AppCacheStatus status) = 0; - virtual void OnEventRaised(const std::vector<int>& host_ids, - blink::mojom::AppCacheEventID event_id) = 0; - virtual void OnProgressEventRaised(const std::vector<int>& host_ids, - const GURL& url, - int num_total, int num_complete) = 0; - virtual void OnErrorEventRaised( - const std::vector<int>& host_ids, - const blink::mojom::AppCacheErrorDetails& details) = 0; - virtual void OnContentBlocked(int host_id, - const GURL& manifest_url) = 0; - virtual void OnLogMessage(int host_id, AppCacheLogLevel log_level, - const std::string& message) = 0; - // In the network service world, we pass the URLLoaderFactory instance to be - // used to issue subresource requeste in the |loader_factory_pipe_handle| - // parameter. - virtual void OnSetSubresourceFactory( - int host_id, - network::mojom::URLLoaderFactoryPtr url_loader_factory) = 0; - - virtual ~AppCacheFrontend() {} -}; - // Useful string constants. CONTENT_EXPORT extern const char kHttpGETMethod[]; CONTENT_EXPORT extern const char kHttpHEADMethod[]; CONTENT_EXPORT bool IsSchemeSupportedForAppCache(const GURL& url); -CONTENT_EXPORT bool IsMethodSupportedForAppCache( - const std::string& method); +CONTENT_EXPORT bool IsMethodSupportedForAppCache(const std::string& method); } // namespace
diff --git a/content/content_resources.grd b/content/content_resources.grd index 44307b2..8abcba9 100644 --- a/content/content_resources.grd +++ b/content/content_resources.grd
@@ -26,12 +26,6 @@ <include name="IDR_INDEXED_DB_INTERNALS_CSS" file="browser/resources/indexed_db/indexeddb_internals.css" flattenhtml="true" compress="gzip" type="BINDATA" /> <include name="IDR_MEDIA_INTERNALS_HTML" file="browser/resources/media/media_internals.html" flattenhtml="true" allowexternalscript="true" compress="gzip" type="BINDATA" /> <include name="IDR_MEDIA_INTERNALS_JS" file="browser/resources/media/media_internals.js" flattenhtml="true" compress="gzip" type="BINDATA" /> - <include name="IDR_MOJO_CONTENT_BROWSER_MANIFEST" file="${root_gen_dir}/content/public/app/browser_manifest.json" use_base_dir="false" type="BINDATA" /> - <include name="IDR_MOJO_CONTENT_GPU_MANIFEST" file="${root_gen_dir}/content/public/app/gpu_manifest.json" use_base_dir="false" type="BINDATA" /> - <include name="IDR_MOJO_CONTENT_PACKAGED_SERVICES_MANIFEST" file="${root_gen_dir}/content/public/app/packaged_services_manifest.json" use_base_dir="false" type="BINDATA" /> - <include name="IDR_MOJO_CONTENT_PLUGIN_MANIFEST" file="${root_gen_dir}/content/public/app/plugin_manifest.json" use_base_dir="false" type="BINDATA" /> - <include name="IDR_MOJO_CONTENT_RENDERER_MANIFEST" file="${root_gen_dir}/content/public/app/renderer_manifest.json" use_base_dir="false" type="BINDATA" /> - <include name="IDR_MOJO_CONTENT_UTILITY_MANIFEST" file="${root_gen_dir}/content/public/app/utility_manifest.json" use_base_dir="false" type="BINDATA" /> <include name="IDR_NETWORK_ERROR_LISTING_HTML" file="browser/resources/net/network_errors_listing.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> <include name="IDR_NETWORK_ERROR_LISTING_JS" file="browser/resources/net/network_errors_listing.js" flattenhtml="true" type="BINDATA" /> <include name="IDR_NETWORK_ERROR_LISTING_CSS" file="browser/resources/net/network_errors_listing.css" flattenhtml="true" type="BINDATA" />
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContactsDialogHost.java b/content/public/android/java/src/org/chromium/content/browser/ContactsDialogHost.java index 02a59af..c37330c 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContactsDialogHost.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContactsDialogHost.java
@@ -4,6 +4,10 @@ package org.chromium.content.browser; +import android.Manifest; +import android.content.pm.PackageManager; +import android.text.TextUtils; + import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.ui.ContactsPickerListener; @@ -41,12 +45,32 @@ private void showDialog( boolean multiple, boolean includeNames, boolean includeEmails, boolean includeTel) { if (mWindowAndroid.getActivity().get() == null) { - nativeEndContactsList(mNativeContactsProviderAndroid); + nativeEndWithPermissionDenied(mNativeContactsProviderAndroid); return; } - UiUtils.showContactsPicker(mWindowAndroid.getActivity().get(), this, multiple, includeNames, - includeEmails, includeTel); + if (mWindowAndroid.hasPermission(Manifest.permission.READ_CONTACTS)) { + UiUtils.showContactsPicker(mWindowAndroid.getActivity().get(), this, multiple, + includeNames, includeEmails, includeTel); + return; + } + + if (!mWindowAndroid.canRequestPermission(Manifest.permission.READ_CONTACTS)) { + nativeEndWithPermissionDenied(mNativeContactsProviderAndroid); + return; + } + + mWindowAndroid.requestPermissions( + new String[] {Manifest.permission.READ_CONTACTS}, (permissions, grantResults) -> { + if (permissions.length == 1 && grantResults.length == 1 + && TextUtils.equals(permissions[0], Manifest.permission.READ_CONTACTS) + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + UiUtils.showContactsPicker(mWindowAndroid.getActivity().get(), this, + multiple, includeNames, includeEmails, includeTel); + } else { + nativeEndWithPermissionDenied(mNativeContactsProviderAndroid); + } + }); } @Override @@ -84,4 +108,5 @@ boolean includeNames, boolean includeEmails, boolean includeTel, String[] names, String[] emails, String[] tel); private static native void nativeEndContactsList(long nativeContactsProviderAndroid); + private static native void nativeEndWithPermissionDenied(long nativeContactsProviderAndroid); }
diff --git a/content/public/app/BUILD.gn b/content/public/app/BUILD.gn index a2147b2..5f5d2f6 100644 --- a/content/public/app/BUILD.gn +++ b/content/public/app/BUILD.gn
@@ -180,11 +180,51 @@ } } -service_manifest("packaged_services_manifest") { - name = "content_packaged_services" - source = "mojo/content_packaged_services_manifest.json" - packaged_services = [ +source_set("content_browser_manifest") { + sources = [ + "content_browser_manifest.cc", + "content_browser_manifest.h", + ] + + deps = [ + ":v8_snapshot_overlay_manifest", + "//base", + "//content/public/common:service_names", + "//services/content:manifest", + "//services/file:manifest", + ] + + public_deps = [ + "//services/service_manager/public/cpp", + ] +} + +source_set("content_gpu_manifest") { + sources = [ + "content_gpu_manifest.cc", + "content_gpu_manifest.h", + ] + + deps = [ + "//base", + "//content/public/common:service_names", + ] + + public_deps = [ + "//services/service_manager/public/cpp", + ] +} + +source_set("content_packaged_services_manifest") { + sources = [ + "content_packaged_services_manifest.cc", + "content_packaged_services_manifest.h", + ] + + deps = [ + "//base", "//components/services/heap_profiling:manifest", + "//content/public/common:service_names", "//media/mojo/services:cdm_manifest", "//media/mojo/services:media_manifest", "//services/audio:manifest", @@ -195,55 +235,102 @@ "//services/network:manifest", "//services/resource_coordinator:manifest", "//services/shape_detection:manifest", + "//services/tracing:manifest", "//services/video_capture:manifest", "//services/viz:manifest", ] + public_deps = [ + "//services/service_manager/public/cpp", + ] + if (is_linux) { - packaged_services += [ "//components/services/font:manifest" ] + deps += [ "//components/services/font:manifest" ] } - if (enable_cros_libassistant) { - packaged_services += - [ "//chromeos/services/assistant/audio_decoder:manifest" ] + if (is_chromeos) { + deps += [ "//chromeos/assistant:buildflags" ] + if (enable_cros_libassistant) { + deps += [ "//chromeos/services/assistant/audio_decoder:manifest" ] + } } } -service_manifest("browser_manifest") { - name = "content_browser" - source = "mojo/content_browser_manifest.json" - packaged_services = [ - "//services/content:manifest", - "//services/file:manifest", +source_set("content_plugin_manifest") { + sources = [ + "content_plugin_manifest.cc", + "content_plugin_manifest.h", + ] + + deps = [ + "//base", + "//content/public/common:service_names", + ] + + public_deps = [ + "//services/service_manager/public/cpp", ] } -service_manifest("gpu_manifest") { - name = "content_gpu" - source = "mojo/content_gpu_manifest.json" +source_set("content_renderer_manifest") { + sources = [ + "content_renderer_manifest.cc", + "content_renderer_manifest.h", + ] + + deps = [ + ":v8_snapshot_overlay_manifest", + "//base", + "//content/public/common:service_names", + ] + + public_deps = [ + "//services/service_manager/public/cpp", + ] } -service_manifest("plugin_manifest") { - name = "content_plugin" - source = "mojo/content_plugin_manifest.json" +source_set("content_utility_manifest") { + sources = [ + "content_utility_manifest.cc", + "content_utility_manifest.h", + ] + + deps = [ + ":v8_snapshot_overlay_manifest", + "//base", + "//content/public/common:service_names", + ] + + public_deps = [ + "//services/service_manager/public/cpp", + ] } -service_manifest("snapshot_manifest") { - if (use_v8_context_snapshot) { - source = "mojo/context_snapshot_manifest.json" - } else { - source = "mojo/snapshot_blob_manifest.json" - } +source_set("v8_snapshot_overlay_manifest") { + sources = [ + "v8_snapshot_overlay_manifest.cc", + "v8_snapshot_overlay_manifest.h", + ] + + deps = [ + "//base", + "//content/public/common:content_descriptor_keys", + ] + + public_deps = [ + "//services/service_manager/public/cpp", + ] + + configs += [ "//tools/v8_context_snapshot:use_v8_context_snapshot" ] } -service_manifest("renderer_manifest") { - name = "content_renderer" - source = "mojo/content_renderer_manifest.json" - overlays = [ ":snapshot_manifest" ] -} - -service_manifest("utility_manifest") { - name = "content_utility" - source = "mojo/content_utility_manifest.json" - overlays = [ ":snapshot_manifest" ] +group("service_manifests") { + public_deps = [ + ":content_browser_manifest", + ":content_gpu_manifest", + ":content_packaged_services_manifest", + ":content_plugin_manifest", + ":content_renderer_manifest", + ":content_utility_manifest", + ] }
diff --git a/content/public/app/DEPS b/content/public/app/DEPS index 35f5311f..889c38a 100644 --- a/content/public/app/DEPS +++ b/content/public/app/DEPS
@@ -1,7 +1,34 @@ include_rules = [ "+content/public/browser/content_browser_client.h", + "+content/public/common/service_manifest.mojom.h", "+content/public/gpu/content_gpu_client.h", "+content/public/renderer/content_renderer_client.h", "+content/public/utility/content_utility_client.h", "+services/service_manager", ] + +specific_include_rules = { + "content_browser_manifest\.cc": [ + "+services/content/manifest.h", + "+services/file/manifest.h", + ], + "content_packaged_services_manifest\.cc": [ + "+chromeos/assistant/buildflags.h", + "+chromeos/services/assistant/audio_decoder/manifest.h", + "+components/services/font/manifest.h", + "+components/services/heap_profiling/manifest.h", + "+media/mojo/services/cdm_manifest.h", + "+media/mojo/services/media_manifest.h", + "+services/audio/manifest.h", + "+services/data_decoder/manifest.h", + "+services/device/manifest.h", + "+services/media_session/manifest.h", + "+services/metrics/manifest.h", + "+services/network/manifest.h", + "+services/resource_coordinator/manifest.h", + "+services/shape_detection/manifest.h", + "+services/tracing/manifest.h", + "+services/video_capture/manifest.h", + "+services/viz/manifest.h", + ], +}
diff --git a/content/public/app/OWNERS b/content/public/app/OWNERS index 16d9656f..6ec455e 100644 --- a/content/public/app/OWNERS +++ b/content/public/app/OWNERS
@@ -1,2 +1,37 @@ -jcivelli@chromium.org +oksamyt@chromium.org rockot@google.com + +per-file content_browser_manifest.cc=set noparent +per-file content_browser_manifest.cc=file://ipc/SECURITY_OWNERS +per-file content_browser_manifest.h=set noparent +per-file content_browser_manifest.h=file://ipc/SECURITY_OWNERS + +per-file content_gpu_manifest.cc=set noparent +per-file content_gpu_manifest.cc=file://ipc/SECURITY_OWNERS +per-file content_gpu_manifest.h=set noparent +per-file content_gpu_manifest.h=file://ipc/SECURITY_OWNERS + +per-file content_packaged_services_manifest.cc=set noparent +per-file content_packaged_services_manifest.cc=file://ipc/SECURITY_OWNERS +per-file content_packaged_services_manifest.h=set noparent +per-file content_packaged_services_manifest.h=file://ipc/SECURITY_OWNERS + +per-file content_plugin_manifest.cc=set noparent +per-file content_plugin_manifest.cc=file://ipc/SECURITY_OWNERS +per-file content_plugin_manifest.h=set noparent +per-file content_plugin_manifest.h=file://ipc/SECURITY_OWNERS + +per-file content_renderer_manifest.cc=set noparent +per-file content_renderer_manifest.cc=file://ipc/SECURITY_OWNERS +per-file content_renderer_manifest.h=set noparent +per-file content_renderer_manifest.h=file://ipc/SECURITY_OWNERS + +per-file content_utility_manifest.cc=set noparent +per-file content_utility_manifest.cc=file://ipc/SECURITY_OWNERS +per-file content_utility_manifest.h=set noparent +per-file content_utility_manifest.h=file://ipc/SECURITY_OWNERS + +per-file v8_snapshot_overlay_manifest.cc=set noparent +per-file v8_snapshot_overlay_manifest.cc=file://ipc/SECURITY_OWNERS +per-file v8_snapshot_overlay_manifest.h=set noparent +per-file v8_snapshot_overlay_manifest.h=file://ipc/SECURITY_OWNERS
diff --git a/content/public/app/content_browser_manifest.cc b/content/public/app/content_browser_manifest.cc new file mode 100644 index 0000000..0e9aca4 --- /dev/null +++ b/content/public/app/content_browser_manifest.cc
@@ -0,0 +1,283 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/app/content_browser_manifest.h" + +#include "base/no_destructor.h" +#include "content/public/common/service_names.mojom.h" +#include "services/content/manifest.h" +#include "services/file/manifest.h" +#include "services/service_manager/public/cpp/manifest_builder.h" + +namespace content { + +const service_manager::Manifest& GetContentBrowserManifest() { + static base::NoDestructor<service_manager::Manifest> manifest{ + service_manager::ManifestBuilder() + .WithServiceName(mojom::kBrowserServiceName) + .WithDisplayName("Content (browser process)") + .WithOptions(service_manager::ManifestOptionsBuilder() + .CanConnectToInstancesInAnyGroup(true) + .CanConnectToInstancesWithAnyId(true) + .CanRegisterOtherServiceInstances(true) + .Build()) + .ExposeCapability("field_trials", + std::set<const char*>{ + "content.mojom.FieldTrialRecorder", + }) + .ExposeCapability("sandbox_support", + std::set<const char*>{ + "content.mojom.SandboxSupportMac", + }) + .ExposeCapability("font_cache", + std::set<const char*>{ + "content.mojom.FontCacheWin", + }) + .ExposeCapability( + "plugin", + std::set<const char*>{ + "discardable_memory.mojom.DiscardableSharedMemoryManager", + "ws.mojom.Gpu", + }) + .ExposeCapability( + "app", + std::set<const char*>{ + "discardable_memory.mojom.DiscardableSharedMemoryManager", + "memory_instrumentation.mojom.Coordinator", + }) + .ExposeCapability("dwrite_font_proxy", + std::set<const char*>{ + "blink.mojom.DWriteFontProxy", + }) + .ExposeCapability("service_manager:service_factory", + std::set<const char*>{ + "service_manager.mojom.ServiceFactory", + }) + .ExposeCapability( + "renderer", + std::set<const char*>{ + "blink.mojom.AppCacheBackend", + "blink.mojom.BackgroundSyncService", + "blink.mojom.BlobRegistry", + "blink.mojom.BroadcastChannelProvider", + "blink.mojom.ClipboardHost", + "blink.mojom.CodeCacheHost", + "blink.mojom.FontUniqueNameLookup", + "blink.mojom.EmbeddedFrameSinkProvider", + "blink.mojom.FileUtilitiesHost", + "blink.mojom.FileSystemManager", + "blink.mojom.Hyphenation", + "blink.mojom.MediaStreamTrackMetricsHost", + "blink.mojom.MimeRegistry", + "blink.mojom.PluginRegistry", + "blink.mojom.ReportingServiceProxy", + "blink.mojom.StoragePartitionService", + "blink.mojom.WebDatabaseHost", + "content.mojom.ClipboardHost", + "content.mojom.FieldTrialRecorder", + "content.mojom.FrameSinkProvider", + "content.mojom.PeerConnectionTrackerHost", + "content.mojom.PushMessaging", + "content.mojom.RendererHost", + "content.mojom.ReportingServiceProxy", + "content.mojom.ServiceWorkerDispatcherHost", + "content.mojom.WorkerURLLoaderFactoryProvider", + "device.mojom.BatteryMonitor", + "device.mojom.GamepadHapticsManager", + "discardable_memory.mojom.DiscardableSharedMemoryManager", + "media.mojom.KeySystemSupport", + "media.mojom.InterfaceFactory", + "media.mojom.VideoCaptureHost", + "media.mojom.VideoDecodePerfHistory", + "metrics.mojom.SingleSampleMetricsProvider", + "midi.mojom.MidiSessionProvider", + "network.mojom.P2PSocketManager", + "network.mojom.MdnsResponder", + "network.mojom.URLLoaderFactory", + "resource_coordinator.mojom.ProcessCoordinationUnit", + "viz.mojom.CompositingModeReporter", + "ws.mojom.Gpu", + }) + .ExposeCapability("gpu_client", + std::set<const char*>{ + "ws.mojom.Gpu", + }) + .ExposeCapability( + "gpu", + std::set<const char*>{ + "discardable_memory.mojom.DiscardableSharedMemoryManager", + "media.mojom.AndroidOverlayProvider", + }) + .RequireCapability("data_decoder", "image_decoder") + .RequireCapability("data_decoder", "json_parser") + .RequireCapability("data_decoder", "xml_parser") + .RequireCapability("cdm", "media:cdm") + .RequireCapability("shape_detection", "barcode_detection") + .RequireCapability("shape_detection", "face_detection") + .RequireCapability("shape_detection", "text_detection") + .RequireCapability("file", "file:filesystem") + .RequireCapability("file", "file:leveldb") + .RequireCapability("network", "network_service") + .RequireCapability("network", "test") + .RequireCapability("network", "url_loader") + .RequireCapability(mojom::kRendererServiceName, "browser") + .RequireCapability("media", "media:media") + .RequireCapability("*", "app") + .RequireCapability("content", "navigation") + .RequireCapability("resource_coordinator", "coordination_unit") + .RequireCapability("resource_coordinator", + "coordination_unit_introspector") + .RequireCapability("resource_coordinator", "service_callbacks") + .RequireCapability("resource_coordinator", "page_signal") + .RequireCapability("service_manager", + "service_manager:service_manager") + .RequireCapability("chromecast", "multizone") + .RequireCapability("content_plugin", "browser") + .RequireCapability("metrics", "url_keyed_metrics") + .RequireCapability("content_utility", "browser") + .RequireCapability("device", "device:battery_monitor") + .RequireCapability("device", "device:bluetooth_system") + .RequireCapability("device", "device:generic_sensor") + .RequireCapability("device", "device:geolocation") + .RequireCapability("device", "device:hid") + .RequireCapability("device", "device:input_service") + .RequireCapability("device", "device:mtp") + .RequireCapability("device", "device:nfc") + .RequireCapability("device", "device:serial") + .RequireCapability("device", "device:usb") + .RequireCapability("device", "device:usb_test") + .RequireCapability("device", "device:vibration") + .RequireCapability("device", "device:wake_lock") + .RequireCapability("media_session", "media_session:app") + .RequireCapability("video_capture", "capture") + .RequireCapability("video_capture", "tests") + .RequireCapability("unzip_service", "unzip_file") + .RequireCapability("tracing", "tracing") + .RequireCapability("patch_service", "patch_file") + .RequireCapability("ui", "arc_manager") + .RequireCapability("audio", "info") + .RequireCapability("audio", "debug_recording") + .RequireCapability("audio", "device_notifier") + .RequireCapability("audio", "log_factory_manager") + .RequireCapability("audio", "stream_factory") + .RequireCapability("audio", "testing_api") + .RequireCapability("content_gpu", "browser") + .ExposeInterfaceFilterCapability_Deprecated( + "navigation:shared_worker", "renderer", + std::set<const char*>{ + "blink.mojom.CacheStorage", "blink.mojom.FileSystemManager", + "blink.mojom.IDBFactory", "blink.mojom.LockManager", + "blink.mojom.NotificationService", + "blink.mojom.PermissionService", + "blink.mojom.QuotaDispatcherHost", "network.mojom.WebSocket", + "payments.mojom.PaymentManager", + "shape_detection.mojom.BarcodeDetectionProvider", + "shape_detection.mojom.FaceDetectionProvider", + "shape_detection.mojom.TextDetection"}) + .ExposeInterfaceFilterCapability_Deprecated( + "navigation:dedicated_worker", "renderer", + std::set<const char*>{ + "blink.mojom.CacheStorage", + "blink.mojom.DedicatedWorkerFactory", + "blink.mojom.FileSystemManager", "blink.mojom.IDBFactory", + "blink.mojom.IdleManager", "blink.mojom.LockManager", + "blink.mojom.NotificationService", + "blink.mojom.PermissionService", + "blink.mojom.QuotaDispatcherHost", + "blink.mojom.SerialService", "blink.mojom.WebUsbService", + "network.mojom.WebSocket", "payments.mojom.PaymentManager", + "shape_detection.mojom.BarcodeDetectionProvider", + "shape_detection.mojom.FaceDetectionProvider", + "shape_detection.mojom.TextDetection"}) + .ExposeInterfaceFilterCapability_Deprecated( + "navigation:service_worker", "renderer", + std::set<const char*>{ + "blink.mojom.BackgroundFetchService", + "blink.mojom.CacheStorage", "blink.mojom.CookieStore", + "blink.mojom.IDBFactory", "blink.mojom.LockManager", + "blink.mojom.NotificationService", + "blink.mojom.PermissionService", + "blink.mojom.QuotaDispatcherHost", + "network.mojom.RestrictedCookieManager", + "network.mojom.WebSocket", "payments.mojom.PaymentManager", + "shape_detection.mojom.BarcodeDetectionProvider", + "shape_detection.mojom.FaceDetectionProvider", + "shape_detection.mojom.TextDetection"}) + .ExposeInterfaceFilterCapability_Deprecated( + "navigation:frame", "renderer", + std::set<const char*>{ + "autofill.mojom.AutofillDriver", + "autofill.mojom.PasswordManagerDriver", + "blink.mojom.AnchorElementMetricsHost", + "blink.mojom.AudioContextManager", + "blink.mojom.Authenticator", + "blink.mojom.BackgroundFetchService", + "blink.mojom.CacheStorage", + "blink.mojom.ColorChooserFactory", + "blink.mojom.ContactsManager", + "blink.mojom.CredentialManager", + "blink.mojom.DisplayCutoutHost", + "blink.mojom.DedicatedWorkerFactory", + "blink.mojom.FileChooser", + "blink.mojom.FileSystemManager", + "blink.mojom.GeolocationService", + "blink.mojom.IDBFactory", + "blink.mojom.IdleManager", + "blink.mojom.InsecureInputService", + "blink.mojom.KeyboardLockService", + "blink.mojom.LockManager", + "blink.mojom.MediaDevicesDispatcherHost", + "blink.mojom.MediaStreamDispatcherHost", + "blink.mojom.MediaSessionService", + "blink.mojom.NotificationService", + "blink.mojom.PermissionService", + "blink.mojom.Portal", + "blink.mojom.PrefetchURLLoaderService", + "blink.mojom.PresentationService", + "blink.mojom.QuotaDispatcherHost", + "blink.mojom.SerialService", + "blink.mojom.SharedWorkerConnector", + "blink.mojom.SpeechRecognizer", + "blink.mojom.TextSuggestionHost", + "blink.mojom.UnhandledTapNotifier", + "blink.mojom.WakeLockService", + "blink.mojom.WebBluetoothService", + "blink.mojom.WebUsbService", + "blink.test.mojom.VirtualAuthenticatorManager", + "content.mojom.BrowserTarget", + "content.mojom.InputInjector", + "content.mojom.RendererAudioInputStreamFactory", + "content.mojom.RendererAudioOutputStreamFactory", + "device.mojom.GamepadMonitor", + "device.mojom.Geolocation", + "device.mojom.NFC", + "device.mojom.SensorProvider", + "device.mojom.VibrationManager", + "device.mojom.VRService", + "device.mojom.WakeLock", + "discardable_memory.mojom.DiscardableSharedMemoryManager", + "media.mojom.ImageCapture", + "media.mojom.InterfaceFactory", + "media.mojom.MediaMetricsProvider", + "media.mojom.RemoterFactory", + "media.mojom.Renderer", + "mojom.ProcessInternalsHandler", + "network.mojom.RestrictedCookieManager", + "network.mojom.WebSocket", + "payments.mojom.PaymentManager", + "payments.mojom.PaymentRequest", + "resource_coordinator.mojom.FrameCoordinationUnit", + "shape_detection.mojom.BarcodeDetectionProvider", + "shape_detection.mojom.FaceDetectionProvider", + "shape_detection.mojom.TextDetection", + "ws.mojom.Gpu"}) + .RequireInterfaceFilterCapability_Deprecated( + mojom::kRendererServiceName, "navigation:frame", "browser") + .PackageService(content::GetManifest()) + .PackageService(file::GetManifest()) + .Build()}; + return *manifest; +} + +} // namespace content
diff --git a/content/public/app/content_browser_manifest.h b/content/public/app/content_browser_manifest.h new file mode 100644 index 0000000..535c140 --- /dev/null +++ b/content/public/app/content_browser_manifest.h
@@ -0,0 +1,25 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_APP_CONTENT_BROWSER_MANIFEST_H_ +#define CONTENT_PUBLIC_APP_CONTENT_BROWSER_MANIFEST_H_ + +#include "services/service_manager/public/cpp/manifest.h" + +namespace content { + +// Returns the service manifest for the "content_browser" service. There are +// multiple instances of this service embedded within the browser process: a +// global instance which establishes a process-wide connection to the Service +// Manager, and one instance per BrowserContext which can be used to connect to +// service instances isolated on a per-BrowserContext basis. +// +// In-process services whose instances should each be bound to the lifetime of +// some BrowserContext are typically packaged within this manifest. For all +// other packaged services, see content_packaged_services_manifest.cc. +const service_manager::Manifest& GetContentBrowserManifest(); + +} // namespace content + +#endif // CONTENT_PUBLIC_APP_CONTENT_BROWSER_MANIFEST_H_
diff --git a/content/public/app/content_gpu_manifest.cc b/content/public/app/content_gpu_manifest.cc new file mode 100644 index 0000000..e3cc48b --- /dev/null +++ b/content/public/app/content_gpu_manifest.cc
@@ -0,0 +1,49 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/app/content_gpu_manifest.h" + +#include "base/no_destructor.h" +#include "content/public/common/service_names.mojom.h" +#include "services/service_manager/public/cpp/manifest_builder.h" + +namespace content { + +const service_manager::Manifest& GetContentGpuManifest() { + static base::NoDestructor<service_manager::Manifest> manifest{ + service_manager::ManifestBuilder() + .WithServiceName(mojom::kGpuServiceName) + .WithDisplayName("Content (GPU process)") + .ExposeCapability("service_manager:service_factory", + std::set<const char*>{ + "service_manager.mojom.ServiceFactory", + }) + .ExposeCapability("browser", + std::set<const char*>{ + "content.mojom.Child", + "content.mojom.ChildControl", + "content.mojom.ChildHistogramFetcher", + "content.mojom.ChildHistogramFetcherFactory", + "content.mojom.ResourceUsageReporter", + "IPC.mojom.ChannelBootstrap", + "service_manager.mojom.ServiceFactory", + "ui.ozone.mojom.DeviceCursor", + "ui.ozone.mojom.DrmDevice", + "ui.ozone.mojom.WaylandConnectionClient", + "ui.mojom.ScenicGpuService", + "viz.mojom.CompositingModeReporter", + "viz.mojom.VizMain", + }) + .RequireCapability("device", "device:power_monitor") + .RequireCapability(mojom::kBrowserServiceName, "dwrite_font_proxy") + .RequireCapability(mojom::kBrowserServiceName, "field_trials") + .RequireCapability(mojom::kBrowserServiceName, "gpu") + .RequireCapability("ui", "discardable_memory") + .RequireCapability("*", "app") + .RequireCapability("metrics", "url_keyed_metrics") + .Build()}; + return *manifest; +} + +} // namespace content
diff --git a/content/public/app/content_gpu_manifest.h b/content/public/app/content_gpu_manifest.h new file mode 100644 index 0000000..a8f3f5d1 --- /dev/null +++ b/content/public/app/content_gpu_manifest.h
@@ -0,0 +1,20 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_APP_CONTENT_GPU_MANIFEST_H_ +#define CONTENT_PUBLIC_APP_CONTENT_GPU_MANIFEST_H_ + +#include "services/service_manager/public/cpp/manifest.h" + +namespace content { + +// Returns the service manifest for the "content_gpu" service. Every GPU process +// is an instance of this service, so this manifest determines what capabilities +// are directly exposed and required by GPU processes through the Service +// Manager. +const service_manager::Manifest& GetContentGpuManifest(); + +} // namespace content + +#endif // CONTENT_PUBLIC_APP_CONTENT_GPU_MANIFEST_H_
diff --git a/content/public/app/content_packaged_services_manifest.cc b/content/public/app/content_packaged_services_manifest.cc new file mode 100644 index 0000000..5d7bc93 --- /dev/null +++ b/content/public/app/content_packaged_services_manifest.cc
@@ -0,0 +1,83 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/app/content_packaged_services_manifest.h" + +#include "base/no_destructor.h" +#include "build/build_config.h" +#include "components/services/heap_profiling/manifest.h" +#include "content/public/common/service_names.mojom.h" +#include "media/mojo/services/cdm_manifest.h" +#include "media/mojo/services/media_manifest.h" +#include "services/audio/manifest.h" +#include "services/data_decoder/manifest.h" +#include "services/device/manifest.h" +#include "services/media_session/manifest.h" +#include "services/metrics/manifest.h" +#include "services/network/manifest.h" +#include "services/resource_coordinator/manifest.h" +#include "services/service_manager/public/cpp/manifest_builder.h" +#include "services/shape_detection/manifest.h" +#include "services/tracing/manifest.h" +#include "services/video_capture/manifest.h" +#include "services/viz/manifest.h" + +#if defined(OS_LINUX) +#include "components/services/font/manifest.h" +#endif + +#if defined(OS_CHROMEOS) +#include "chromeos/assistant/buildflags.h" +#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) +#include "chromeos/services/assistant/audio_decoder/manifest.h" +#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) +#endif // defined(OS_CHROMEOS) + +namespace content { + +const service_manager::Manifest& GetContentPackagedServicesManifest() { + static base::NoDestructor<service_manager::Manifest> manifest { + service_manager::ManifestBuilder() + .WithServiceName(mojom::kPackagedServicesServiceName) + .WithOptions(service_manager::ManifestOptionsBuilder() + .WithInstanceSharingPolicy( + service_manager::Manifest::InstanceSharingPolicy:: + kSingleton) + .CanConnectToInstancesInAnyGroup(true) + .CanRegisterOtherServiceInstances(true) + .Build()) + .ExposeCapability("service_manager:service_factory", + std::set<const char*>{ + "service_manager.mojom.ServiceFactory", + }) + .RequireCapability(mojom::kBrowserServiceName, "") + .RequireCapability("*", "app") + .PackageService(heap_profiling::GetManifest()) + .PackageService(cdm::GetManifest()) + .PackageService(media::GetManifest()) + .PackageService(audio::GetManifest()) + .PackageService(data_decoder::GetManifest()) + .PackageService(device::GetManifest()) + .PackageService(media_session::GetManifest()) + .PackageService(metrics::GetManifest()) + .PackageService(network::GetManifest()) + .PackageService(resource_coordinator::GetManifest()) + .PackageService(shape_detection::GetManifest()) + .PackageService(tracing::GetManifest()) + .PackageService(video_capture::GetManifest()) + .PackageService(viz::GetManifest()) +#if defined(OS_LINUX) + .PackageService(font_service::GetManifest()) +#endif +#if defined(OS_CHROMEOS) +#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) + .PackageService(assistant_audio_decoder::GetManifest()) +#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) +#endif // defined(OS_CHROMEOS) + .Build() + }; + return *manifest; +} + +} // namespace content
diff --git a/content/public/app/content_packaged_services_manifest.h b/content/public/app/content_packaged_services_manifest.h new file mode 100644 index 0000000..7e749779 --- /dev/null +++ b/content/public/app/content_packaged_services_manifest.h
@@ -0,0 +1,26 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_APP_CONTENT_PACKAGED_SERVICES_MANIFEST_H_ +#define CONTENT_PUBLIC_APP_CONTENT_PACKAGED_SERVICES_MANIFEST_H_ + +#include "services/service_manager/public/cpp/manifest.h" + +namespace content { + +// Returns the service manifest for the "content_packaged_services" service. +// This is a singleton service embedded in the browser process, and it exists +// to package other in- and out-of-process services hosted by Content or its +// embedder. +// +// TODO(https://crbug.com/689159): This can be removed once process launching is +// moved out of Content and into the Service Manager. Instead of this hack, we +// should have a Service Manager embedder API for plugging in manifests at +// startup, as well as for hooking up in- and out-of-process service +// instantiation logic for individual services. +const service_manager::Manifest& GetContentPackagedServicesManifest(); + +} // namespace content + +#endif // CONTENT_PUBLIC_APP_CONTENT_PACKAGED_SERVICES_MANIFEST_H_
diff --git a/content/public/app/content_plugin_manifest.cc b/content/public/app/content_plugin_manifest.cc new file mode 100644 index 0000000..3f01d57 --- /dev/null +++ b/content/public/app/content_plugin_manifest.cc
@@ -0,0 +1,44 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/app/content_plugin_manifest.h" + +#include "base/no_destructor.h" +#include "content/public/common/service_names.mojom.h" +#include "services/service_manager/public/cpp/manifest_builder.h" + +namespace content { + +const service_manager::Manifest& GetContentPluginManifest() { + static base::NoDestructor<service_manager::Manifest> manifest{ + service_manager::ManifestBuilder() + .WithServiceName(mojom::kPluginServiceName) + .WithDisplayName("Content (plugin process)") + .ExposeCapability("service_manager:service_factory", + std::set<const char*>{ + "service_manager.mojom.ServiceFactory", + }) + .ExposeCapability("browser", + std::set<const char*>{ + "content.mojom.Child", + "content.mojom.ChildControl", + "content.mojom.ChildHistogramFetcher", + "content.mojom.ChildHistogramFetcherFactory", + "content.mojom.ResourceUsageReporter", + "IPC.mojom.ChannelBootstrap", + }) + .RequireCapability("device", "device:power_monitor") + .RequireCapability(mojom::kBrowserServiceName, "dwrite_font_proxy") + .RequireCapability(mojom::kBrowserServiceName, "field_trials") + .RequireCapability(mojom::kBrowserServiceName, "font_cache") + .RequireCapability(mojom::kBrowserServiceName, "plugin") + .RequireCapability(mojom::kBrowserServiceName, "sandbox_support") + .RequireCapability("ui", "discardable_memory") + .RequireCapability("*", "app") + .RequireCapability("font_service", "font_service") + .Build()}; + return *manifest; +} + +} // namespace content
diff --git a/content/public/app/content_plugin_manifest.h b/content/public/app/content_plugin_manifest.h new file mode 100644 index 0000000..25b0b18 --- /dev/null +++ b/content/public/app/content_plugin_manifest.h
@@ -0,0 +1,20 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_APP_CONTENT_PLUGIN_MANIFEST_H_ +#define CONTENT_PUBLIC_APP_CONTENT_PLUGIN_MANIFEST_H_ + +#include "services/service_manager/public/cpp/manifest.h" + +namespace content { + +// Returns the service manifest for the "content_plugin" service. Every +// plugin process is an instance of this service, so this manifest determines +// what capabilities are directly exposed and required by plugin processes +// through the Service Manager. +const service_manager::Manifest& GetContentPluginManifest(); + +} // namespace content + +#endif // CONTENT_PUBLIC_APP_CONTENT_PLUGIN_MANIFEST_H_
diff --git a/content/public/app/content_renderer_manifest.cc b/content/public/app/content_renderer_manifest.cc new file mode 100644 index 0000000..798614df --- /dev/null +++ b/content/public/app/content_renderer_manifest.cc
@@ -0,0 +1,86 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/app/content_renderer_manifest.h" + +#include "base/no_destructor.h" +#include "content/public/app/v8_snapshot_overlay_manifest.h" +#include "content/public/common/service_names.mojom.h" +#include "services/service_manager/public/cpp/manifest_builder.h" + +namespace content { + +const service_manager::Manifest& GetContentRendererManifest() { + static base::NoDestructor<service_manager::Manifest> manifest{ + service_manager::ManifestBuilder() + .WithServiceName(mojom::kRendererServiceName) + .WithDisplayName("Content (renderer process)") + .ExposeCapability("service_manager:service_factory", + std::set<const char*>{ + "service_manager.mojom.ServiceFactory", + }) + .ExposeCapability( + "browser", + std::set<const char*>{ + "blink.mojom.AppCacheFrontend", + "blink.mojom.CodeCacheHost", + "blink.mojom.CrashMemoryMetricsReporter", + "blink.mojom.LeakDetector", + "blink.mojom.OomIntervention", + "blink.mojom.WebDatabase", + "content.mojom.Child", + "content.mojom.ChildControl", + "content.mojom.ChildHistogramFetcher", + "content.mojom.ChildHistogramFetcherFactory", + "content.mojom.FrameFactory", + "content.mojom.RenderWidgetWindowTreeClientFactory", + "content.mojom.ResourceUsageReporter", + "content.mojom.SharedWorkerFactory", + "IPC.mojom.ChannelBootstrap", + "visitedlink.mojom.VisitedLinkNotificationSink", + "web_cache.mojom.WebCache", + }) + .RequireCapability("font_service", "font_service") + .RequireCapability("*", "app") + .RequireCapability("metrics", "url_keyed_metrics") + .RequireCapability("ui", "discardable_memory") + .RequireCapability("ui", "gpu_client") + .RequireCapability("device", "device:power_monitor") + .RequireCapability("device", "device:screen_orientation") + .RequireCapability("device", "device:time_zone_monitor") + .RequireCapability(mojom::kBrowserServiceName, "dwrite_font_proxy") + .RequireCapability(mojom::kBrowserServiceName, "field_trials") + .RequireCapability(mojom::kBrowserServiceName, "renderer") + .RequireCapability(mojom::kBrowserServiceName, "sandbox_support") + .RequireInterfaceFilterCapability_Deprecated( + mojom::kBrowserServiceName, "navigation:shared_worker", + "renderer") + .RequireInterfaceFilterCapability_Deprecated( + mojom::kBrowserServiceName, "navigation:dedicated_worker", + "renderer") + .RequireInterfaceFilterCapability_Deprecated( + mojom::kBrowserServiceName, "navigation:service_worker", + "renderer") + .ExposeInterfaceFilterCapability_Deprecated( + "navigation:frame", "browser", + std::set<const char*>{ + "blink.mojom.AppBannerController", + "blink.mojom.EngagementClient", + "blink.mojom.InstallationService", + "blink.mojom.ManifestManager", + "blink.mojom.MediaDevicesListener", + "blink.mojom.MediaStreamDeviceObserver", + "blink.mojom.TextSuggestionBackend", + "content.mojom.ImageDownloader", + "content.mojom.FrameInputHandler", + "content.mojom.FullscreenVideoElementHandler", + "content.mojom.Widget", "viz.mojom.InputTargetClient"}) + .RequireInterfaceFilterCapability_Deprecated( + mojom::kBrowserServiceName, "navigation:frame", "renderer") + .Build() + .Amend(GetV8SnapshotOverlayManifest())}; + return *manifest; +} + +} // namespace content
diff --git a/content/public/app/content_renderer_manifest.h b/content/public/app/content_renderer_manifest.h new file mode 100644 index 0000000..3c06e50e --- /dev/null +++ b/content/public/app/content_renderer_manifest.h
@@ -0,0 +1,20 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_APP_CONTENT_RENDERER_MANIFEST_H_ +#define CONTENT_PUBLIC_APP_CONTENT_RENDERER_MANIFEST_H_ + +#include "services/service_manager/public/cpp/manifest.h" + +namespace content { + +// Returns the service manifest for the "content_renderer" service. Every +// renderer process is an instance of this service, so this manifest determines +// what capabilities are directly exposed and required by renderer processes +// through the Service Manager. +const service_manager::Manifest& GetContentRendererManifest(); + +} // namespace content + +#endif // CONTENT_PUBLIC_APP_CONTENT_RENDERER_MANIFEST_H_
diff --git a/content/public/app/content_utility_manifest.cc b/content/public/app/content_utility_manifest.cc new file mode 100644 index 0000000..cef3e43c --- /dev/null +++ b/content/public/app/content_utility_manifest.cc
@@ -0,0 +1,48 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/app/content_utility_manifest.h" + +#include "base/no_destructor.h" +#include "content/public/app/v8_snapshot_overlay_manifest.h" +#include "content/public/common/service_names.mojom.h" +#include "services/service_manager/public/cpp/manifest_builder.h" + +namespace content { + +const service_manager::Manifest& GetContentUtilityManifest() { + static base::NoDestructor<service_manager::Manifest> manifest{ + service_manager::ManifestBuilder() + .WithServiceName(mojom::kUtilityServiceName) + .WithDisplayName("Content (utility process)") + .ExposeCapability("service_manager:service_factory", + std::set<const char*>{ + "service_manager.mojom.ServiceFactory", + }) + .ExposeCapability("browser", + std::set<const char*>{ + "content.mojom.Child", + "content.mojom.ChildControl", + "content.mojom.ChildHistogramFetcher", + "content.mojom.ChildHistogramFetcherFactory", + "content.mojom.ResourceUsageReporter", + "IPC.mojom.ChannelBootstrap", + "printing.mojom.PdfToEmfConverterFactory", + "printing.mojom.PdfToPwgRasterConverter", + "service_manager.mojom.ServiceFactory", + }) + .RequireCapability("device", "device:power_monitor") + .RequireCapability("device", "device:time_zone_monitor") + .RequireCapability(mojom::kBrowserServiceName, "dwrite_font_proxy") + .RequireCapability(mojom::kBrowserServiceName, "field_trials") + .RequireCapability(mojom::kBrowserServiceName, "font_cache") + .RequireCapability(mojom::kBrowserServiceName, "sandbox_support") + .RequireCapability("*", "app") + .RequireCapability("font_service", "font_service") + .Build() + .Amend(GetV8SnapshotOverlayManifest())}; + return *manifest; +} + +} // namespace content
diff --git a/content/public/app/content_utility_manifest.h b/content/public/app/content_utility_manifest.h new file mode 100644 index 0000000..340b03b2 --- /dev/null +++ b/content/public/app/content_utility_manifest.h
@@ -0,0 +1,20 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_APP_CONTENT_UTILITY_MANIFEST_H_ +#define CONTENT_PUBLIC_APP_CONTENT_UTILITY_MANIFEST_H_ + +#include "services/service_manager/public/cpp/manifest.h" + +namespace content { + +// Returns the service manifest for the "content_utility" service. Every +// utility (i.e. out-of-process service) process is an instance of this service, +// so this manifest determines what capabilities are directly exposed and +// required by service processes. +const service_manager::Manifest& GetContentUtilityManifest(); + +} // namespace content + +#endif // CONTENT_PUBLIC_APP_CONTENT_UTILITY_MANIFEST_H_
diff --git a/content/public/app/mojo/OWNERS b/content/public/app/mojo/OWNERS deleted file mode 100644 index 79cfaba..0000000 --- a/content/public/app/mojo/OWNERS +++ /dev/null
@@ -1,17 +0,0 @@ -per-file content_browser_manifest.json=set noparent -per-file content_browser_manifest.json=file://ipc/SECURITY_OWNERS - -per-file content_gpu_manifest.json=set noparent -per-file content_gpu_manifest.json=file://ipc/SECURITY_OWNERS - -per-file content_packaged_services_manifest.json=set noparent -per-file content_packaged_services_manifest.json=file://ipc/SECURITY_OWNERS - -per-file content_plugin_manifest.json=set noparent -per-file content_plugin_manifest.json=file://ipc/SECURITY_OWNERS - -per-file content_renderer_manifest.json=set noparent -per-file content_renderer_manifest.json=file://ipc/SECURITY_OWNERS - -per-file content_utility_manifest.json=set noparent -per-file content_utility_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json deleted file mode 100644 index 08bd560..0000000 --- a/content/public/app/mojo/content_browser_manifest.json +++ /dev/null
@@ -1,296 +0,0 @@ -{ - "name": "content_browser", - "display_name": "Content (browser process)", - "options": { - "can_connect_to_other_services_as_any_user": true, - "can_connect_to_other_services_with_any_instance_name": true, - "can_create_other_service_instances": true - }, - "interface_provider_specs": { - "service_manager:connector": { - "provides": { - // Interfaces needed by a generic client of content browser. - "app": [ - "discardable_memory.mojom.DiscardableSharedMemoryManager", - "memory_instrumentation.mojom.Coordinator" - ], - "dwrite_font_proxy": [ - "blink.mojom.DWriteFontProxy" - ], - "field_trials": [ - "content.mojom.FieldTrialRecorder" - ], - "font_cache": [ - "content.mojom.FontCacheWin" - ], - "gpu": [ - "discardable_memory.mojom.DiscardableSharedMemoryManager", - "media.mojom.AndroidOverlayProvider" - ], - "gpu_client": [ - "ws.mojom.Gpu" - ], - "plugin": [ - "discardable_memory.mojom.DiscardableSharedMemoryManager", - "ws.mojom.Gpu" - ], - "renderer": [ - "blink.mojom.AppCacheBackend", - "blink.mojom.BackgroundSyncService", - "blink.mojom.BlobRegistry", - "blink.mojom.BroadcastChannelProvider", - "blink.mojom.ClipboardHost", - "blink.mojom.CodeCacheHost", - "blink.mojom.FontUniqueNameLookup", - "blink.mojom.EmbeddedFrameSinkProvider", - "blink.mojom.FileUtilitiesHost", - "blink.mojom.FileSystemManager", - "blink.mojom.Hyphenation", - "blink.mojom.MediaStreamTrackMetricsHost", - "blink.mojom.MimeRegistry", - "blink.mojom.PluginRegistry", - "blink.mojom.ReportingServiceProxy", - "blink.mojom.StoragePartitionService", - "blink.mojom.WebDatabaseHost", - "content.mojom.ClipboardHost", - "content.mojom.FieldTrialRecorder", - "content.mojom.FrameSinkProvider", - "content.mojom.PeerConnectionTrackerHost", - "content.mojom.PushMessaging", - "content.mojom.RendererHost", - "content.mojom.ReportingServiceProxy", - "content.mojom.ServiceWorkerDispatcherHost", - "content.mojom.WorkerURLLoaderFactoryProvider", - "device.mojom.BatteryMonitor", - "device.mojom.GamepadHapticsManager", - "discardable_memory.mojom.DiscardableSharedMemoryManager", - "media.mojom.KeySystemSupport", - "media.mojom.InterfaceFactory", - "media.mojom.VideoCaptureHost", - "media.mojom.VideoDecodePerfHistory", - "metrics.mojom.SingleSampleMetricsProvider", - "midi.mojom.MidiSessionProvider", - "network.mojom.P2PSocketManager", - "network.mojom.MdnsResponder", - "network.mojom.URLLoaderFactory", - "resource_coordinator.mojom.ProcessCoordinationUnit", - "viz.mojom.CompositingModeReporter", - "ws.mojom.Gpu" - ], - "sandbox_support": [ - "content.mojom.SandboxSupportMac" - ], - "service_manager:service_factory": [ - "service_manager.mojom.ServiceFactory" - ] - }, - "requires": { - "*": [ "app" ], - "audio": [ - "info", - "debug_recording", - "device_notifier", - "log_factory_manager", - "stream_factory", - "testing_api" - ], - "cdm": [ "media:cdm" ], - "chromecast": [ "multizone" ], - "content": [ "navigation" ], - "content_gpu": [ "browser" ], - "content_plugin": [ "browser" ], - "content_renderer": [ "browser" ], - "content_utility": [ "browser" ], - "data_decoder": [ "image_decoder", "json_parser", "xml_parser" ], - "device": [ - "device:battery_monitor", - "device:bluetooth_system", - "device:generic_sensor", - "device:geolocation", - "device:hid", - "device:input_service", - "device:mtp", - "device:nfc", - "device:serial", - "device:usb", - "device:usb_test", - "device:vibration", - "device:wake_lock" - ], - "file": [ "file:filesystem", "file:leveldb" ], - "media": [ "media:media" ], - "media_session": [ "media_session:app" ], - "metrics": [ "url_keyed_metrics" ], - "network": [ - "network_service", - "test", - "url_loader" - ], - "patch_service": [ "patch_file" ], - "resource_coordinator": [ - "coordination_unit", - "coordination_unit_introspector", - "service_callbacks", - "page_signal" - ], - "service_manager": [ - "service_manager:service_manager" - ], - "shape_detection": [ - "barcode_detection", - "face_detection", - "text_detection" - ], - "tracing": [ - "tracing" - ], - "ui": [ "arc_manager" ], - "unzip_service": [ "unzip_file" ], - "video_capture": [ "capture", "tests" ] - } - }, - "navigation:frame": { - "provides": { - "renderer": [ - // TODO(beng): these belong in //chrome's overlay, but there are some - // issues with mash browser_tests's manifest config that make this - // impossible this week. Remove once sky/ken fix this. - "autofill.mojom.AutofillDriver", - "autofill.mojom.PasswordManagerDriver", - "blink.mojom.AnchorElementMetricsHost", - "blink.mojom.AudioContextManager", - "blink.mojom.Authenticator", - "blink.mojom.BackgroundFetchService", - "blink.mojom.CacheStorage", - "blink.mojom.ColorChooserFactory", - "blink.mojom.ContactsManager", - "blink.mojom.CredentialManager", - "blink.mojom.DisplayCutoutHost", - "blink.mojom.DedicatedWorkerFactory", - "blink.mojom.FileChooser", - "blink.mojom.FileSystemManager", - "blink.mojom.GeolocationService", - "blink.mojom.IDBFactory", - "blink.mojom.IdleManager", - "blink.mojom.InsecureInputService", - "blink.mojom.KeyboardLockService", - "blink.mojom.LockManager", - "blink.mojom.MediaDevicesDispatcherHost", - "blink.mojom.MediaStreamDispatcherHost", - "blink.mojom.MediaSessionService", - "blink.mojom.NotificationService", - "blink.mojom.PermissionService", - "blink.mojom.Portal", - "blink.mojom.PrefetchURLLoaderService", - "blink.mojom.PresentationService", - "blink.mojom.QuotaDispatcherHost", - "blink.mojom.SerialService", - "blink.mojom.SharedWorkerConnector", - "blink.mojom.SpeechRecognizer", - "blink.mojom.TextSuggestionHost", - "blink.mojom.UnhandledTapNotifier", - "blink.mojom.WakeLockService", - "blink.mojom.WebBluetoothService", - "blink.mojom.WebUsbService", - "blink.test.mojom.VirtualAuthenticatorManager", - - - // TODO(beng): figure out how to overlay test interfaces like this. - "content.mojom.BrowserTarget", - - // InputInjector is only exposed when gpu benchmarking is enabled. - "content.mojom.InputInjector", - - "content.mojom.RendererAudioInputStreamFactory", - "content.mojom.RendererAudioOutputStreamFactory", - "device.mojom.GamepadMonitor", - "device.mojom.Geolocation", - "device.mojom.NFC", - "device.mojom.SensorProvider", - "device.mojom.VibrationManager", - "device.mojom.VRService", - "device.mojom.WakeLock", - "discardable_memory.mojom.DiscardableSharedMemoryManager", - "media.mojom.ImageCapture", - "media.mojom.InterfaceFactory", - "media.mojom.MediaMetricsProvider", - "media.mojom.RemoterFactory", - "media.mojom.Renderer", - "mojom.ProcessInternalsHandler", - "network.mojom.RestrictedCookieManager", - "network.mojom.WebSocket", - "payments.mojom.PaymentManager", - "payments.mojom.PaymentRequest", - "resource_coordinator.mojom.FrameCoordinationUnit", - "shape_detection.mojom.BarcodeDetectionProvider", - "shape_detection.mojom.FaceDetectionProvider", - "shape_detection.mojom.TextDetection", - "ws.mojom.Gpu" - ] - }, - "requires": { - "content_renderer": [ "browser" ] - } - }, - "navigation:dedicated_worker": { - "provides": { - "renderer": [ - "blink.mojom.CacheStorage", - "blink.mojom.DedicatedWorkerFactory", - "blink.mojom.FileSystemManager", - "blink.mojom.IDBFactory", - "blink.mojom.IdleManager", - "blink.mojom.LockManager", - "blink.mojom.NotificationService", - "blink.mojom.PermissionService", - "blink.mojom.QuotaDispatcherHost", - "blink.mojom.SerialService", - "blink.mojom.WebUsbService", - "network.mojom.WebSocket", - "payments.mojom.PaymentManager", - "shape_detection.mojom.BarcodeDetectionProvider", - "shape_detection.mojom.FaceDetectionProvider", - "shape_detection.mojom.TextDetection" - ] - } - }, - "navigation:service_worker": { - "provides": { - "renderer": [ - "blink.mojom.BackgroundFetchService", - "blink.mojom.CacheStorage", - "blink.mojom.CookieStore", - "blink.mojom.IDBFactory", - "blink.mojom.LockManager", - "blink.mojom.NotificationService", - "blink.mojom.PermissionService", - "blink.mojom.QuotaDispatcherHost", - "network.mojom.RestrictedCookieManager", - "network.mojom.WebSocket", - "payments.mojom.PaymentManager", - "shape_detection.mojom.BarcodeDetectionProvider", - "shape_detection.mojom.FaceDetectionProvider", - "shape_detection.mojom.TextDetection" - ] - } - }, - "navigation:shared_worker": { - "provides": { - "renderer": [ - "blink.mojom.CacheStorage", - "blink.mojom.FileSystemManager", - "blink.mojom.IDBFactory", - "blink.mojom.LockManager", - "blink.mojom.NotificationService", - "blink.mojom.PermissionService", - "blink.mojom.QuotaDispatcherHost", - "network.mojom.WebSocket", - "payments.mojom.PaymentManager", - "shape_detection.mojom.BarcodeDetectionProvider", - "shape_detection.mojom.FaceDetectionProvider", - "shape_detection.mojom.TextDetection" - ] - } - } - } -}
diff --git a/content/public/app/mojo/content_gpu_manifest.json b/content/public/app/mojo/content_gpu_manifest.json deleted file mode 100644 index 9c09b9b..0000000 --- a/content/public/app/mojo/content_gpu_manifest.json +++ /dev/null
@@ -1,39 +0,0 @@ -{ - "name": "content_gpu", - "display_name": "Content (GPU process)", - "interface_provider_specs": { - "service_manager:connector": { - "provides": { - "browser": [ - "content.mojom.Child", - "content.mojom.ChildControl", - "content.mojom.ChildHistogramFetcher", - "content.mojom.ChildHistogramFetcherFactory", - "content.mojom.ResourceUsageReporter", - "IPC.mojom.ChannelBootstrap", - "service_manager.mojom.ServiceFactory", - "ui.ozone.mojom.DeviceCursor", - "ui.ozone.mojom.DrmDevice", - "ui.ozone.mojom.WaylandConnectionClient", - "ui.mojom.ScenicGpuService", - "viz.mojom.CompositingModeReporter", - "viz.mojom.VizMain" - ], - "service_manager:service_factory": [ - "service_manager.mojom.ServiceFactory" - ] - }, - "requires": { - "*": [ "app" ], - "content_browser": [ - "dwrite_font_proxy", - "field_trials", - "gpu" - ], - "device": [ "device:power_monitor" ], - "metrics": [ "url_keyed_metrics" ], - "ui": [ "discardable_memory" ] - } - } - } -}
diff --git a/content/public/app/mojo/content_packaged_services_manifest.json b/content/public/app/mojo/content_packaged_services_manifest.json deleted file mode 100644 index ce69bd3..0000000 --- a/content/public/app/mojo/content_packaged_services_manifest.json +++ /dev/null
@@ -1,29 +0,0 @@ -// Primordial service for the browser process. This is a singleton service which -// acts as a runtime ServiceFactory for other packaged global services exposed -// at or below the content layer. -// -// Note that this is only for packaging services which do not require user -// profile context. Services which require user profile context must instead be -// packaged within the content_browser service. -{ - "name": "content_packaged_services", - "display_name": "Content Packaged Services", - "options" : { - "instance_sharing" : "singleton", - "can_connect_to_other_services_as_any_user": true, - "can_create_other_service_instances": true - }, - "interface_provider_specs": { - "service_manager:connector": { - "provides": { - "service_manager:service_factory": [ - "service_manager.mojom.ServiceFactory" - ] - }, - "requires": { - "*": [ "app" ], - "content_browser": [] - } - } - } -}
diff --git a/content/public/app/mojo/content_plugin_manifest.json b/content/public/app/mojo/content_plugin_manifest.json deleted file mode 100644 index faa6fd9..0000000 --- a/content/public/app/mojo/content_plugin_manifest.json +++ /dev/null
@@ -1,34 +0,0 @@ -{ - "name": "content_plugin", - "display_name": "Content (plugin process)", - "interface_provider_specs": { - "service_manager:connector": { - "provides": { - "browser": [ - "content.mojom.Child", - "content.mojom.ChildControl", - "content.mojom.ChildHistogramFetcher", - "content.mojom.ChildHistogramFetcherFactory", - "content.mojom.ResourceUsageReporter", - "IPC.mojom.ChannelBootstrap" - ], - "service_manager:service_factory": [ - "service_manager.mojom.ServiceFactory" - ] - }, - "requires": { - "*": [ "app" ], - "content_browser": [ - "dwrite_font_proxy", - "field_trials", - "font_cache", - "plugin", - "sandbox_support" - ], - "device": [ "device:power_monitor" ], - "font_service": [ "font_service" ], - "ui": [ "discardable_memory" ] - } - } - } -}
diff --git a/content/public/app/mojo/content_renderer_manifest.json b/content/public/app/mojo/content_renderer_manifest.json deleted file mode 100644 index 922b8c9..0000000 --- a/content/public/app/mojo/content_renderer_manifest.json +++ /dev/null
@@ -1,100 +0,0 @@ -{ - "name": "content_renderer", - "display_name": "Content (renderer process)", - "interface_provider_specs": { - "service_manager:connector": { - "provides": { - "browser": [ - "blink.mojom.AppCacheFrontend", - "blink.mojom.CodeCacheHost", - "blink.mojom.CrashMemoryMetricsReporter", - "blink.mojom.LeakDetector", - "blink.mojom.OomIntervention", - "blink.mojom.WebDatabase", - "content.mojom.Child", - "content.mojom.ChildControl", - "content.mojom.ChildHistogramFetcher", - "content.mojom.ChildHistogramFetcherFactory", - "content.mojom.FrameFactory", - "content.mojom.RenderWidgetWindowTreeClientFactory", - "content.mojom.ResourceUsageReporter", - "content.mojom.SharedWorkerFactory", - "IPC.mojom.ChannelBootstrap", - "visitedlink.mojom.VisitedLinkNotificationSink", - "web_cache.mojom.WebCache" - ], - "service_manager:service_factory": [ - "service_manager.mojom.ServiceFactory" - ] - }, - "requires": { - "*": [ "app" ], - "content_browser": [ - "dwrite_font_proxy", - "field_trials", - "renderer", - "sandbox_support" - ], - "font_service": [ "font_service" ], - "metrics": [ "url_keyed_metrics" ], - "device": [ - "device:power_monitor", - "device:screen_orientation", - "device:time_zone_monitor" - ], - "ui": [ - "discardable_memory", - "gpu_client" - ] - } - }, - "navigation:frame": { - "provides": { - "browser": [ - "blink.mojom.AppBannerController", - "blink.mojom.EngagementClient", - "blink.mojom.InstallationService", - "blink.mojom.ManifestManager", - "blink.mojom.MediaDevicesListener", - "blink.mojom.MediaStreamDeviceObserver", - "blink.mojom.TextSuggestionBackend", - "content.mojom.ImageDownloader", - "content.mojom.FrameInputHandler", - "content.mojom.FullscreenVideoElementHandler", - "content.mojom.Widget", - "viz.mojom.InputTargetClient" - ] - }, - "requires": { - "content_browser": [ "renderer" ] - } - }, - "navigation:dedicated_worker": { - "requires": { - "content_browser": [ "renderer" ] - } - }, - "navigation:service_worker": { - "requires": { - "content_browser": [ "renderer" ] - } - }, - "navigation:shared_worker": { - "requires": { - "content_browser": [ "renderer" ] - } - } - }, - "required_files" : { - "v8_natives_data" : [ - { - "path": "natives_blob.bin", - "platform": "linux" - }, - { - "path": "assets/natives_blob.bin", - "platform": "android" - } - ] - } -}
diff --git a/content/public/app/mojo/content_utility_manifest.json b/content/public/app/mojo/content_utility_manifest.json deleted file mode 100644 index bb410686..0000000 --- a/content/public/app/mojo/content_utility_manifest.json +++ /dev/null
@@ -1,50 +0,0 @@ -{ - "name": "content_utility", - "display_name": "Content (utility process)", - "interface_provider_specs": { - "service_manager:connector": { - "provides": { - "browser": [ - "content.mojom.Child", - "content.mojom.ChildControl", - "content.mojom.ChildHistogramFetcher", - "content.mojom.ChildHistogramFetcherFactory", - "content.mojom.ResourceUsageReporter", - "IPC.mojom.ChannelBootstrap", - "printing.mojom.PdfToEmfConverterFactory", - "printing.mojom.PdfToPwgRasterConverter", - "service_manager.mojom.ServiceFactory" - ], - "service_manager:service_factory": [ - "service_manager.mojom.ServiceFactory" - ] - }, - "requires": { - "*": [ "app" ], - "content_browser": [ - "dwrite_font_proxy", - "field_trials", - "font_cache", - "sandbox_support" - ], - "device": [ - "device:power_monitor", - "device:time_zone_monitor" - ], - "font_service": [ "font_service" ] - } - } - }, - "required_files" : { - "v8_natives_data" : [ - { - "path": "natives_blob.bin", - "platform": "linux" - }, - { - "path": "assets/natives_blob.bin", - "platform": "android" - } - ] - } -}
diff --git a/content/public/app/mojo/context_snapshot_manifest.json b/content/public/app/mojo/context_snapshot_manifest.json deleted file mode 100644 index 8849750..0000000 --- a/content/public/app/mojo/context_snapshot_manifest.json +++ /dev/null
@@ -1,16 +0,0 @@ -{ - "required_files" : { - "v8_context_snapshot_data" : [{ - "path": "v8_context_snapshot.bin", - "platform": "linux" - }], - "v8_snapshot_32_data" : [{ - "path": "assets/v8_context_snapshot_32.bin", - "platform": "android" - }], - "v8_snapshot_64_data" : [{ - "path": "assets/v8_context_snapshot_64.bin", - "platform": "android" - }] - } -}
diff --git a/content/public/app/mojo/snapshot_blob_manifest.json b/content/public/app/mojo/snapshot_blob_manifest.json deleted file mode 100644 index 552e18a..0000000 --- a/content/public/app/mojo/snapshot_blob_manifest.json +++ /dev/null
@@ -1,16 +0,0 @@ -{ - "required_files" : { - "v8_snapshot_data" : [{ - "path": "snapshot_blob.bin", - "platform": "linux" - }], - "v8_snapshot_32_data" : [{ - "path": "assets/snapshot_blob_32.bin", - "platform": "android" - }], - "v8_snapshot_64_data" : [{ - "path": "assets/snapshot_blob_64.bin", - "platform": "android" - }] - } -}
diff --git a/content/public/app/v8_snapshot_overlay_manifest.cc b/content/public/app/v8_snapshot_overlay_manifest.cc new file mode 100644 index 0000000..46977557 --- /dev/null +++ b/content/public/app/v8_snapshot_overlay_manifest.cc
@@ -0,0 +1,54 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/app/v8_snapshot_overlay_manifest.h" + +#include "base/files/file_path.h" +#include "base/no_destructor.h" +#include "build/build_config.h" +#include "content/public/common/content_descriptor_keys.h" +#include "services/service_manager/public/cpp/manifest_builder.h" + +namespace content { + +const service_manager::Manifest& GetV8SnapshotOverlayManifest() { + static base::NoDestructor<service_manager::Manifest> manifest { + service_manager::ManifestBuilder() +#if defined(OS_LINUX) + .PreloadFile(kV8NativesDataDescriptor, + base::FilePath(FILE_PATH_LITERAL("natives_blob.bin"))) +#if defined(USE_V8_CONTEXT_SNAPSHOT) + .PreloadFile( + kV8ContextSnapshotDataDescriptor, + base::FilePath(FILE_PATH_LITERAL("v8_context_snapshot.bin"))) +#else + .PreloadFile(kV8SnapshotDataDescriptor, + base::FilePath(FILE_PATH_LITERAL("snapshot_blob.bin"))) +#endif // defined(USE_V8_CONTEXT_SNAPSHOT) +#elif defined(OS_ANDROID) + .PreloadFile( + kV8NativesDataDescriptor, + base::FilePath(FILE_PATH_LITERAL("assets/natives_blob.bin"))) +#if defined(USE_V8_CONTEXT_SNAPSHOT) + .PreloadFile(kV8Snapshot32DataDescriptor, + base::FilePath(FILE_PATH_LITERAL( + "assets/v8_context_snapshot_32.bin"))) + .PreloadFile(kV8Snapshot64DataDescriptor, + base::FilePath(FILE_PATH_LITERAL( + "assets/v8_context_snapshot_64.bin"))) +#else + .PreloadFile( + kV8Snapshot32DataDescriptor, + base::FilePath(FILE_PATH_LITERAL("assets/snapshot_blob_32.bin"))) + .PreloadFile( + kV8Snapshot64DataDescriptor, + base::FilePath(FILE_PATH_LITERAL("assets/snapshot_blob_64.bin"))) +#endif // defined(USE_V8_CONTEXT_SNAPSHOT) +#endif + .Build() + }; + return *manifest; +} + +} // namespace content
diff --git a/content/public/app/v8_snapshot_overlay_manifest.h b/content/public/app/v8_snapshot_overlay_manifest.h new file mode 100644 index 0000000..b06375f --- /dev/null +++ b/content/public/app/v8_snapshot_overlay_manifest.h
@@ -0,0 +1,19 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_APP_V8_SNAPSHOT_OVERLAY_MANIFEST_H_ +#define CONTENT_PUBLIC_APP_V8_SNAPSHOT_OVERLAY_MANIFEST_H_ + +#include "services/service_manager/public/cpp/manifest.h" + +namespace content { + +// Returns a service manifest overlay that should be amended to the manifest of +// any service which initializes V8. This gives the service access to preloaded +// snapshot files on startup. +const service_manager::Manifest& GetV8SnapshotOverlayManifest(); + +} // namespace content + +#endif // CONTENT_PUBLIC_APP_V8_SNAPSHOT_OVERLAY_MANIFEST_H_
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn index fb60c4e..916d52bc 100644 --- a/content/public/browser/BUILD.gn +++ b/content/public/browser/BUILD.gn
@@ -168,6 +168,8 @@ "media_capture_devices.h", "media_device_id.cc", "media_device_id.h", + "media_keys_listener_manager.cc", + "media_keys_listener_manager.h", "media_request_state.h", "media_session.h", "media_session_observer.cc",
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index bce9b68..abc9829 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -680,9 +680,9 @@ return base::nullopt; } -std::vector<ContentBrowserClient::ServiceManifestInfo> +std::vector<service_manager::Manifest> ContentBrowserClient::GetExtraServiceManifests() { - return std::vector<ContentBrowserClient::ServiceManifestInfo>(); + return std::vector<service_manager::Manifest>(); } std::vector<std::string> ContentBrowserClient::GetStartupServices() {
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 92425b0..694796b 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -1027,20 +1027,9 @@ virtual base::Optional<service_manager::Manifest> GetServiceManifestOverlay( base::StringPiece name); - struct ServiceManifestInfo { - // The name of the service. - std::string name; - - // The resource ID of a blob of manifest JSON. Used if not -1. - int resource_id; - - // A Manifest value to use if |resource_id| is -1. - service_manager::Manifest manifest; - }; - // Allows the embedder to provide extra service manifests to be registered // with the service manager context. - virtual std::vector<ServiceManifestInfo> GetExtraServiceManifests(); + virtual std::vector<service_manager::Manifest> GetExtraServiceManifests(); // Allows the embedder to have a list of services started after the // in-process Service Manager has been initialized.
diff --git a/content/public/browser/gpu_utils.cc b/content/public/browser/gpu_utils.cc index a02ca09..34212d7 100644 --- a/content/public/browser/gpu_utils.cc +++ b/content/public/browser/gpu_utils.cc
@@ -57,6 +57,8 @@ #else if (!base::FeatureList::IsEnabled(features::kVizDisplayCompositor)) return false; + if (!base::FeatureList::IsEnabled(features::kAImageReaderMediaPlayer)) + return false; return base::FeatureList::IsEnabled(features::kAndroidSurfaceControl); #endif
diff --git a/content/public/browser/media_keys_listener_manager.cc b/content/public/browser/media_keys_listener_manager.cc new file mode 100644 index 0000000..36d756ba --- /dev/null +++ b/content/public/browser/media_keys_listener_manager.cc
@@ -0,0 +1,11 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/browser/media_keys_listener_manager.h" + +namespace content { + +MediaKeysListenerManager::~MediaKeysListenerManager() = default; + +} // namespace content
diff --git a/content/public/browser/media_keys_listener_manager.h b/content/public/browser/media_keys_listener_manager.h new file mode 100644 index 0000000..3f5a270 --- /dev/null +++ b/content/public/browser/media_keys_listener_manager.h
@@ -0,0 +1,63 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_BROWSER_MEDIA_KEYS_LISTENER_MANAGER_H_ +#define CONTENT_PUBLIC_BROWSER_MEDIA_KEYS_LISTENER_MANAGER_H_ + +#include "content/common/content_export.h" +#include "ui/base/accelerators/media_keys_listener.h" +#include "ui/events/keycodes/keyboard_codes.h" + +namespace content { + +// The browser listens for media keys and uses them to control the active media +// session. However, there are cases where this behavior is undesirable, for +// example when an extension wants to handle media key presses instead. This +// class provides an interface for code outside of content (e.g. extensions) to +// receive global media key input instead of allowing the browser to use it to +// control the active session. +class MediaKeysListenerManager { + public: + // Returns the singleton instance. + CONTENT_EXPORT static MediaKeysListenerManager* GetInstance(); + + // Start listening for a given media key. Returns true if the listener + // successfully started listening for the key. This will prevent the + // HardwareKeyMediaController from also handling the specified key. + // Note: Delegates *must* call |StopWatchingMediaKey()| for each key code + // they're listening to before destruction in order to prevent the + // MediaKeysListenerManager from holding invalid pointers. + virtual bool StartWatchingMediaKey( + ui::KeyboardCode key_code, + ui::MediaKeysListener::Delegate* delegate) = 0; + + // Stop listening for a given media key. This will free the key to be handled + // by the HardwareKeyMediaController. Delegates must stop watching all keys + // before they are destroyed in order to prevent the MediaKeysListenerManager + // from holding invalid pointers. + virtual void StopWatchingMediaKey( + ui::KeyboardCode key_code, + ui::MediaKeysListener::Delegate* delegate) = 0; + + // Prevent the browser from using media key presses to control the active + // media session. This allows a caller to prevent the media key handling + // without registering to receive the key events. Note that this does not + // prevent callers of |StartWatchingMediaKey()| from receiving media key + // events. This does not need to be called if |StartWatchingMediaKey()| is + // used, since |StartWatchingMediaKey()| will automatically prevent the + // browser from using the media key presses. + virtual void DisableInternalMediaKeyHandling() = 0; + + // Allows the browser to use media key presses to control the active media. + // Only needs to be called if a call to |DisableInternalMediaKeyHandling()| + // has been made. + virtual void EnableInternalMediaKeyHandling() = 0; + + protected: + virtual ~MediaKeysListenerManager(); +}; + +} // namespace content + +#endif // CONTENT_PUBLIC_BROWSER_MEDIA_KEYS_LISTENER_MANAGER_H_ \ No newline at end of file
diff --git a/content/public/browser/navigation_controller.cc b/content/public/browser/navigation_controller.cc index 4a15053..28abe11 100644 --- a/content/public/browser/navigation_controller.cc +++ b/content/public/browser/navigation_controller.cc
@@ -25,7 +25,8 @@ should_clear_history_list(false), started_from_context_menu(false), navigation_ui_data(nullptr), - was_activated(WasActivatedOption::kUnknown) {} + was_activated(WasActivatedOption::kUnknown), + reload_type(ReloadType::NONE) {} NavigationController::LoadURLParams::~LoadURLParams() { }
diff --git a/content/public/browser/navigation_controller.h b/content/public/browser/navigation_controller.h index 66353e2..db1320d 100644 --- a/content/public/browser/navigation_controller.h +++ b/content/public/browser/navigation_controller.h
@@ -215,6 +215,9 @@ // language code). Empty otherwise. std::string href_translate; + // Indicates the reload type of this navigation. + ReloadType reload_type = ReloadType::NONE; + explicit LoadURLParams(const GURL& url); ~LoadURLParams();
diff --git a/content/public/browser/page_navigator.cc b/content/public/browser/page_navigator.cc index c16b602..52a5829 100644 --- a/content/public/browser/page_navigator.cc +++ b/content/public/browser/page_navigator.cc
@@ -21,7 +21,8 @@ should_replace_current_entry(false), user_gesture(!is_renderer_initiated), started_from_context_menu(false), - open_app_window_if_possible(false) {} + open_app_window_if_possible(false), + reload_type(ReloadType::NONE) {} OpenURLParams::OpenURLParams(const GURL& url, const Referrer& referrer, @@ -39,7 +40,8 @@ should_replace_current_entry(false), user_gesture(!is_renderer_initiated), started_from_context_menu(started_from_context_menu), - open_app_window_if_possible(false) {} + open_app_window_if_possible(false), + reload_type(ReloadType::NONE) {} OpenURLParams::OpenURLParams(const GURL& url, const Referrer& referrer, @@ -57,7 +59,8 @@ should_replace_current_entry(false), user_gesture(!is_renderer_initiated), started_from_context_menu(false), - open_app_window_if_possible(false) {} + open_app_window_if_possible(false), + reload_type(ReloadType::NONE) {} OpenURLParams::OpenURLParams() : uses_post(false), @@ -68,7 +71,8 @@ should_replace_current_entry(false), user_gesture(true), started_from_context_menu(false), - open_app_window_if_possible(false) {} + open_app_window_if_possible(false), + reload_type(ReloadType::NONE) {} OpenURLParams::OpenURLParams(const OpenURLParams& other) = default;
diff --git a/content/public/browser/page_navigator.h b/content/public/browser/page_navigator.h index d387561..961896a 100644 --- a/content/public/browser/page_navigator.h +++ b/content/public/browser/page_navigator.h
@@ -15,6 +15,7 @@ #include "base/memory/ref_counted.h" #include "content/common/content_export.h" #include "content/public/browser/global_request_id.h" +#include "content/public/browser/reload_type.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/site_instance.h" #include "content/public/common/child_process_host.h" @@ -124,6 +125,9 @@ // language code). Empty otherwise. std::string href_translate; + // Indicates if this navigation is a reload. + ReloadType reload_type; + private: OpenURLParams(); };
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn index 6b6266cc..127664b 100644 --- a/content/public/common/BUILD.gn +++ b/content/public/common/BUILD.gn
@@ -365,13 +365,6 @@ sources += [ "font_cache_win.mojom" ] } - if (is_mac) { - sources += [ - "ns_view_bridge_factory.mojom", - "web_contents_ns_view_bridge.mojom", - ] - } - public_deps = [ ":resource_type_bindings", "//mojo/public/mojom/base:base", @@ -383,6 +376,14 @@ "//url/mojom:url_mojom_origin", ] + if (is_mac) { + sources += [ + "ns_view_bridge_factory.mojom", + "web_contents_ns_view_bridge.mojom", + ] + public_deps += [ "//ui/gfx/geometry/mojo" ] + } + component_output_prefix = "content_public_common_mojo_bindings" export_class_attribute = "CONTENT_EXPORT" export_define = "CONTENT_IMPLEMENTATION=1"
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h index 848a739..a902e8e 100644 --- a/content/public/common/common_param_traits_macros.h +++ b/content/public/common/common_param_traits_macros.h
@@ -165,6 +165,7 @@ IPC_STRUCT_TRAITS_MEMBER(strictly_block_blockable_mixed_content) IPC_STRUCT_TRAITS_MEMBER(block_mixed_plugin_content) IPC_STRUCT_TRAITS_MEMBER(enable_scroll_animator) + IPC_STRUCT_TRAITS_MEMBER(prefers_reduced_motion) IPC_STRUCT_TRAITS_MEMBER(password_echo_enabled) IPC_STRUCT_TRAITS_MEMBER(should_clear_document_background) IPC_STRUCT_TRAITS_MEMBER(touch_event_feature_detection_enabled)
diff --git a/content/public/common/content_descriptor_keys.h b/content/public/common/content_descriptor_keys.h index 80bccdf..bfe2b0ce 100644 --- a/content/public/common/content_descriptor_keys.h +++ b/content/public/common/content_descriptor_keys.h
@@ -9,10 +9,6 @@ // This is a list of global descriptor keys to be used with the // base::FileDescriptorStore object (see base/file_descriptor_store.h) -// -// Note that these keys are also used in -// content/public/app/mojo/content_renderer_manifest.json and should be kept in -// sync. extern const char kV8NativesDataDescriptor[]; extern const char kV8SnapshotDataDescriptor[];
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 1e624722..2b74bf36 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -524,10 +524,10 @@ base::FEATURE_DISABLED_BY_DEFAULT}; // Controls whether CTAP2 devices can communicate via the WebAuthentication API -// using pairingless BLE protocol on Windows. +// using pairingless BLE protocol. // https://w3c.github.io/webauthn -const base::Feature kWebAuthCableWin{"WebAuthenticationCableWin", - base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kWebAuthCable{"WebAuthenticationCable", + base::FEATURE_ENABLED_BY_DEFAULT}; // Controls whether AuthenticatorAttestationResponse contains a getTransports // member to return the set of transports supported by an authenticator.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index d02fcf89..81e3f56 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -118,7 +118,6 @@ CONTENT_EXPORT extern const base::Feature kWebAuth; CONTENT_EXPORT extern const base::Feature kWebAuthBle; CONTENT_EXPORT extern const base::Feature kWebAuthCable; -CONTENT_EXPORT extern const base::Feature kWebAuthCableWin; CONTENT_EXPORT extern const base::Feature kWebAuthGetTransports; CONTENT_EXPORT extern const base::Feature kWebContentsOcclusion; CONTENT_EXPORT extern const base::Feature kWebGLImageChromium;
diff --git a/content/public/common/service_names.mojom b/content/public/common/service_names.mojom index 7064122..86cf8c5 100644 --- a/content/public/common/service_names.mojom +++ b/content/public/common/service_names.mojom
@@ -5,33 +5,27 @@ module content.mojom; // The default service name the browser identifies as when connecting to -// the Service Manager. This must match the name in -// src/content/public/app/mojo/content_browser_manifest.json. +// the Service Manager. const string kBrowserServiceName = "content_browser"; // The default service name used to identify the gpu process when connecting it -// to the Service Manager. This must match the name in -// src/content/public/app/mojo/content_gpu_manifest.json. +// to the Service Manager. const string kGpuServiceName = "content_gpu"; // The service name used to identify the browser process's singleton service -// instance which packages other browser-wide services. this must match the name -// in src/content/public/app/mojo/content_packaged_services_manifest.json. +// instance which packages other browser-wide services. const string kPackagedServicesServiceName = "content_packaged_services"; // The default service name used to identify plugin processes when connecting -// them to the Service Manager. This must match the name in -// src/content/public/app/mojo/content_plugin_manifest.json. +// them to the Service Manager. const string kPluginServiceName = "content_plugin"; // The default service name used to identify render processes when connecting -// them to the Service Manager. This must match the name in -// src/content/public/app/mojo/content_renderer_manifest.json. +// them to the Service Manager. const string kRendererServiceName = "content_renderer"; // The default service name used to identify utility processes when connecting -// them to the Service Manager. This must match the name in -// src/content/public/app/mojo/content_utility_manifest.json. +// them to the Service Manager. const string kUtilityServiceName = "content_utility"; // The name for the network service running in the utility process.
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc index 9b2926f7..8ce9ab7 100644 --- a/content/public/common/web_preferences.cc +++ b/content/public/common/web_preferences.cc
@@ -121,6 +121,7 @@ should_print_backgrounds(false), should_clear_document_background(true), enable_scroll_animator(false), + prefers_reduced_motion(false), touch_event_feature_detection_enabled(false), touch_adjustment_enabled(true), pointer_events_max_touch_points(0),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h index 1e9d3ec1..12b30f3 100644 --- a/content/public/common/web_preferences.h +++ b/content/public/common/web_preferences.h
@@ -161,6 +161,7 @@ bool should_print_backgrounds; bool should_clear_document_background; bool enable_scroll_animator; + bool prefers_reduced_motion; bool touch_event_feature_detection_enabled; bool touch_adjustment_enabled; int pointer_events_max_touch_points;
diff --git a/content/public/test/nested_message_pump_android.cc b/content/public/test/nested_message_pump_android.cc index 4328e55..412b9e3 100644 --- a/content/public/test/nested_message_pump_android.cc +++ b/content/public/test/nested_message_pump_android.cc
@@ -98,7 +98,6 @@ env, g_message_handler_obj.Get()); CHECK(ret) << "Error running java message loop, tests will likely fail."; - base::ThreadRestrictions::ScopedAllowWait allow_wait; if (state_->delayed_work_time.is_null()) { state_->waitable_event.TimedWait(max_delay); } else {
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc index 143eaf0..f0231ca 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.cc +++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -115,14 +115,15 @@ case WebAXObjectAttribute::kAriaActiveDescendant: // TODO(dmazzoni): WebAXObject::ActiveDescendant currently returns // more information than the sparse interface does. + // ******** Why is this a TODO? ******** break; case WebAXObjectAttribute::kAriaDetails: dst_->AddIntAttribute(ax::mojom::IntAttribute::kDetailsId, value.AxID()); break; case WebAXObjectAttribute::kAriaErrorMessage: - dst_->AddIntAttribute(ax::mojom::IntAttribute::kErrormessageId, - value.AxID()); + // Use WebAXObject::ErrorMessage(), which provides both ARIA error + // messages as well as built-in HTML form validation messages. break; default: NOTREACHED(); @@ -693,6 +694,11 @@ src.AriaActiveDescendant().AxID()); } + if (!src.ErrorMessage().IsDetached()) { + dst->AddIntAttribute(ax::mojom::IntAttribute::kErrormessageId, + src.ErrorMessage().AxID()); + } + if (ui::IsHeading(dst->role) && src.HeadingLevel()) { dst->AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, src.HeadingLevel());
diff --git a/content/renderer/child_frame_compositing_helper.cc b/content/renderer/child_frame_compositing_helper.cc index 6bd5177..fda424e7 100644 --- a/content/renderer/child_frame_compositing_helper.cc +++ b/content/renderer/child_frame_compositing_helper.cc
@@ -27,24 +27,25 @@ DCHECK(child_frame_compositor_); } -ChildFrameCompositingHelper::~ChildFrameCompositingHelper() = default; +ChildFrameCompositingHelper::~ChildFrameCompositingHelper() { + if (crash_ui_layer_) + crash_ui_layer_->ClearClient(); +} void ChildFrameCompositingHelper::ChildFrameGone( const gfx::Size& frame_size_in_dip, float device_scale_factor) { surface_id_ = viz::SurfaceId(); - crashed_ = true; device_scale_factor_ = device_scale_factor; - auto crash_ui_layer = cc::PictureLayer::Create(this); - crash_ui_layer->SetMasksToBounds(true); + crash_ui_layer_ = cc::PictureLayer::Create(this); + crash_ui_layer_->SetMasksToBounds(true); + crash_ui_layer_->SetIsDrawable(true); bool prevent_contents_opaque_changes = false; bool is_surface_layer = false; - child_frame_compositor_->SetLayer(std::move(crash_ui_layer), - prevent_contents_opaque_changes, - is_surface_layer); - UpdateVisibility(true); + child_frame_compositor_->SetLayer( + crash_ui_layer_, prevent_contents_opaque_changes, is_surface_layer); } void ChildFrameCompositingHelper::SetSurfaceId( @@ -82,15 +83,15 @@ } gfx::Rect ChildFrameCompositingHelper::PaintableRegion() { - DCHECK(crashed_); - return gfx::Rect(child_frame_compositor_->GetLayer()->bounds()); + DCHECK(crash_ui_layer_); + return gfx::Rect(crash_ui_layer_->bounds()); } scoped_refptr<cc::DisplayItemList> ChildFrameCompositingHelper::PaintContentsToDisplayList( PaintingControlSetting) { - DCHECK(crashed_); - auto layer_size = child_frame_compositor_->GetLayer()->bounds(); + DCHECK(crash_ui_layer_); + auto layer_size = crash_ui_layer_->bounds(); auto display_list = base::MakeRefCounted<cc::DisplayItemList>(); display_list->StartPaint(); display_list->push<cc::DrawColorOp>(SK_ColorGRAY, SkBlendMode::kSrc);
diff --git a/content/renderer/child_frame_compositing_helper.h b/content/renderer/child_frame_compositing_helper.h index 7d9ca17..2615b9b 100644 --- a/content/renderer/child_frame_compositing_helper.h +++ b/content/renderer/child_frame_compositing_helper.h
@@ -17,6 +17,10 @@ #include "components/viz/common/surfaces/surface_id.h" #include "content/common/content_export.h" +namespace cc { +class PictureLayer; +} + namespace gfx { class Size; } @@ -57,7 +61,7 @@ ChildFrameCompositor* const child_frame_compositor_; viz::SurfaceId surface_id_; scoped_refptr<cc::SurfaceLayer> surface_layer_; - bool crashed_ = false; + scoped_refptr<cc::PictureLayer> crash_ui_layer_; float device_scale_factor_ = 1.f; DISALLOW_COPY_AND_ASSIGN(ChildFrameCompositingHelper);
diff --git a/content/renderer/compositor/layer_tree_view.h b/content/renderer/compositor/layer_tree_view.h index 1dc6c373..e41f457 100644 --- a/content/renderer/compositor/layer_tree_view.h +++ b/content/renderer/compositor/layer_tree_view.h
@@ -211,6 +211,8 @@ uint32_t frame_token, const gfx::PresentationFeedback& feedback) override; void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override; + void DidGenerateLocalSurfaceIdAllocation( + const viz::LocalSurfaceIdAllocation& allocation) override {} // cc::LayerTreeHostSingleThreadClient implementation. void DidSubmitCompositorFrame() override;
diff --git a/content/renderer/devtools/render_widget_screen_metrics_emulator.cc b/content/renderer/devtools/render_widget_screen_metrics_emulator.cc index dcab579..0b95e08 100644 --- a/content/renderer/devtools/render_widget_screen_metrics_emulator.cc +++ b/content/renderer/devtools/render_widget_screen_metrics_emulator.cc
@@ -139,8 +139,6 @@ const VisualProperties& params) { original_visual_properties_ = params; Apply(); - - delegate_->Redraw(); } void RenderWidgetScreenMetricsEmulator::OnUpdateWindowScreenRect(
diff --git a/content/renderer/devtools/render_widget_screen_metrics_emulator_delegate.h b/content/renderer/devtools/render_widget_screen_metrics_emulator_delegate.h index ac7c8e6..fdaadb8 100644 --- a/content/renderer/devtools/render_widget_screen_metrics_emulator_delegate.h +++ b/content/renderer/devtools/render_widget_screen_metrics_emulator_delegate.h
@@ -19,9 +19,6 @@ // delegate in order to transport emulation information across processes. class CONTENT_EXPORT RenderWidgetScreenMetricsEmulatorDelegate { public: - // Requests a full redraw of the contents of the renderer. - virtual void Redraw() = 0; - // Synchronize visual properties with the widget. virtual void SynchronizeVisualProperties( const VisualProperties& visual_properties) = 0;
diff --git a/content/renderer/media/android/media_player_renderer_client.cc b/content/renderer/media/android/media_player_renderer_client.cc index f1bd671..ace94bf 100644 --- a/content/renderer/media/android/media_player_renderer_client.cc +++ b/content/renderer/media/android/media_player_renderer_client.cc
@@ -173,4 +173,10 @@ client_->OnDurationChange(duration); } +void MediaPlayerRendererClient::OnRemotePlayStateChange( + media::MediaStatus::State state) { + // Only used with the FlingingRenderer. + NOTREACHED(); +} + } // namespace content
diff --git a/content/renderer/media/android/media_player_renderer_client.h b/content/renderer/media/android/media_player_renderer_client.h index 5e77567..f1593b8 100644 --- a/content/renderer/media/android/media_player_renderer_client.h +++ b/content/renderer/media/android/media_player_renderer_client.h
@@ -68,6 +68,7 @@ void OnVideoNaturalSizeChange(const gfx::Size& size) override; void OnVideoOpacityChange(bool opaque) override; void OnDurationChange(base::TimeDelta duration) override; + void OnRemotePlayStateChange(media::MediaStatus::State state) override; // Called on |compositor_task_runner_| whenever |stream_texture_wrapper_| has // a new frame.
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc index 03091a5..25abe66 100644 --- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc +++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -846,13 +846,15 @@ } void OnIceConnectionChange( + PeerConnectionInterface::IceConnectionState new_state) override {} + void OnStandardizedIceConnectionChange( + PeerConnectionInterface::IceConnectionState new_state) override { if (!main_thread_->BelongsToCurrentThread()) { main_thread_->PostTask( - FROM_HERE, - base::BindOnce( - &RTCPeerConnectionHandler::Observer::OnIceConnectionChange, this, - new_state)); + FROM_HERE, base::BindOnce(&RTCPeerConnectionHandler::Observer:: + OnStandardizedIceConnectionChange, + this, new_state)); } else if (handler_) { handler_->OnIceConnectionChange(new_state); }
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.h b/content/renderer/media/webrtc/rtc_peer_connection_handler.h index f5f53fe..608e0d7 100644 --- a/content/renderer/media/webrtc/rtc_peer_connection_handler.h +++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.h
@@ -211,6 +211,8 @@ webrtc::PeerConnectionInterface::SignalingState new_state); void OnIceConnectionChange( webrtc::PeerConnectionInterface::IceConnectionState new_state); + void OnStandardizedIceConnectionChange( + webrtc::PeerConnectionInterface::IceConnectionState new_state); void OnConnectionChange( webrtc::PeerConnectionInterface::PeerConnectionState new_state); void OnIceGatheringChange(
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc index eed9b23..62251b6 100644 --- a/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc +++ b/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc
@@ -1047,7 +1047,7 @@ EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionNew)); - pc_handler_->observer()->OnIceConnectionChange(new_state); + pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionChecking; EXPECT_CALL(*mock_tracker_.get(), @@ -1057,7 +1057,7 @@ EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionChecking)); - pc_handler_->observer()->OnIceConnectionChange(new_state); + pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionConnected; EXPECT_CALL(*mock_tracker_.get(), @@ -1067,7 +1067,7 @@ EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionConnected)); - pc_handler_->observer()->OnIceConnectionChange(new_state); + pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionCompleted; EXPECT_CALL(*mock_tracker_.get(), @@ -1077,7 +1077,7 @@ EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionCompleted)); - pc_handler_->observer()->OnIceConnectionChange(new_state); + pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionFailed; EXPECT_CALL(*mock_tracker_.get(), @@ -1087,7 +1087,7 @@ EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionFailed)); - pc_handler_->observer()->OnIceConnectionChange(new_state); + pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionDisconnected; EXPECT_CALL(*mock_tracker_.get(), @@ -1097,7 +1097,7 @@ EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionDisconnected)); - pc_handler_->observer()->OnIceConnectionChange(new_state); + pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); new_state = webrtc::PeerConnectionInterface::kIceConnectionClosed; EXPECT_CALL(*mock_tracker_.get(), @@ -1107,7 +1107,7 @@ EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState( webrtc::PeerConnectionInterface::kIceConnectionClosed)); - pc_handler_->observer()->OnIceConnectionChange(new_state); + pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state); } TEST_F(RTCPeerConnectionHandlerTest, OnIceGatheringChange) {
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc index 75814f1..d29afb3 100644 --- a/content/renderer/render_frame_proxy.cc +++ b/content/renderer/render_frame_proxy.cc
@@ -800,6 +800,7 @@ void RenderFrameProxy::Navigate(const blink::WebURLRequest& request, bool should_replace_current_entry, bool is_opener_navigation, + bool prevent_sandboxed_download, mojo::ScopedMessagePipeHandle blob_url_token) { // The request must always have a valid initiator origin. DCHECK(!request.RequestorOrigin().IsNull()); @@ -821,8 +822,11 @@ params.triggering_event_info = blink::WebTriggeringEventInfo::kUnknown; params.blob_url_token = blob_url_token.release(); - params.download_policy = RenderFrameImpl::GetOpenerDownloadPolicy( - is_opener_navigation, request, web_frame_->GetSecurityOrigin()); + params.download_policy = + prevent_sandboxed_download + ? NavigationDownloadPolicy::kDisallowSandbox + : RenderFrameImpl::GetOpenerDownloadPolicy( + is_opener_navigation, request, web_frame_->GetSecurityOrigin()); Send(new FrameHostMsg_OpenURL(routing_id_, params)); }
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h index a6bd961..0f94066 100644 --- a/content/renderer/render_frame_proxy.h +++ b/content/renderer/render_frame_proxy.h
@@ -202,6 +202,7 @@ void Navigate(const blink::WebURLRequest& request, bool should_replace_current_entry, bool is_opener_navigation, + bool prevent_sandboxed_download, mojo::ScopedMessagePipeHandle blob_url_token) override; void FrameRectsChanged(const blink::WebRect& local_frame_rect, const blink::WebRect& screen_space_rect) override;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 06b40af1..19be288 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -757,6 +757,7 @@ settings->SetShouldClearDocumentBackground( prefs.should_clear_document_background); settings->SetEnableScrollAnimator(prefs.enable_scroll_animator); + settings->SetPrefersReducedMotion(prefs.prefers_reduced_motion); WebRuntimeFeatures::EnableTouchEventFeatureDetection( prefs.touch_event_feature_detection_enabled);
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 6c8b80e..ff843ae 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -753,6 +753,28 @@ if (screen_metrics_emulator_) { screen_metrics_emulator_->OnSynchronizeVisualProperties(params); } else { + if (!delegate()) { + // The main frame controls the page scale factor, from blink. For other + // frame widgets, the page scale is received from its parent as part of + // the visual properties here. While blink doesn't need to know this + // page scale factor outside the main frame, the compositor does in + // order to produce its output at the correct scale. + layer_tree_view_->SetExternalPageScaleFactor(params.page_scale_factor); + // Store the value to give to any new RenderFrameProxy that is + // registered. + page_scale_factor_from_mainframe_ = params.page_scale_factor; + // Push the page scale factor down to any child RenderWidgets via our + // child proxy frames. + // TODO(danakj): This ends up setting the page scale factor in the + // RenderWidgetHost of the child RenderWidget, so that it can bounce + // the value down to its RenderWidget. Since this is essentially a + // global value per-page, we could instead store it once in the browser + // (such as in RenderViewHost) and distribute it to each frame-hosted + // RenderWidget from there. + for (auto& child_proxy : render_frame_proxies_) + child_proxy.OnPageScaleFactorChanged(params.page_scale_factor); + } + gfx::Size old_visible_viewport_size = visible_viewport_size_; SynchronizeVisualProperties(params); if (old_visible_viewport_size != visible_viewport_size_) { @@ -779,7 +801,6 @@ visual_properties.visible_viewport_size = visible_viewport_size_; visual_properties.is_fullscreen_granted = is_fullscreen_granted_; visual_properties.display_mode = display_mode_; - visual_properties.page_scale_factor = page_scale_factor_from_mainframe_; screen_metrics_emulator_.reset(new RenderWidgetScreenMetricsEmulator( this, params, visual_properties, widget_screen_rect_, window_screen_rect_)); @@ -1349,11 +1370,6 @@ /////////////////////////////////////////////////////////////////////////////// // RenderWidgetScreenMetricsDelegate -void RenderWidget::Redraw() { - if (layer_tree_view_) - layer_tree_view_->SetNeedsRedrawRect(gfx::Rect(size_)); -} - void RenderWidget::ResizeWebWidget() { gfx::Size size = GetSizeForWebWidget(); if (delegate()) { @@ -1402,14 +1418,6 @@ if (render_thread) render_thread->SetRenderingColorSpace(params.screen_info.color_space); - // Ignore this during shutdown. - if (!GetWebWidget()) - return; - - // Only propagate the external PSF to non-main-frames. - if (!delegate()) - layer_tree_view_->SetExternalPageScaleFactor(params.page_scale_factor); - gfx::Size new_compositor_viewport_pixel_size = params.auto_resize_enabled ? gfx::ScaleToCeiledSize(size_, @@ -1433,10 +1441,6 @@ if (!params.auto_resize_enabled) { visible_viewport_size_ = params.visible_viewport_size; - // NOTE: We may have entered fullscreen mode without changing our size. - bool fullscreen_change = - is_fullscreen_granted_ != params.is_fullscreen_granted; - is_fullscreen_granted_ = params.is_fullscreen_granted; display_mode_ = params.display_mode; size_ = params.new_size; @@ -1453,16 +1457,8 @@ } GetWebWidget()->ResizeVisualViewport(visual_viewport_size); - if (fullscreen_change) - DidToggleFullscreen(); - } - - if (!delegate()) { - // Make sure that page scale factor changes propagating down from the main - // frame are relayed to nested OOPIFs/non-main-frames. - page_scale_factor_from_mainframe_ = params.page_scale_factor; - for (auto& observer : render_frame_proxies_) - observer.OnPageScaleFactorChanged(params.page_scale_factor); + // NOTE: We may have entered fullscreen mode without changing our size. + SetIsFullscreen(params.is_fullscreen_granted); } } @@ -2082,7 +2078,6 @@ visual_properties.display_mode = display_mode_; visual_properties.local_surface_id_allocation = local_surface_id_allocation_from_parent_; - visual_properties.page_scale_factor = page_scale_factor_from_mainframe_; // We are resizing the window from the renderer, so allocate a new // viz::LocalSurfaceId to avoid surface invariants violations in tests. if (layer_tree_view_) @@ -2377,10 +2372,10 @@ layer_tree_view_->SetVisible(!is_hidden_); } -void RenderWidget::DidToggleFullscreen() { - if (!GetWebWidget()) +void RenderWidget::SetIsFullscreen(bool fullscreen) { + if (fullscreen == is_fullscreen_granted_) return; - + is_fullscreen_granted_ = fullscreen; if (is_fullscreen_granted_) { GetWebWidget()->DidEnterFullscreen(); } else { @@ -3110,9 +3105,10 @@ void RenderWidget::RegisterRenderFrameProxy(RenderFrameProxy* proxy) { render_frame_proxies_.AddObserver(proxy); - // During initial page load, the main frame may have received page - // scale factor information before the sub-frame proxies were registered, so - // make sure we pass the page scale factor along here. + // Page scale factor is propagated down the RenderWidget tree (across + // frame trees). A new RenderFrameProxy means there is a new child + // RenderWidget in another frame tree. In order for it to hear about + // the page scale factor we pass along the last seen value here. proxy->OnPageScaleFactorChanged(page_scale_factor_from_mainframe_); } @@ -3256,15 +3252,24 @@ } void RenderWidget::PageScaleFactorChanged(float page_scale_factor) { - // Only the main frame pulls page scale information from the layer tree host. - // Pages scale is shared with non-mainframe widgets via the IPC for - // OnSynchronizeVisualProperties. - if (!delegate()) - return; + // The page scale is controlled by the WebView for the local main frame of + // the Page. So this is called from blink by for the RenderWidget of that + // local main frame. We forward the value on to each child RenderWidget (each + // of which will be via proxy child frame). These will each in turn forward + // the message to their child RenderWidgets (through their proxy child + // frames). + // TODO(crbug.com/924336): This value is continuously propagated during a + // pinch-zoom, causing the child RenderWidgets to re-raster, while the main + // frame is able to throttle re-raster to powers of 2. We could find some way + // to throttle child RenderWidgets also, perhaps by informing them when the + // pinch-zoom gesture is started and stopped. + DCHECK(!is_frozen_); + DCHECK(delegate()); - page_scale_factor_from_mainframe_ = page_scale_factor; for (auto& observer : render_frame_proxies_) observer.OnPageScaleFactorChanged(page_scale_factor); + // Store the value to give to any new RenderFrameProxy that is registered. + page_scale_factor_from_mainframe_ = page_scale_factor; } void RenderWidget::UseSynchronousResizeModeForTesting(bool enable) { @@ -3287,7 +3292,6 @@ visual_properties.display_mode = display_mode_; visual_properties.local_surface_id_allocation = local_surface_id_allocation_from_parent_; - visual_properties.page_scale_factor = page_scale_factor_from_mainframe_; // We are changing the device scale factor from the renderer, so allocate a // new viz::LocalSurfaceId to avoid surface invariants violations in tests. if (layer_tree_view_) @@ -3311,7 +3315,6 @@ visual_properties.display_mode = display_mode_; visual_properties.local_surface_id_allocation = local_surface_id_allocation_from_parent_; - visual_properties.page_scale_factor = page_scale_factor_from_mainframe_; // We are changing the device color space from the renderer, so allocate a // new viz::LocalSurfaceId to avoid surface invariants violations in tests. if (layer_tree_view_) @@ -3335,7 +3338,6 @@ viz::LocalSurfaceIdAllocation( viz::LocalSurfaceId(1, 1, base::UnguessableToken::Create()), base::TimeTicks::Now())); - visual_properties.page_scale_factor = page_scale_factor_from_mainframe_; OnSynchronizeVisualProperties(visual_properties); } @@ -3355,7 +3357,6 @@ visual_properties.visible_viewport_size = visible_viewport_size_; visual_properties.is_fullscreen_granted = is_fullscreen_granted_; visual_properties.display_mode = display_mode_; - visual_properties.page_scale_factor = page_scale_factor_from_mainframe_; OnSynchronizeVisualProperties(visual_properties); }
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index 35064ea..6c95299 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h
@@ -337,7 +337,6 @@ bool WillHandleMouseEvent(const blink::WebMouseEvent& event) override; // RenderWidgetScreenMetricsEmulatorDelegate - void Redraw() override; void SynchronizeVisualProperties( const VisualProperties& resize_params) override; void SetScreenMetricsEmulationParameters( @@ -690,7 +689,10 @@ // state. void SetHidden(bool hidden); - void DidToggleFullscreen(); + // Sets the fullscreen state for the WebView. + // TODO(danakj): This is currently located on RenderWidget but is a page/view + // state, and should move to RenderView. + void SetIsFullscreen(bool fullscreen); // Returns a rect that the compositor needs to raster. For a main frame this // is always the entire viewport, but for out-of-process iframes this can be @@ -1017,8 +1019,9 @@ // The height of the browser bottom controls. float bottom_controls_height_ = 0.f; - // The page scale factor reported by the main-frame's RenderWidget, via - // SynchronizeVisualProperties. + // The last seen page scale factor, which comes from the main frame and is + // propagated through the RenderWidget tree. This value is passed to any new + // child RenderWidget. float page_scale_factor_from_mainframe_ = 1.f; // This is initialized to zero and is incremented on each non-same-page
diff --git a/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2 b/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2 index 6d0a041..fd0e1513 100644 --- a/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2 +++ b/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2
@@ -9,7 +9,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.content_browsertests_apk"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.CAMERA" />
diff --git a/content/shell/android/javatests/AndroidManifest.xml b/content/shell/android/javatests/AndroidManifest.xml index 496e46c..24ae32d 100644 --- a/content/shell/android/javatests/AndroidManifest.xml +++ b/content/shell/android/javatests/AndroidManifest.xml
@@ -6,7 +6,7 @@ doesn't ignore this. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.content_shell_apk.tests"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /> <!-- We add an application tag here just so that we can indicate that this package needs to link against the android.test library, which is
diff --git a/content/shell/android/linker_test_apk/AndroidManifest.xml.jinja2 b/content/shell/android/linker_test_apk/AndroidManifest.xml.jinja2 index cbb809b..aea6429 100644 --- a/content/shell/android/linker_test_apk/AndroidManifest.xml.jinja2 +++ b/content/shell/android/linker_test_apk/AndroidManifest.xml.jinja2
@@ -9,7 +9,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.chromium_linker_test_apk"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.CAMERA" />
diff --git a/content/shell/android/shell_apk/AndroidManifest.xml.jinja2 b/content/shell/android/shell_apk/AndroidManifest.xml.jinja2 index e7fc25d8..e2c85cd 100644 --- a/content/shell/android/shell_apk/AndroidManifest.xml.jinja2 +++ b/content/shell/android/shell_apk/AndroidManifest.xml.jinja2
@@ -9,7 +9,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.content_shell_apk"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.CAMERA"/>
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc index aeff978..12321b6 100644 --- a/content/shell/browser/shell.cc +++ b/content/shell/browser/shell.cc
@@ -456,6 +456,7 @@ load_url_params.should_replace_current_entry = params.should_replace_current_entry; load_url_params.blob_url_loader_factory = params.blob_url_loader_factory; + load_url_params.reload_type = params.reload_type; if (params.uses_post) { load_url_params.load_type = NavigationController::LOAD_TYPE_HTTP_POST;
diff --git a/content/shell/browser/shell_javascript_dialog_mac.mm b/content/shell/browser/shell_javascript_dialog_mac.mm index 096d2e78..d77829d 100644 --- a/content/shell/browser/shell_javascript_dialog_mac.mm +++ b/content/shell/browser/shell_javascript_dialog_mac.mm
@@ -26,9 +26,8 @@ andCallback:(content::JavaScriptDialogManager::DialogClosedCallback)callback; - (NSAlert*)alert; - (NSTextField*)textField; -- (void)alertDidEnd:(NSAlert*)alert - returnCode:(int)returnCode - contextInfo:(void*)contextInfo; +- (void)alertDidEndWithResult:(NSModalResponse)returnCode + dialog:(content::ShellJavaScriptDialog*)dialog; - (void)cancel; @end @@ -60,10 +59,9 @@ return textField_; } -- (void)alertDidEnd:(NSAlert*)alert - returnCode:(int)returnCode - contextInfo:(void*)contextInfo { - if (returnCode == NSRunStoppedResponse) +- (void)alertDidEndWithResult:(NSModalResponse)returnCode + dialog:(content::ShellJavaScriptDialog*)dialog { + if (returnCode == NSModalResponseStop) return; bool success = returnCode == NSAlertFirstButtonReturn; @@ -71,10 +69,8 @@ if (textField_) input = base::SysNSStringToUTF16([textField_ stringValue]); - content::ShellJavaScriptDialog* native_dialog = - reinterpret_cast<content::ShellJavaScriptDialog*>(contextInfo); std::move(callback_).Run(success, input); - manager_->DialogClosed(native_dialog); + manager_->DialogClosed(dialog); } - (void)cancel { @@ -117,11 +113,10 @@ [other setKeyEquivalent:@"\e"]; } - [alert - beginSheetModalForWindow:nil // nil here makes it app-modal - modalDelegate:helper_ - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:this]; + [alert beginSheetModalForWindow:nil // nil here makes it app-modal + completionHandler:^void(NSModalResponse returnCode) { + [helper_ alertDidEndWithResult:returnCode dialog:this]; + }]; } ShellJavaScriptDialog::~ShellJavaScriptDialog() {
diff --git a/content/shell/browser/shell_login_dialog_mac.mm b/content/shell/browser/shell_login_dialog_mac.mm index 695f8bbd..647b3b70 100644 --- a/content/shell/browser/shell_login_dialog_mac.mm +++ b/content/shell/browser/shell_login_dialog_mac.mm
@@ -31,9 +31,8 @@ - (NSAlert*)alert; - (NSView*)accessoryView; -- (void)alertDidEnd:(NSAlert*)alert - returnCode:(int)returnCode - contextInfo:(void*)contextInfo; +- (void)alertDidEndWithResponse:(NSModalResponse)response + dialog:(content::ShellLoginDialog*)dialog; - (void)cancel; @end @@ -57,20 +56,17 @@ return accessory_view; } -- (void)alertDidEnd:(NSAlert*)alert - returnCode:(int)returnCode - contextInfo:(void*)contextInfo { - if (returnCode == NSRunStoppedResponse) +- (void)alertDidEndWithResponse:(NSModalResponse)returnCode + dialog:(content::ShellLoginDialog*)dialog { + if (returnCode == NSModalResponseStop) return; - content::ShellLoginDialog* this_dialog = - reinterpret_cast<content::ShellLoginDialog*>(contextInfo); if (returnCode == NSAlertFirstButtonReturn) { - this_dialog->UserAcceptedAuth( + dialog->UserAcceptedAuth( base::SysNSStringToUTF16([usernameField_ stringValue]), base::SysNSStringToUTF16([passwordField_ stringValue])); } else { - this_dialog->UserCancelledAuth(); + dialog->UserCancelledAuth(); } } @@ -95,11 +91,10 @@ [alert addButtonWithTitle:@"OK"]; NSButton* other = [alert addButtonWithTitle:@"Cancel"]; [other setKeyEquivalent:@"\e"]; - [alert - beginSheetModalForWindow:nil // nil here makes it app-modal - modalDelegate:helper_ - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:this]; + [alert beginSheetModalForWindow:nil + completionHandler:^void(NSModalResponse resp) { + [helper_ alertDidEndWithResponse:resp dialog:this]; + }]; } void ShellLoginDialog::PlatformCleanUp() {
diff --git a/content/shell/renderer/web_test/web_test_content_renderer_client.cc b/content/shell/renderer/web_test/web_test_content_renderer_client.cc index afdfc761..d5046e21 100644 --- a/content/shell/renderer/web_test/web_test_content_renderer_client.cc +++ b/content/shell/renderer/web_test/web_test_content_renderer_client.cc
@@ -121,15 +121,18 @@ SetRuntimeFeaturesDefaultsBeforeBlinkInitialization() { // We always expose GC to web tests. std::string flags("--expose-gc"); + auto* command_line = base::CommandLine::ForCurrentProcess(); v8::V8::SetFlagsFromString(flags.c_str(), static_cast<int>(flags.size())); - if (!base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kStableReleaseMode)) { + if (!command_line->HasSwitch(switches::kStableReleaseMode)) { blink::WebRuntimeFeatures::EnableTestOnlyFeatures(true); } - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableFontAntialiasing)) { + if (command_line->HasSwitch(switches::kEnableFontAntialiasing)) { blink::SetFontAntialiasingEnabledForTest(true); } + if (command_line->HasSwitch( + switches::kDisableOriginTrialControlledBlinkFeatures)) { + blink::WebRuntimeFeatures::EnableOriginTrialControlledFeatures(false); + } } bool WebTestContentRendererClient::IsIdleMediaSuspendEnabled() {
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index df55581..26813f7 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1109,6 +1109,11 @@ ] } + if (!is_chromeos) { + sources += + [ "../browser/media/media_keys_listener_manager_impl_browsertest.cc" ] + } + if (is_win) { sources += [ "../browser/accessibility/accessibility_win_browsertest.cc", @@ -1355,6 +1360,7 @@ "../browser/background_fetch/background_fetch_registration_notifier_unittest.cc", "../browser/background_fetch/background_fetch_scheduler_unittest.cc", "../browser/background_fetch/background_fetch_service_unittest.cc", + "../browser/background_fetch/storage/database_helpers_unittest.cc", "../browser/background_fetch/storage/image_helpers_unittest.cc", "../browser/background_sync/background_sync_manager_unittest.cc", "../browser/background_sync/background_sync_network_observer_unittest.cc", @@ -2196,8 +2202,7 @@ } } -# Disabled on jumbo builds because of timeouts (crbug.com/882852). -if (enable_nocompile_tests && !use_jumbo_build) { +if (enable_nocompile_tests) { nocompile_test("content_nocompile_tests") { sources = [ "../public/browser/browser_task_traits_unittest.nc",
diff --git a/content/test/data/accessibility/aria/aria-alert-expected-mac.txt b/content/test/data/accessibility/aria/aria-alert-expected-mac.txt index 3c7a505..aced76b 100644 --- a/content/test/data/accessibility/aria/aria-alert-expected-mac.txt +++ b/content/test/data/accessibility/aria/aria-alert-expected-mac.txt
@@ -1,3 +1,3 @@ AXWebArea -++AXGroup AXRoleDescription='alert' AXARIAAtomic='1' +++AXGroup AXSubrole=AXApplicationAlert AXRoleDescription='alert' AXARIAAtomic='1' ++++AXStaticText AXValue='This test is for aria role="alert"' AXARIAAtomic='0'
diff --git a/content/test/data/accessibility/aria/aria-alert.html b/content/test/data/accessibility/aria/aria-alert.html index 00ef417..2301c3d 100644 --- a/content/test/data/accessibility/aria/aria-alert.html +++ b/content/test/data/accessibility/aria/aria-alert.html
@@ -1,6 +1,7 @@ <!DOCTYPE html> <!-- @MAC-ALLOW:AXRoleDescription='alert' +@MAC-ALLOW:AXSubrole=AXApplicationAlert @MAC-ALLOW:AXARIAAtomic=* @WIN-ALLOW:atomic:* @WIN-ALLOW:container-atomic:*
diff --git a/content/test/data/accessibility/event/report-validity-invalid-field-expected-mac.txt b/content/test/data/accessibility/event/report-validity-invalid-field-expected-mac.txt new file mode 100644 index 0000000..ccae42e --- /dev/null +++ b/content/test/data/accessibility/event/report-validity-invalid-field-expected-mac.txt
@@ -0,0 +1,3 @@ +AXFocusedUIElementChanged on AXTextField AXTitle="Pet name:" +AXLiveRegionChanged on AXGroup AXDescription="Please enter pet name" +AXLiveRegionCreated on AXGroup AXDescription="Please enter pet name"
diff --git a/content/test/data/accessibility/event/report-validity-invalid-field-expected-win.txt b/content/test/data/accessibility/event/report-validity-invalid-field-expected-win.txt new file mode 100644 index 0000000..55c664b --- /dev/null +++ b/content/test/data/accessibility/event/report-validity-invalid-field-expected-win.txt
@@ -0,0 +1,2 @@ +EVENT_OBJECT_FOCUS on <input#in1> role=ROLE_SYSTEM_TEXT name="Pet name:" FOCUSED,FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_INVALID_ENTRY,IA2_STATE_REQUIRED,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE +EVENT_SYSTEM_ALERT on role=ROLE_SYSTEM_ALERT name="Please enter pet name"
diff --git a/content/test/data/accessibility/event/report-validity-invalid-field.html b/content/test/data/accessibility/event/report-validity-invalid-field.html new file mode 100644 index 0000000..5d3e7050 --- /dev/null +++ b/content/test/data/accessibility/event/report-validity-invalid-field.html
@@ -0,0 +1,21 @@ +<!-- +@WIN-DENY:* +@WIN-ALLOW:EVENT_OBJECT_FOCUS* +@WIN-ALLOW:EVENT_SYSTEM_ALERT* +@WIN-ALLOW:EVENT_OBJECT_LIVE* +@MAC-DENY:* +@MAC-ALLOW:AXFocusedUIElementChanged* +@MAC-ALLOW:AXFocusedUIElementChanged* +@MAC-ALLOW:AXLiveRegion* +--> +<!DOCTYPE html> +<form> + <label for="in1">Pet name:</label><input id="in1" required> +</form> +<script> + function go() { + const in1 = document.querySelector('input'); + in1.setCustomValidity('Please enter pet name'); + in1.reportValidity(); + } +</script>
diff --git a/content/test/data/accessibility/html/audio-expected-auralinux.txt b/content/test/data/accessibility/html/audio-expected-auralinux.txt index d0201060..a11729b 100644 --- a/content/test/data/accessibility/html/audio-expected-auralinux.txt +++ b/content/test/data/accessibility/html/audio-expected-auralinux.txt
@@ -5,9 +5,13 @@ ++++++++[tool bar] name='audio' description='audio' horizontal ++++++++++[tool bar] name='audio' description='audio' horizontal ++++++++++++[push button] name='play' xml-roles:button -++++++++++++[text] name='0:00' -++++++++++++[text] name='/ 0:00' +++++++++++++[section] name='elapsed time: 0:00' +++++++++++++++[text] name='0:00' +++++++++++++[section] name='remaining time: / 0:00' +++++++++++++++[text] name='/ 0:00' ++++++++++++[slider] description='audio time scrubber' horizontal xml-roles:slider ++++++++++++[section] ++++++++++++++[section] +++++++++++++++[slider] name='volume' horizontal xml-roles:slider ++++++++++++++[push button] name='mute' xml-roles:button +++++++++++++[push button] name='show more media controls' description='more options' xml-roles:button \ No newline at end of file
diff --git a/content/test/data/accessibility/html/audio.html b/content/test/data/accessibility/html/audio.html index 105c1da..2a824a2 100644 --- a/content/test/data/accessibility/html/audio.html +++ b/content/test/data/accessibility/html/audio.html
@@ -5,6 +5,7 @@ @AURALINUX-ALLOW:description* @AURALINUX-ALLOW:horizontal @AURALINUX-ALLOW:vertical +@WAIT-FOR:volume --> <!DOCTYPE html> <html>
diff --git a/content/test/data/accessibility/html/form-validation-message-expected-blink.txt b/content/test/data/accessibility/html/form-validation-message-expected-blink.txt new file mode 100644 index 0000000..9a6bd4cd --- /dev/null +++ b/content/test/data/accessibility/html/form-validation-message-expected-blink.txt
@@ -0,0 +1,8 @@ +rootWebArea +++form +++++labelText +++++++staticText name='Pet name:' +++++++++inlineTextBox name='Pet name:' +++++textField required name='Pet name:' errormessageId=alert invalidState=true +++++++genericContainer +++alert containerLiveRelevant='additions' containerLiveStatus='assertive' name='Please enter pet name' liveRelevant='additions' liveStatus='assertive' containerLiveAtomic=true containerLiveBusy=false liveAtomic=true \ No newline at end of file
diff --git a/content/test/data/accessibility/html/form-validation-message-expected-mac.txt b/content/test/data/accessibility/html/form-validation-message-expected-mac.txt new file mode 100644 index 0000000..f67b883 --- /dev/null +++ b/content/test/data/accessibility/html/form-validation-message-expected-mac.txt
@@ -0,0 +1,6 @@ +AXWebArea +++AXGroup +++++AXGroup +++++++AXStaticText AXValue='Pet name:' +++++AXTextField AXTitle='Pet name:' +++AXGroup AXSubrole=AXApplicationAlert AXDescription='Please enter pet name'
diff --git a/content/test/data/accessibility/html/form-validation-message-expected-win.txt b/content/test/data/accessibility/html/form-validation-message-expected-win.txt new file mode 100644 index 0000000..0e4d21c8 --- /dev/null +++ b/content/test/data/accessibility/html/form-validation-message-expected-win.txt
@@ -0,0 +1,6 @@ +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE +++IA2_ROLE_FORM +++++IA2_ROLE_LABEL +++++++ROLE_SYSTEM_STATICTEXT name='Pet name:' +++++ROLE_SYSTEM_TEXT name='Pet name:' FOCUSABLE IA2_STATE_INVALID_ENTRY IA2_STATE_REQUIRED +++ROLE_SYSTEM_ALERT name='Please enter pet name' \ No newline at end of file
diff --git a/content/test/data/accessibility/html/form-validation-message.html b/content/test/data/accessibility/html/form-validation-message.html new file mode 100644 index 0000000..616f4ab --- /dev/null +++ b/content/test/data/accessibility/html/form-validation-message.html
@@ -0,0 +1,14 @@ +<!-- +@BLINK-ALLOW:live* +@BLINK-ALLOW:container* +@MAC-ALLOW:AXSubrole=AXApplicationAlert +--> +<!DOCTYPE html> +<form> + <label for="in1">Pet name:</label><input id="in1" required> +</form> +<script> + const in1 = document.querySelector('input'); + in1.setCustomValidity('Please enter pet name'); + in1.reportValidity(); +</script>
diff --git a/content/test/data/gpu/pixel_video_complex_overlays.html b/content/test/data/gpu/pixel_video_complex_overlays.html index 6ca87799..a48f81e7 100644 --- a/content/test/data/gpu/pixel_video_complex_overlays.html +++ b/content/test/data/gpu/pixel_video_complex_overlays.html
@@ -18,24 +18,7 @@ transform: rotate(20deg); } </style> -<script> -var video; - -function main() { - video = document.getElementById("video"); - video.loop = true; - video.addEventListener('timeupdate', SendSuccess); - video.play(); -} - -function SendSuccess() { - if (video.currentTime > 0) { - video.removeEventListener('timeupdate', SendSuccess); - domAutomationController.send("SUCCESS"); - } -} - -</script> +<script src="pixel_video_test.js"></script> </head> <body onload="main()"> <div id="container" style="position:absolute; top:0px; left:0px;">
diff --git a/content/test/data/gpu/pixel_video_mp4.html b/content/test/data/gpu/pixel_video_mp4.html index fc30eed..fd842a2 100644 --- a/content/test/data/gpu/pixel_video_mp4.html +++ b/content/test/data/gpu/pixel_video_mp4.html
@@ -14,35 +14,12 @@ margin: 0px auto; } </style> -<script> -var g_swapsBeforeAck = 15; -var video; - -function main() -{ - video = document.getElementById("video"); - if (video.readyState >= 4) { - waitForFinish(); - } else { - video.addEventListener('canplaythrough', waitForFinish, true); - } -} - -function waitForFinish() -{ - if (g_swapsBeforeAck == 0) { - domAutomationController.send("SUCCESS"); - } else { - g_swapsBeforeAck--; - window.requestAnimationFrame(waitForFinish); - } -} -</script> +<script src="pixel_video_test.js"></script> </head> <body onload="main()"> <div id="container" style="position:absolute; top:0px; left:0px"> -<video class="nomargin" id="video"> -<source src="/media/test/data/bear.mp4" type="video/mp4"> +<video class="nomargin" id="video" width="240" height="135"> +<source src="/media/test/data/four-colors.mp4" type="video/mp4"> </video> </div> </body>
diff --git a/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html b/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html index a8b7000..cc624f6 100644 --- a/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html +++ b/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html
@@ -14,30 +14,7 @@ margin: 0px auto; } </style> -<script> -var g_swapsBeforeAck = 15; -var video; - -function main() -{ - video = document.getElementById("video"); - if (video.readyState >= 4) { - waitForFinish(); - } else { - video.addEventListener('canplaythrough', waitForFinish, true); - } -} - -function waitForFinish() -{ - if (g_swapsBeforeAck == 0) { - domAutomationController.send("SUCCESS"); - } else { - g_swapsBeforeAck--; - window.requestAnimationFrame(waitForFinish); - } -} -</script> +<script src="pixel_video_test.js"></script> </head> <body onload="main()"> <div id="container" style="position:absolute; top:0px; left:0px">
diff --git a/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html b/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html index e08d543e..37a0f97 100644 --- a/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html +++ b/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html
@@ -14,30 +14,7 @@ margin: 0px auto; } </style> -<script> -var g_swapsBeforeAck = 15; -var video; - -function main() -{ - video = document.getElementById("video"); - if (video.readyState >= 4) { - waitForFinish(); - } else { - video.addEventListener('canplaythrough', waitForFinish, true); - } -} - -function waitForFinish() -{ - if (g_swapsBeforeAck == 0) { - domAutomationController.send("SUCCESS"); - } else { - g_swapsBeforeAck--; - window.requestAnimationFrame(waitForFinish); - } -} -</script> +<script src="pixel_video_test.js"></script> </head> <body onload="main()"> <div id="container" style="position:absolute; top:0px; left:0px">
diff --git a/content/test/data/gpu/pixel_video_mp4_four_colors_rot_270.html b/content/test/data/gpu/pixel_video_mp4_four_colors_rot_270.html index 34cfe8e3..8f975e9 100644 --- a/content/test/data/gpu/pixel_video_mp4_four_colors_rot_270.html +++ b/content/test/data/gpu/pixel_video_mp4_four_colors_rot_270.html
@@ -14,30 +14,7 @@ margin: 0px auto; } </style> -<script> -var g_swapsBeforeAck = 15; -var video; - -function main() -{ - video = document.getElementById("video"); - if (video.readyState >= 4) { - waitForFinish(); - } else { - video.addEventListener('canplaythrough', waitForFinish, true); - } -} - -function waitForFinish() -{ - if (g_swapsBeforeAck == 0) { - domAutomationController.send("SUCCESS"); - } else { - g_swapsBeforeAck--; - window.requestAnimationFrame(waitForFinish); - } -} -</script> +<script src="pixel_video_test.js"></script> </head> <body onload="main()"> <div id="container" style="position:absolute; top:0px; left:0px">
diff --git a/content/test/data/gpu/pixel_video_mp4_four_colors_rot_90.html b/content/test/data/gpu/pixel_video_mp4_four_colors_rot_90.html index eac2ea3..008bd4e 100644 --- a/content/test/data/gpu/pixel_video_mp4_four_colors_rot_90.html +++ b/content/test/data/gpu/pixel_video_mp4_four_colors_rot_90.html
@@ -14,30 +14,7 @@ margin: 0px auto; } </style> -<script> -var g_swapsBeforeAck = 15; -var video; - -function main() -{ - video = document.getElementById("video"); - if (video.readyState >= 4) { - waitForFinish(); - } else { - video.addEventListener('canplaythrough', waitForFinish, true); - } -} - -function waitForFinish() -{ - if (g_swapsBeforeAck == 0) { - domAutomationController.send("SUCCESS"); - } else { - g_swapsBeforeAck--; - window.requestAnimationFrame(waitForFinish); - } -} -</script> +<script src="pixel_video_test.js"></script> </head> <body onload="main()"> <div id="container" style="position:absolute; top:0px; left:0px">
diff --git a/content/test/data/gpu/pixel_video_nonroot.html b/content/test/data/gpu/pixel_video_nonroot.html index c5b89c0..c935f3f4 100644 --- a/content/test/data/gpu/pixel_video_nonroot.html +++ b/content/test/data/gpu/pixel_video_nonroot.html
@@ -23,30 +23,7 @@ color-stop(1.00, rgba(0,0,0,0))); } </style> -<script> -var g_swapsBeforeAck = 15; -var video; - -function main() -{ - video = document.getElementById("video"); - if (video.readyState >= 4) { - waitForFinish(); - } else { - video.addEventListener('canplaythrough', waitForFinish, true); - } -} - -function waitForFinish() -{ - if (g_swapsBeforeAck == 0) { - domAutomationController.send("SUCCESS"); - } else { - g_swapsBeforeAck--; - window.requestAnimationFrame(waitForFinish); - } -} -</script> +<script src="pixel_video_test.js"></script> </head> <body onload="main()"> <div id="container" style="position:absolute; top:0px; left:0px;">
diff --git a/content/test/data/gpu/pixel_video_test.js b/content/test/data/gpu/pixel_video_test.js new file mode 100644 index 0000000..85134b2 --- /dev/null +++ b/content/test/data/gpu/pixel_video_test.js
@@ -0,0 +1,19 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var video; + +function main() { + video = document.getElementById("video"); + video.loop = true; + video.addEventListener('timeupdate', SendSuccess); + video.play(); +} + +function SendSuccess() { + if (video.currentTime > 0) { + video.removeEventListener('timeupdate', SendSuccess); + domAutomationController.send("SUCCESS"); + } +}
diff --git a/content/test/data/gpu/pixel_video_underlay.html b/content/test/data/gpu/pixel_video_underlay.html index e1b0c677..ef9424f9 100644 --- a/content/test/data/gpu/pixel_video_underlay.html +++ b/content/test/data/gpu/pixel_video_underlay.html
@@ -14,30 +14,7 @@ margin: 0px auto; } </style> -<script> -var g_swapsBeforeAck = 15; -var video; - -function main() -{ - video = document.getElementById("video"); - if (video.readyState >= 4) { - waitForFinish(); - } else { - video.addEventListener('canplaythrough', waitForFinish, true); - } -} - -function waitForFinish() -{ - if (g_swapsBeforeAck == 0) { - domAutomationController.send("SUCCESS"); - } else { - g_swapsBeforeAck--; - window.requestAnimationFrame(waitForFinish); - } -} -</script> +<script src="pixel_video_test.js"></script> </head> <body onload="main()"> <div id="container" style="position:absolute; top:0px; left:0px">
diff --git a/content/test/data/gpu/pixel_video_vp9.html b/content/test/data/gpu/pixel_video_vp9.html index 2f6a0bd0..c08aca2 100644 --- a/content/test/data/gpu/pixel_video_vp9.html +++ b/content/test/data/gpu/pixel_video_vp9.html
@@ -14,36 +14,12 @@ margin: 0px auto; } </style> -<script> -var g_swapsBeforeAck = 15; -var video; - -function main() -{ - video = document.getElementById("video"); - if (video.readyState >= 4) { - waitForFinish(); - } else { - video.addEventListener('canplaythrough', waitForFinish, true); - } -} - -function waitForFinish() -{ - console.log("readyState" + video.readyState); - if (g_swapsBeforeAck == 0) { - domAutomationController.send("SUCCESS"); - } else { - g_swapsBeforeAck--; - window.requestAnimationFrame(waitForFinish); - } -} -</script> +<script src="pixel_video_test.js"></script> </head> <body onload="main()"> <div id="container" style="position:absolute; top:0px; left:0px"> -<video class="nomargin" id="video"> -<source src="/media/test/data/bear-vp9.webm" type="video/webm"> +<video class="nomargin" id="video" width="240" height="135"> +<source src="/media/test/data/four-colors-vp9.webm" type="video/webm"> </video> </div> </body>
diff --git a/content/test/did_commit_provisional_load_interceptor.cc b/content/test/did_commit_provisional_load_interceptor.cc index 7ca80fd..cb651e8b 100644 --- a/content/test/did_commit_provisional_load_interceptor.cc +++ b/content/test/did_commit_provisional_load_interceptor.cc
@@ -5,6 +5,7 @@ #include "content/test/did_commit_provisional_load_interceptor.h" #include "content/browser/frame_host/render_frame_host_impl.h" +#include "content/common/frame.mojom-test-utils.h" #include "content/common/frame_messages.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h"
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py index fd88996..37a91c93 100644 --- a/content/test/gpu/gpu_tests/pixel_expectations.py +++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -58,16 +58,6 @@ # TODO(kbr): flakily timing out on this configuration. self.Flaky('*', ['linux', 'intel', 'debug'], bug=648369) - # TODO(sunnyps): re-enable after rebaselining - # self.Flaky('Pixel_Video_MP4', ['android', 'nvidia'], bug=716564) - # self.Flaky('Pixel_Video_MP4', ['linux', 'nvidia'], bug=819635) - - # TODO(sunnyps): temporarily disabling for rebaselining. - self.Fail('Pixel_Video_MP4', bug=869677) - self.Fail('Pixel_Video_VP9', bug=869677) - self.Fail('Pixel_DirectComposition_Video_MP4', bug=869677) - self.Fail('Pixel_DirectComposition_Video_VP9', bug=869677) - # Flaky for unknown reasons only on macOS. Not planning to investigate # further. self.Flaky('Pixel_ScissorTestWithPreserveDrawingBuffer', ['mac'], @@ -82,12 +72,6 @@ self.Skip('Pixel_WebGL2_ClearBufferfv_Result_Displayed', ['android', ('qualcomm', 'Adreno (TM) 330')], bug=773293) - # Failing on Mac Intel HighSierra - # TODO(sunnyps): re-enable after rebaselining. - # self.Fail('Pixel_Video_MP4', - # ['highsierra', ('intel', 0xa2e)], bug=774809) - # self.Fail('Pixel_Video_VP9', - # ['highsierra', ('intel', 0xa2e)], bug=774809) self.Fail('Pixel_WebGLGreenTriangle_NonChromiumImage_NoAA_NoAlpha', ['highsierra', 'mojave', ('intel', 0xa2e)], bug=774809) self.Flaky('Pixel_OffscreenCanvasTransferBeforeStyleResize', @@ -116,10 +100,6 @@ self.Fail('Pixel_WebGLSadCanvas', ['mac'], bug=872423) self.Fail('Pixel_WebGLSadCanvas', ['android'], bug=575305) - # Flaky on Android: crbug.com/860548 - # TODO(sunnyps): re-enable after rebaselining. - # self.Flaky('Pixel_Video_VP9', ['android'], bug=860548) - self.Fail('Pixel_CanvasLowLatencyWebGL', ['android', 'nvidia'], bug=868596) self.Fail('Pixel_OffscreenCanvasWebGLPaintAfterResize', ['android', 'nvidia'], bug=868596) @@ -132,11 +112,19 @@ self.Fail('Pixel_BackgroundImage', ['android', ('qualcomm', 'Adreno (TM) 430')], bug=883500) - # Fails on android-marshmallow-arm64-rel - self.Fail('Pixel_Video_MP4_FourColors_Aspect_4x3', ['android'], bug=911898) - self.Fail('Pixel_Video_MP4_FourColors_Rot_90', ['android'], bug=911898) - self.Fail('Pixel_Video_MP4_FourColors_Rot_180', ['android'], bug=911898) - self.Fail('Pixel_Video_MP4_FourColors_Rot_270', ['android'], bug=911898) + # Fails on android-marshmallow-arm64-rel (Nexus 5X) + self.Fail('Pixel_Video_MP4', + ['android', ('qualcomm', 'Adreno (TM) 418')], bug=911898) + self.Fail('Pixel_Video_MP4_FourColors_Aspect_4x3', + ['android', ('qualcomm', 'Adreno (TM) 418')], bug=911898) + self.Fail('Pixel_Video_MP4_FourColors_Rot_90', + ['android', ('qualcomm', 'Adreno (TM) 418')], bug=911898) + self.Fail('Pixel_Video_MP4_FourColors_Rot_180', + ['android', ('qualcomm', 'Adreno (TM) 418')], bug=911898) + self.Fail('Pixel_Video_MP4_FourColors_Rot_270', + ['android', ('qualcomm', 'Adreno (TM) 418')], bug=911898) + self.Fail('Pixel_Video_VP9', + ['android', ('qualcomm', 'Adreno (TM) 418')], bug=911898) # Fails on Mac Pro FYI Release (AMD) self.Fail('Pixel_Video_MP4_FourColors_Aspect_4x3', @@ -147,7 +135,3 @@ ['mac', ('amd', 0x679e)], bug=911413) self.Fail('Pixel_Video_MP4_FourColors_Rot_270', ['mac', ('amd', 0x679e)], bug=911413) - - # Flaky on Windows: crbug.com/921279 - self.Flaky('Pixel_DirectComposition_ComplexOverlays', - ['win', 'nvidia'], bug=921279)
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py index dc353c4..a89697c8 100644 --- a/content/test/gpu/gpu_tests/pixel_test_pages.py +++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -96,10 +96,12 @@ sw_compositing_args = ['--disable-gpu-compositing'] tolerance = 3 + tolerance_vp9 = 5 # VP9 video requires larger tolerance if sys.platform == 'darwin': # On MacOSX, pixels are slightly off. # https://crbug.com/911895 tolerance = 10 + tolerance_vp9 = 20 return [ PixelTestPage( @@ -167,7 +169,7 @@ 'pixel_scissor.html', base_name + '_ScissorTestWithPreserveDrawingBuffer', test_rect=[0, 0, 300, 300], - revision=0, # This is not used. + revision=0, # Golden image revision is not used expected_colors=[ { 'comment': 'red top', @@ -207,14 +209,44 @@ PixelTestPage( 'pixel_video_mp4.html', base_name + '_Video_MP4', - test_rect=[0, 0, 300, 300], - revision=10), + test_rect=[0, 0, 240, 135], + revision=0, # Golden image revision is not used + expected_colors=[ + { + 'comment': 'top left video, yellow', + 'location': [5, 5], + 'size': [110, 57], + 'color': [255, 255, 15], + 'tolerance': tolerance + }, + { + 'comment': 'top right video, red', + 'location': [125, 5], + 'size': [110, 57], + 'color': [255, 17, 24], + 'tolerance': tolerance + }, + { + 'comment': 'bottom left video, blue', + 'location': [5, 72], + 'size': [110, 57], + 'color': [12, 12, 255], + 'tolerance': tolerance + }, + { + 'comment': 'bottom right video, green', + 'location': [125, 72], + 'size': [110, 57], + 'color': [44, 255, 16], + 'tolerance': tolerance + } + ]), PixelTestPage( 'pixel_video_mp4_four_colors_aspect_4x3.html', base_name + '_Video_MP4_FourColors_Aspect_4x3', test_rect=[0, 0, 240, 135], - revision=0, # This is not used. + revision=0, # Golden image revision is not used expected_colors=[ { 'comment': 'outside video content, left side, white', @@ -264,7 +296,7 @@ 'pixel_video_mp4_four_colors_rot_90.html', base_name + '_Video_MP4_FourColors_Rot_90', test_rect=[0, 0, 427, 240], - revision=0, # This is not used. + revision=0, # Golden image revision is not used expected_colors=[ { 'comment': 'outside video content, left side, white', @@ -314,7 +346,7 @@ 'pixel_video_mp4_four_colors_rot_180.html', base_name + '_Video_MP4_FourColors_Rot_180', test_rect=[0, 0, 240, 135], - revision=0, # This is not used. + revision=0, # Golden image revision is not used expected_colors=[ { 'comment': 'top left video, green', @@ -350,7 +382,7 @@ 'pixel_video_mp4_four_colors_rot_270.html', base_name + '_Video_MP4_FourColors_Rot_270', test_rect=[0, 0, 427, 240], - revision=0, # This is not used. + revision=0, # Golden image revision is not used expected_colors=[ { 'comment': 'outside video content, left side, white', @@ -399,14 +431,44 @@ PixelTestPage( 'pixel_video_vp9.html', base_name + '_Video_VP9', - test_rect=[0, 0, 300, 300], - revision=10), + test_rect=[0, 0, 240, 135], + revision=0, # Golden image revision is not used + expected_colors=[ + { + 'comment': 'top left video, yellow', + 'location': [5, 5], + 'size': [110, 57], + 'color': [255, 255, 15], + 'tolerance': tolerance_vp9 + }, + { + 'comment': 'top right video, red', + 'location': [125, 5], + 'size': [110, 57], + 'color': [255, 17, 24], + 'tolerance': tolerance_vp9 + }, + { + 'comment': 'bottom left video, blue', + 'location': [5, 72], + 'size': [110, 57], + 'color': [12, 12, 255], + 'tolerance': tolerance_vp9 + }, + { + 'comment': 'bottom right video, green', + 'location': [125, 72], + 'size': [110, 57], + 'color': [44, 255, 16], + 'tolerance': tolerance_vp9 + } + ]), PixelTestPage( 'pixel_webgl_premultiplied_alpha_false.html', base_name + '_WebGL_PremultipliedAlpha_False', test_rect=[0, 0, 150, 150], - revision=0, # This is not used. + revision=0, # Golden image revision is not used expected_colors=[ SCALE_FACTOR_OVERRIDES, { @@ -426,7 +488,7 @@ 'pixel_webgl2_blitframebuffer_result_displayed.html', base_name + '_WebGL2_BlitFramebuffer_Result_Displayed', test_rect=[0, 0, 200, 200], - revision=0, # This is not used. + revision=0, # Golden image revision is not used expected_colors=[ SCALE_FACTOR_OVERRIDES, { @@ -442,7 +504,7 @@ 'pixel_webgl2_clearbufferfv_result_displayed.html', base_name + '_WebGL2_ClearBufferfv_Result_Displayed', test_rect=[0, 0, 200, 200], - revision=0, # This is not used. + revision=0, # Golden image revision is not used expected_colors=[ SCALE_FACTOR_OVERRIDES, { @@ -458,7 +520,7 @@ 'pixel_repeated_webgl_to_2d.html', base_name + '_RepeatedWebGLTo2D', test_rect=[0, 0, 256, 256], - revision=0, # This is not used. + revision=0, # Golden image revision is not used expected_colors=[ SCALE_FACTOR_OVERRIDES, { @@ -475,7 +537,7 @@ 'pixel_repeated_webgl_to_2d.html', base_name + '_RepeatedWebGLTo2D_SoftwareCompositing', test_rect=[0, 0, 256, 256], - revision=0, # This is not used. + revision=0, # Golden image revision is not used browser_args=sw_compositing_args, expected_colors=[ SCALE_FACTOR_OVERRIDES, @@ -499,7 +561,7 @@ 'pixel_background.html', base_name + '_GpuRasterization_BlueBox', test_rect=[0, 0, 220, 220], - revision=0, # This is not used. + revision=0, # Golden image revision is not used browser_args=browser_args, expected_colors=[ { @@ -591,7 +653,7 @@ 'concave_paths.html', base_name + '_GpuRasterization_ConcavePaths', test_rect=[0, 0, 100, 100], - revision=0, # This is not used. + revision=0, # Golden image revision is not used browser_args=browser_args, expected_colors=[ { @@ -653,7 +715,7 @@ base_name + '_OffscreenCanvasWebGLPaintAfterResize', test_rect=[0, 0, 200, 200], browser_args=browser_args, - revision=0, # This is not used. + revision=0, # Golden image revision is not used expected_colors=[ SCALE_FACTOR_OVERRIDES, { @@ -854,7 +916,7 @@ 'pixel_repeated_webgl_to_2d.html', base_name + '_RepeatedWebGLTo2D' + suffix, test_rect=[0, 0, 256, 256], - revision=0, # This is not used. + revision=0, # Golden image revision is not used browser_args=browser_args, expected_colors=[ SCALE_FACTOR_OVERRIDES, @@ -964,7 +1026,7 @@ 'pixel_webgl_premultiplied_alpha_false.html', base_name + '_WebGL_PremultipliedAlpha_False_NoOverlays', test_rect=[0, 0, 150, 150], - revision=0, # This is not used. + revision=0, # Golden image revision is not used browser_args=no_overlays_args, expected_colors=[ SCALE_FACTOR_OVERRIDES, @@ -993,19 +1055,52 @@ '--enable-features=DirectCompositionComplexOverlays,' + 'DirectCompositionNonrootOverlays,' + 'DirectCompositionUnderlays'] + + tolerance_dc = 3 + return [ PixelTestPage( 'pixel_video_mp4.html', base_name + '_DirectComposition_Video_MP4', - test_rect=[0, 0, 300, 300], - revision=8, - browser_args=browser_args), + test_rect=[0, 0, 240, 135], + revision=0, # Golden image revision is not used + browser_args=browser_args, + expected_colors=[ + { + 'comment': 'top left video, yellow', + 'location': [5, 5], + 'size': [110, 57], + 'color': [255, 255, 15], + 'tolerance': tolerance_dc + }, + { + 'comment': 'top right video, red', + 'location': [125, 5], + 'size': [110, 57], + 'color': [255, 17, 24], + 'tolerance': tolerance_dc + }, + { + 'comment': 'bottom left video, blue', + 'location': [5, 72], + 'size': [110, 57], + 'color': [12, 12, 255], + 'tolerance': tolerance_dc + }, + { + 'comment': 'bottom right video, green', + 'location': [125, 72], + 'size': [110, 57], + 'color': [44, 255, 16], + 'tolerance': tolerance_dc + } + ]), PixelTestPage( 'pixel_video_mp4_four_colors_aspect_4x3.html', base_name + '_DirectComposition_Video_MP4_FourColors_Aspect_4x3', test_rect=[0, 0, 240, 135], - revision=0, # This is not used. + revision=0, # Golden image revision is not used browser_args=browser_args, expected_colors=[ { @@ -1013,42 +1108,42 @@ 'location': [1, 1], 'size': [28, 133], 'color': [255, 255, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'outside video content, right side, white', 'location': [211, 1], 'size': [28, 133], 'color': [255, 255, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'top left video, yellow', 'location': [35, 5], 'size': [80, 57], 'color': [255, 255, 15], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'top right video, red', 'location': [125, 5], 'size': [80, 57], 'color': [255, 17, 24], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'bottom left video, blue', 'location': [35, 73], 'size': [80, 57], 'color': [12, 12, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'bottom right video, green', 'location': [125, 73], 'size': [80, 57], 'color': [44, 255, 16], - 'tolerance': 3 + 'tolerance': tolerance_dc } ]), @@ -1056,7 +1151,7 @@ 'pixel_video_mp4_four_colors_rot_90.html', base_name + '_DirectComposition_Video_MP4_FourColors_Rot_90', test_rect=[0, 0, 427, 240], - revision=0, # This is not used. + revision=0, # Golden image revision is not used browser_args=browser_args, expected_colors=[ { @@ -1064,42 +1159,42 @@ 'location': [1, 1], 'size': [144, 238], 'color': [255, 255, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'outside video content, right side, white', 'location': [282, 1], 'size': [144, 238], 'color': [255, 255, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'top left video, red', 'location': [152, 5], 'size': [55, 110], 'color': [255, 17, 24], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'top right video, green', 'location': [220, 5], 'size': [55, 110], 'color': [44, 255, 16], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'bottom left video, yellow', 'location': [152, 125], 'size': [55, 110], 'color': [255, 255, 15], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'bottom right video, blue', 'location': [220, 125], 'size': [55, 110], 'color': [12, 12, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc } ]), @@ -1107,7 +1202,7 @@ 'pixel_video_mp4_four_colors_rot_180.html', base_name + '_DirectComposition_Video_MP4_FourColors_Rot_180', test_rect=[0, 0, 240, 135], - revision=0, # This is not used. + revision=0, # Golden image revision is not used browser_args=browser_args, expected_colors=[ { @@ -1115,28 +1210,28 @@ 'location': [5, 5], 'size': [110, 57], 'color': [44, 255, 16], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'top right video, blue', 'location': [125, 5], 'size': [110, 57], 'color': [12, 12, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'bottom left video, red', 'location': [5, 72], 'size': [110, 57], 'color': [255, 17, 24], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'bottom right video, yellow', 'location': [125, 72], 'size': [110, 57], 'color': [255, 255, 15], - 'tolerance': 3 + 'tolerance': tolerance_dc } ]), @@ -1144,7 +1239,7 @@ 'pixel_video_mp4_four_colors_rot_270.html', base_name + '_DirectComposition_Video_MP4_FourColors_Rot_270', test_rect=[0, 0, 427, 240], - revision=0, # This is not used. + revision=0, # Golden image revision is not used browser_args=browser_args, expected_colors=[ { @@ -1152,51 +1247,81 @@ 'location': [1, 1], 'size': [144, 238], 'color': [255, 255, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'outside video content, right side, white', 'location': [282, 1], 'size': [144, 238], 'color': [255, 255, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'top left video, blue', 'location': [152, 5], 'size': [55, 110], 'color': [12, 12, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'top right video, yellow', 'location': [220, 5], 'size': [55, 110], 'color': [255, 255, 15], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'bottom left video, green', 'location': [152, 125], 'size': [55, 110], 'color': [44, 255, 16], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'bottom right video, red', 'location': [220, 125], 'size': [55, 110], 'color': [255, 17, 24], - 'tolerance': 3 + 'tolerance': tolerance_dc } ]), PixelTestPage( 'pixel_video_vp9.html', base_name + '_DirectComposition_Video_VP9', - test_rect=[0, 0, 300, 300], - revision=10, - browser_args=browser_args), + test_rect=[0, 0, 240, 135], + revision=0, # Golden image revision is not used + browser_args=browser_args, + expected_colors=[ + { + 'comment': 'top left video, yellow', + 'location': [5, 5], + 'size': [110, 57], + 'color': [255, 255, 15], + 'tolerance': tolerance_dc + }, + { + 'comment': 'top right video, red', + 'location': [125, 5], + 'size': [110, 57], + 'color': [255, 17, 24], + 'tolerance': tolerance_dc + }, + { + 'comment': 'bottom left video, blue', + 'location': [5, 72], + 'size': [110, 57], + 'color': [12, 12, 255], + 'tolerance': tolerance_dc + }, + { + 'comment': 'bottom right video, green', + 'location': [125, 72], + 'size': [110, 57], + 'color': [44, 255, 16], + 'tolerance': tolerance_dc + } + ]), PixelTestPage( 'pixel_video_underlay.html', @@ -1210,35 +1335,35 @@ 'location': [4, 4], 'size': [20, 20], 'color': [0, 0, 0], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'yellow top left quadrant', 'location': [4, 34], 'size': [110, 30], 'color': [255, 255, 15], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'red top right quadrant', 'location': [124, 4], 'size': [110, 60], 'color': [255, 17, 24], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'blue bottom left quadrant', 'location': [4, 72], 'size': [110, 60], 'color': [12, 12, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'green bottom right quadrant', 'location': [124, 72], 'size': [110, 60], 'color': [44, 255, 16], - 'tolerance': 3 + 'tolerance': tolerance_dc } ]), @@ -1254,35 +1379,35 @@ 'location': [4, 4], 'size': [20, 20], 'color': [0, 0, 0], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'yellow top left quadrant', 'location': [4, 34], 'size': [110, 30], 'color': [255, 255, 15], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'red top right quadrant', 'location': [124, 4], 'size': [50, 60], 'color': [255, 17, 24], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'blue bottom left quadrant', 'location': [4, 72], 'size': [110, 60], 'color': [12, 12, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'green bottom right quadrant', 'location': [124, 72], 'size': [50, 60], 'color': [44, 255, 16], - 'tolerance': 3 + 'tolerance': tolerance_dc } ]), @@ -1298,35 +1423,35 @@ 'location': [4, 4], 'size': [20, 20], 'color': [0, 0, 0], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'yellow top left quadrant', 'location': [60, 10], 'size': [65, 30], 'color': [255, 255, 15], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'red top right quadrant', 'location': [150, 45], 'size': [65, 30], 'color': [255, 17, 24], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'blue bottom left quadrant', 'location': [30, 70], 'size': [65, 30], 'color': [12, 12, 255], - 'tolerance': 3 + 'tolerance': tolerance_dc }, { 'comment': 'green bottom right quadrant', 'location': [130, 100], 'size': [65, 30], 'color': [44, 255, 16], - 'tolerance': 3 + 'tolerance': tolerance_dc } ]), ]
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index 42abd1b3..ba36d2f 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -95,12 +95,6 @@ 'integer-cubemap-specification-order-bug.html', bug=905003) # owner:cwallez, test might be buggy - # The following actually passes on gl_passthrough and also Mac Intel with - # command buffer. - self.Fail('deqp/functional/gles3/shadertexturefunction/' + - 'texturelodoffset.html', - bug=794335) - # Nvidia bugs fixed in latest driver # TODO(http://crbug.com/887241): Upgrade the drivers on the bots. self.Fail('conformance/glsl/bugs/assign-to-swizzled-twice-in-function.html',
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt index c0cd411..c996c24 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt +++ b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
@@ -1,3 +1,3 @@ # AUTOGENERATED FILE - DO NOT EDIT # SEE roll_webgl_conformance.py -Current webgl revision f22b9ad8d75bf99652dfc3b1db40e73d9fdd3840 +Current webgl revision db52df17f0d012983dc281e4864c71485a86bd0e
diff --git a/device/BUILD.gn b/device/BUILD.gn index f6c7e0d..7efc0a8 100644 --- a/device/BUILD.gn +++ b/device/BUILD.gn
@@ -100,6 +100,7 @@ "fido/u2f_command_constructor_unittest.cc", "fido/u2f_register_operation_unittest.cc", "fido/u2f_sign_operation_unittest.cc", + "fido/win/type_conversions_unittest.cc", "gamepad/abstract_haptic_gamepad_unittest.cc", "gamepad/gamepad_id_list_unittest.cc", "gamepad/gamepad_provider_unittest.cc",
diff --git a/device/fido/win/type_conversions.cc b/device/fido/win/type_conversions.cc index c381fc7..20b94a76 100644 --- a/device/fido/win/type_conversions.cc +++ b/device/fido/win/type_conversions.cc
@@ -35,7 +35,7 @@ base::Optional<cbor::Value> cbor_attestation_statement = cbor::Reader::Read( base::span<const uint8_t>(credential_attestation.pbAttestation, credential_attestation.cbAttestation)); - if (!cbor_attestation_statement) { + if (!cbor_attestation_statement || !cbor_attestation_statement->is_map()) { DLOG(ERROR) << "CBOR decoding attestation statement failed: " << base::HexEncode(credential_attestation.pbAttestation, credential_attestation.cbAttestation); @@ -67,7 +67,7 @@ } return AuthenticatorMakeCredentialResponse( - base::nullopt /* transport_used */, + transport_used, AttestationObject( std::move(*authenticator_data), std::make_unique<OpaqueAttestationStatement>(
diff --git a/device/fido/win/type_conversions_unittest.cc b/device/fido/win/type_conversions_unittest.cc new file mode 100644 index 0000000..ab02c1c --- /dev/null +++ b/device/fido/win/type_conversions_unittest.cc
@@ -0,0 +1,132 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/fido/win/type_conversions.h" + +#include "base/strings/utf_string_conversions.h" +#include "components/cbor/values.h" +#include "components/cbor/writer.h" +#include "device/fido/attestation_object.h" +#include "device/fido/attestation_statement.h" +#include "device/fido/fido_parsing_utils.h" +#include "device/fido/fido_test_data.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace device { +namespace { + +TEST(TypeConversionsTest, ToAuthenticatorMakeCredentialResponse) { + struct TestCase { + const wchar_t* format; + std::vector<uint8_t> authenticator_data; + std::vector<uint8_t> cbor_attestation_statement; + uint8_t used_transport; // WEBAUTHN_CTAP_TRANSPORT_* from <webauthn.h> + bool success; + base::Optional<FidoTransportProtocol> expected_transport; + } test_cases[] = { + {L"packed", + fido_parsing_utils::Materialize(test_data::kTestSignAuthenticatorData), + fido_parsing_utils::Materialize( + test_data::kPackedAttestationStatementCBOR), + WEBAUTHN_CTAP_TRANSPORT_USB, true, + FidoTransportProtocol::kUsbHumanInterfaceDevice}, + {L"packed", + fido_parsing_utils::Materialize(test_data::kTestSignAuthenticatorData), + fido_parsing_utils::Materialize( + test_data::kPackedAttestationStatementCBOR), + WEBAUTHN_CTAP_TRANSPORT_NFC, true, + FidoTransportProtocol::kNearFieldCommunication}, + {L"packed", + fido_parsing_utils::Materialize(test_data::kTestSignAuthenticatorData), + fido_parsing_utils::Materialize( + test_data::kPackedAttestationStatementCBOR), + WEBAUTHN_CTAP_TRANSPORT_INTERNAL, true, + FidoTransportProtocol::kInternal}, + {L"packed", + fido_parsing_utils::Materialize(test_data::kTestSignAuthenticatorData), + fido_parsing_utils::Materialize( + test_data::kPackedAttestationStatementCBOR), + WEBAUTHN_CTAP_TRANSPORT_TEST, true, base::nullopt}, + // Unknown attestation formats + {L"weird-unknown-format", + fido_parsing_utils::Materialize(test_data::kTestSignAuthenticatorData), + {0xa0}, // Empty CBOR map. + WEBAUTHN_CTAP_TRANSPORT_USB, + true, + FidoTransportProtocol::kUsbHumanInterfaceDevice}, + {L"weird-unknown-format", + fido_parsing_utils::Materialize(test_data::kTestSignAuthenticatorData), + {0x60}, // Empty string. Not a valid attStmt. + WEBAUTHN_CTAP_TRANSPORT_USB, + false}, + // Invalid authenticator data + {L"packed", + {}, + fido_parsing_utils::Materialize( + test_data::kPackedAttestationStatementCBOR), + WEBAUTHN_CTAP_TRANSPORT_USB, + false}, + {L"packed", + {1, 2, 3}, + fido_parsing_utils::Materialize( + test_data::kPackedAttestationStatementCBOR), + WEBAUTHN_CTAP_TRANSPORT_USB, + false}, + // Invalid attestation statement + {L"packed", + fido_parsing_utils::Materialize(test_data::kTestSignAuthenticatorData), + {}, + WEBAUTHN_CTAP_TRANSPORT_USB, + false}, + {L"packed", + fido_parsing_utils::Materialize(test_data::kTestSignAuthenticatorData), + {1, 2, 3}, + WEBAUTHN_CTAP_TRANSPORT_USB, + false}, + }; + size_t i = 0; + for (const auto test : test_cases) { + SCOPED_TRACE(::testing::Message() << "Test case " << i++); + auto response = + ToAuthenticatorMakeCredentialResponse(WEBAUTHN_CREDENTIAL_ATTESTATION{ + WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3, + test.format, + test.authenticator_data.size(), + const_cast<unsigned char*>(test.authenticator_data.data()), + test.cbor_attestation_statement.size(), + const_cast<unsigned char*>(test.cbor_attestation_statement.data()), + // dwAttestationDecodeType and pvAttestationDecode are ignored. + WEBAUTHN_ATTESTATION_DECODE_NONE, + nullptr, + // cbAttestationObject and pbAttestationObject are ignored. + 0, + nullptr, + // cbCredentialId and pbCredentialId are ignored. + 0, + nullptr, + WEBAUTHN_EXTENSIONS{}, + test.used_transport, + }); + EXPECT_EQ(response.has_value(), test.success); + if (!response) + return; + + EXPECT_EQ(response->attestation_object() + .authenticator_data() + .SerializeToByteArray(), + test.authenticator_data); + EXPECT_EQ( + response->attestation_object().attestation_statement().format_name(), + base::UTF16ToUTF8(test.format)); + EXPECT_EQ(cbor::Writer::Write(cbor::Value(response->attestation_object() + .attestation_statement() + .GetAsCBORMap())), + test.cbor_attestation_statement); + EXPECT_EQ(response->transport_used(), test.expected_transport); + } +}; + +} // namespace +} // namespace device
diff --git a/docs/android_build_instructions.md b/docs/android_build_instructions.md index ad4a800..9d39141 100644 --- a/docs/android_build_instructions.md +++ b/docs/android_build_instructions.md
@@ -184,7 +184,7 @@ 3 different versions using 3 different ninja targets: 1. `chrome_public_apk` (ChromePublic.apk) - * `minSdkVersion=16` (Jelly Bean). + * `minSdkVersion=19` (KitKat). * Stores libchrome.so compressed within the APK. * Uses [Crazy Linker](https://cs.chromium.org/chromium/src/base/android/linker/BUILD.gn?rcl=6bb29391a86f2be58c626170156cbfaa2cbc5c91&l=9). * Shipped only for Android < 21, but still works fine on Android >= 21.
diff --git a/docs/gpu/gpu_testing.md b/docs/gpu/gpu_testing.md index bd1b8821..69eac24f 100644 --- a/docs/gpu/gpu_testing.md +++ b/docs/gpu/gpu_testing.md
@@ -304,7 +304,7 @@ example, look at a recent build from the [Mac Release (Intel)] bot, and look at the `gl_unittests` step. You will see something like: -[Mac Release (Intel)]: https://ci.chromium.org/buildbot/chromium.gpu/Mac%20Release%20%28Intel%29/ +[Mac Release (Intel)]: https://ci.chromium.org/p/chromium/builders/luci.chromium.ci/Mac%20Release%20%28Intel%29/ ``` Triggered task: gl_unittests on Intel GPU on Mac/Mac-10.12.6/[TRUNCATED_ISOLATE_HASH]/Mac Release (Intel)/83664
diff --git a/docs/gpu/gpu_testing_bot_details.md b/docs/gpu/gpu_testing_bot_details.md index 7c4d6d8..a1c46751 100644 --- a/docs/gpu/gpu_testing_bot_details.md +++ b/docs/gpu/gpu_testing_bot_details.md
@@ -31,7 +31,7 @@ Release (NVIDIA)] bot is actually a virtual machine which spawns all of its jobs with the Swarming parameters: -[Win10 Release (NVIDIA)]: https://ci.chromium.org/buildbot/chromium.gpu/Win10%20Release%20%28NVIDIA%29/?limit=200 +[Win10 Release (NVIDIA)]: https://ci.chromium.org/p/chromium/builders/luci.chromium.ci/Win10%20Release%20%28NVIDIA%29 ```json { @@ -71,10 +71,9 @@ run locally on physical hardware, rather than via Swarming. A few examples are: <!-- XXX: update this list --> -* [Mac Pro Release (AMD)](https://luci-milo.appspot.com/buildbot/chromium.gpu.fyi/Mac%20Pro%20Release%20%28AMD%29/) -* [Mac Pro Debug (AMD)](https://luci-milo.appspot.com/buildbot/chromium.gpu.fyi/Mac%20Pro%20Debug%20%28AMD%29/) -* [Linux Release (Intel HD 630)](https://luci-milo.appspot.com/buildbot/chromium.gpu.fyi/Linux%20Release%20%28Intel%20HD%20630%29/) -* [Linux Release (AMD R7 240)](https://luci-milo.appspot.com/buildbot/chromium.gpu.fyi/Linux%20Release%20%28AMD%20R7%20240%29/) +* [Mac Pro Release (AMD)](https://luci-milo.appspot.com/p/chromium/builders/luci.chromium.ci/Mac%20Pro%20FYI%20Release%20%28AMD%29) +* [Linux Release (Intel HD 630)](https://luci-milo.appspot.com/p/chromium/builders/luci.chromium.ci/Linux%20FYI%20Release%20%28Intel%20HD%20630%29) +* [Linux Release (AMD R7 240)](https://luci-milo.appspot.com/p/chromium/builders/luci.chromium.ci/Linux%20FYI%20Release%20%28AMD%20R7%20240%29/) There are a couple of reasons to continue to support running tests on a specific machine: it might be too expensive to deploy the required multiple
diff --git a/docs/infra/cq_builders.md b/docs/infra/cq_builders.md index c845c62..24d6779 100644 --- a/docs/infra/cq_builders.md +++ b/docs/infra/cq_builders.md
@@ -54,25 +54,25 @@ * [linux-ozone-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/linux-ozone-rel) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+linux-ozone-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+linux-ozone-rel)) +* [linux-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/linux-rel) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+linux-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+linux-rel)) + * [linux_chromium_asan_rel_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/linux_chromium_asan_rel_ng) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+linux_chromium_asan_rel_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+linux_chromium_asan_rel_ng)) * [linux_chromium_compile_dbg_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/linux_chromium_compile_dbg_ng) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+linux_chromium_compile_dbg_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+linux_chromium_compile_dbg_ng)) * [linux_chromium_headless_rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/linux_chromium_headless_rel) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+linux_chromium_headless_rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+linux_chromium_headless_rel)) -* [linux_chromium_rel_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/linux_chromium_rel_ng) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+linux_chromium_rel_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+linux_chromium_rel_ng)) - * [linux_chromium_tsan_rel_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/linux_chromium_tsan_rel_ng) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+linux_chromium_tsan_rel_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+linux_chromium_tsan_rel_ng)) -* [mac_chromium_compile_dbg_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/mac_chromium_compile_dbg_ng) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+mac_chromium_compile_dbg_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+mac_chromium_compile_dbg_ng)) +* [mac-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/mac-rel) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+mac-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+mac-rel)) -* [mac_chromium_rel_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/mac_chromium_rel_ng) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+mac_chromium_rel_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+mac_chromium_rel_ng)) +* [mac_chromium_compile_dbg_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/mac_chromium_compile_dbg_ng) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+mac_chromium_compile_dbg_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+mac_chromium_compile_dbg_ng)) * [win-libfuzzer-asan-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win-libfuzzer-asan-rel) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+win-libfuzzer-asan-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win-libfuzzer-asan-rel)) * [win10_chromium_x64_rel_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win10_chromium_x64_rel_ng) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+win10_chromium_x64_rel_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win10_chromium_x64_rel_ng)) -* [win7_chromium_rel_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win7_chromium_rel_ng) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+win7_chromium_rel_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win7_chromium_rel_ng)) +* [win7-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win7-rel) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+win7-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win7-rel)) * [win_chromium_compile_dbg_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win_chromium_compile_dbg_ng) ([`cq.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:cq.cfg+win_chromium_compile_dbg_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win_chromium_compile_dbg_ng))
diff --git a/docs/win_cross.md b/docs/win_cross.md index 6376c7057..ffea53d 100644 --- a/docs/win_cross.md +++ b/docs/win_cross.md
@@ -92,6 +92,6 @@ See the contents of run-swarmed.py for how to do this manually. The -[linux-win_cross-rel](https://ci.chromium.org/buildbot/chromium.clang/linux-win_cross-rel/) +[linux-win_cross-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.ci/linux-win_cross-rel/) buildbot does 64-bit release cross builds, and also runs tests. You can look at it to get an idea of which tests pass in the cross build.
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h index 841b2818..d29bd5d6 100644 --- a/extensions/browser/extension_event_histogram_value.h +++ b/extensions/browser/extension_event_histogram_value.h
@@ -451,6 +451,8 @@ STORAGE_LOCAL_ON_CHANGE = 430, STORAGE_SYNC_ON_CHANGE = 431, STORAGE_MANAGED_ON_CHANGE = 432, + AUTOFILL_PRIVATE_ON_LOCAL_CREDIT_CARD_LIST_CHANGED = 433, + AUTOFILL_PRIVATE_ON_SERVER_CREDIT_CARD_LIST_CHANGED = 434, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index fc9ecba..2697dc2 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1373,6 +1373,8 @@ ACCESSIBILITY_PRIVATE_GETBATTERYDESCRIPTION = 1310, IDLE_GETAUTOLOCKDELAY = 1311, AUTOTESTPRIVATE_GETPRIMARYDISPLAYSCALEFACTOR = 1312, + AUTOFILLPRIVATE_GETLOCALCREDITCARDLIST = 1313, + AUTOFILLPRIVATE_GETSERVERCREDITCARDLIST = 1314, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/common/csp_validator.cc b/extensions/common/csp_validator.cc index 1b29ff2..6f9c83f 100644 --- a/extensions/common/csp_validator.cc +++ b/extensions/common/csp_validator.cc
@@ -9,6 +9,7 @@ #include <algorithm> #include <initializer_list> #include <iterator> +#include <set> #include <utility> #include <vector> @@ -38,6 +39,9 @@ const char kObjectSrc[] = "object-src"; const char kFrameSrc[] = "frame-src"; const char kChildSrc[] = "child-src"; +const char kWorkerSrc[] = "worker-src"; +const char kSelfSource[] = "'self'"; +const char kNoneSource[] = "'none'"; const char kDirectiveSeparator = ';'; @@ -82,6 +86,31 @@ // does not contain any duplicates. using DirectiveList = CSPParser::DirectiveList; +bool IsLocalHostSource(const std::string& source_lower) { + DCHECK_EQ(base::ToLowerASCII(source_lower), source_lower); + + constexpr char kLocalHost[] = "http://localhost"; + constexpr char kLocalHostIP[] = "http://127.0.0.1"; + + // Subtracting 1 to exclude the null terminator '\0'. + constexpr size_t kLocalHostLen = base::size(kLocalHost) - 1; + constexpr size_t kLocalHostIPLen = base::size(kLocalHostIP) - 1; + + if (base::StartsWith(source_lower, kLocalHost, + base::CompareCase::SENSITIVE)) { + return source_lower.length() == kLocalHostLen || + source_lower[kLocalHostLen] == ':'; + } + + if (base::StartsWith(source_lower, kLocalHostIP, + base::CompareCase::SENSITIVE)) { + return source_lower.length() == kLocalHostIPLen || + source_lower[kLocalHostIPLen] == ':'; + } + + return false; +} + // Represents the status of a directive in a CSP string. // // Examples of directive: @@ -94,6 +123,9 @@ DirectiveStatus(std::initializer_list<const char*> directives) : directive_names_(directives.begin(), directives.end()) {} + DirectiveStatus(DirectiveStatus&&) = default; + DirectiveStatus& operator=(DirectiveStatus&&) = default; + // Returns true if |directive_name| matches this DirectiveStatus. bool Matches(const std::string& directive_name) const { for (const auto& directive : directive_names_) { @@ -215,21 +247,16 @@ bool is_secure_csp_token = false; // We might need to relax this whitelist over time. - if (source_lower == "'self'" || source_lower == "'none'" || - source_lower == "'wasm-eval'" || source_lower == "http://127.0.0.1" || - source_lower == "blob:" || source_lower == "filesystem:" || - source_lower == "http://localhost" || - base::StartsWith(source_lower, - "http://127.0.0.1:", base::CompareCase::SENSITIVE) || - base::StartsWith(source_lower, - "http://localhost:", base::CompareCase::SENSITIVE) || + if (source_lower == kSelfSource || source_lower == kNoneSource || + source_lower == "'wasm-eval'" || source_lower == "blob:" || + source_lower == "filesystem:" || isNonWildcardTLD(source_lower, "https://", true) || isNonWildcardTLD(source_lower, "chrome://", false) || isNonWildcardTLD(source_lower, std::string(extensions::kExtensionScheme) + url::kStandardSchemeSeparator, false) || - IsHashSource(source_literal)) { + IsHashSource(source_literal) || IsLocalHostSource(source_lower)) { is_secure_csp_token = true; } else if ((options & OPTIONS_ALLOW_UNSAFE_EVAL) && source_lower == "'unsafe-eval'") { @@ -248,7 +275,7 @@ } else if (warnings) { warnings->push_back(InstallWarning( ErrorUtils::FormatErrorMessage( - manifest_errors::kInvalidCSPInsecureValue, manifest_key, + manifest_errors::kInvalidCSPInsecureValueIgnored, manifest_key, source_literal.as_string(), directive_name), manifest_key)); } @@ -286,7 +313,7 @@ } else if (warnings) { warnings->push_back(InstallWarning( ErrorUtils::FormatErrorMessage( - manifest_errors::kInvalidCSPInsecureValue, manifest_key, + manifest_errors::kInvalidCSPInsecureValueIgnored, manifest_key, source_literal.as_string(), directive_name), manifest_key)); } @@ -411,6 +438,8 @@ virtual std::string GetDefaultCSPValue(const DirectiveStatus& status) = 0; // List of directives we care about. + // TODO(karandeepb): There is no reason for these to be on the heap. Stack + // allocate. std::vector<std::unique_ptr<DirectiveStatus>> secure_directives_; private: @@ -641,6 +670,116 @@ return seen_sandbox; } +bool IsSecureIsolatedWorldCSP(const std::string& isolated_world_csp, + base::string16* error) { + DCHECK(error); + + struct DirectiveMapping { + DirectiveMapping(DirectiveStatus status) : status(std::move(status)) {} + + DirectiveStatus status; + const CSPParser::Directive* directive = nullptr; + }; + + DirectiveMapping script_src_mapping({DirectiveStatus({kScriptSrc})}); + DirectiveMapping object_src_mapping({DirectiveStatus({kObjectSrc})}); + DirectiveMapping worker_src_mapping({DirectiveStatus({kWorkerSrc})}); + DirectiveMapping default_src_mapping({DirectiveStatus({kDefaultSrc})}); + + DirectiveMapping* directive_mappings[] = { + &script_src_mapping, + &object_src_mapping, + &worker_src_mapping, + &default_src_mapping, + }; + + // Populate |directive_mappings|. + CSPParser csp_parser(isolated_world_csp); + for (DirectiveMapping* mapping : directive_mappings) { + // Find the first matching directive. As per + // http://www.w3.org/TR/CSP/#parse-a-csp-policy, duplicate directive names + // are ignored. + auto it = std::find_if( + csp_parser.directives().begin(), csp_parser.directives().end(), + [mapping](const CSPParser::Directive& directive) { + return mapping->status.Matches(directive.directive_name); + }); + + if (it != csp_parser.directives().end()) + mapping->directive = &(*it); + } + + auto fallback_if_necessary = [](DirectiveMapping* from, + const DirectiveMapping& to) { + DCHECK(from); + + // No fallback necessary. + if (from->directive) + return; + + from->directive = to.directive; + }; + + // "script-src" fallbacks to "default-src". + fallback_if_necessary(&script_src_mapping, default_src_mapping); + + // "object-src" fallbacks to "default-src". + fallback_if_necessary(&object_src_mapping, default_src_mapping); + + // "worker-src" fallbacks to "script-src", which might itself fallback to + // "default-src". + fallback_if_necessary(&worker_src_mapping, script_src_mapping); + + auto is_secure_directive = [](const DirectiveMapping& mapping, + base::string16* error) { + if (!mapping.directive) { + *error = ErrorUtils::FormatErrorMessageUTF16( + manifest_errors::kInvalidCSPMissingSecureSrc, + manifest_keys::kContentSecurityPolicy_IsolatedWorldPath, + mapping.status.name()); + return false; + } + + auto directive_values = mapping.directive->directive_values; + auto it = std::find_if_not( + directive_values.begin(), directive_values.end(), + [](base::StringPiece source) { + std::string source_lower = base::ToLowerASCII(source); + return source_lower == kSelfSource || source_lower == kNoneSource || + IsLocalHostSource(source_lower); + }); + + if (it == directive_values.end()) + return true; + + *error = ErrorUtils::FormatErrorMessageUTF16( + manifest_errors::kInvalidCSPInsecureValueError, + manifest_keys::kContentSecurityPolicy_IsolatedWorldPath, *it, + mapping.status.name()); + return false; + }; + + std::set<const CSPParser::Directive*> secure_directives; + for (const DirectiveMapping* mapping : directive_mappings) { + // We don't need "default-src" to be a secure directive. Ignore it. + if (mapping == &default_src_mapping) + continue; + + if (mapping->directive && secure_directives.count(mapping->directive)) { + // We already checked this directive and know it's secure. Skip it. + continue; + } + + if (!is_secure_directive(*mapping, error)) + return false; + + DCHECK(mapping->directive); + secure_directives.insert(mapping->directive); + } + + return true; +} + } // namespace csp_validator } // namespace extensions
diff --git a/extensions/common/csp_validator.h b/extensions/common/csp_validator.h index dbf9b37..98fe1c96 100644 --- a/extensions/common/csp_validator.h +++ b/extensions/common/csp_validator.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/macros.h" +#include "base/strings/string16.h" #include "base/strings/string_piece_forward.h" #include "extensions/common/manifest.h" @@ -131,6 +132,11 @@ bool ContentSecurityPolicyIsSandboxed( const std::string& policy, Manifest::Type type); +// Returns whether the given |isolated_world_csp| is secure. If not, populates +// |error|. +bool IsSecureIsolatedWorldCSP(const std::string& isolated_world_csp, + base::string16* error); + } // namespace csp_validator } // namespace extensions
diff --git a/extensions/common/csp_validator_unittest.cc b/extensions/common/csp_validator_unittest.cc index 744f48cd..f80f19f9 100644 --- a/extensions/common/csp_validator_unittest.cc +++ b/extensions/common/csp_validator_unittest.cc
@@ -7,6 +7,7 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" #include "extensions/common/csp_validator.h" #include "extensions/common/error_utils.h" #include "extensions/common/install_warning.h" @@ -32,8 +33,8 @@ const std::string& manifest_key = extensions::manifest_keys::kContentSecurityPolicy) { return ErrorUtils::FormatErrorMessage( - extensions::manifest_errors::kInvalidCSPInsecureValue, manifest_key, - value, directive); + extensions::manifest_errors::kInvalidCSPInsecureValueIgnored, + manifest_key, value, directive); } std::string MissingSecureSrcWarning(const std::string& manifest_key, @@ -615,3 +616,51 @@ ::testing::PrintToString(test_case.expected_directives)); } } + +TEST(ExtensionCSPValidator, IsSecureIsolatedWorldCSP) { + auto insecure_value_error = [](const std::string& directive, + const std::string& value) { + return ErrorUtils::FormatErrorMessage( + extensions::manifest_errors::kInvalidCSPInsecureValueError, + extensions::manifest_keys::kContentSecurityPolicy_IsolatedWorldPath, + value, directive); + }; + + auto missing_secure_src_error = [](const std::string& directive) { + return MissingSecureSrcWarning( + extensions::manifest_keys::kContentSecurityPolicy_IsolatedWorldPath, + directive); + }; + + struct { + const char* policy; + std::string expected_error; // Empty if no error expected. + } test_cases[] = { + {"frame-src google.com; default-src yahoo.com; script-src 'self'; " + "worker-src; object-src http://localhost:80 'none'", + ""}, + {"worker-src http://localhost google.com; script-src; object-src 'self'", + insecure_value_error("worker-src", "google.com")}, + {"script-src; worker-src 'self';", + missing_secure_src_error("object-src")}, + // Duplicate directives are ignored. + {"script-src; worker-src 'self'; default-src 'self'; script-src " + "google.com", + ""}, + // "object-src" falls back to "default-src". + {"script-src; worker-src 'self'; default-src google.com", + insecure_value_error("object-src", "google.com")}, + // "worker-src" falls back to "script-src". + {"script-src 'self'; object-src 'none'; default-src google.com", ""}, + {"script-src 'unsafe-eval'; worker-src; default-src;", + insecure_value_error("script-src", "'unsafe-eval'")}}; + + for (const auto& test_case : test_cases) { + SCOPED_TRACE(test_case.policy); + base::string16 error; + bool result = extensions::csp_validator::IsSecureIsolatedWorldCSP( + test_case.policy, &error); + EXPECT_EQ(test_case.expected_error.empty(), result); + EXPECT_EQ(base::ASCIIToUTF16(test_case.expected_error), error); + } +}
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc index 7b198aae..ea25d37c 100644 --- a/extensions/common/manifest_constants.cc +++ b/extensions/common/manifest_constants.cc
@@ -34,6 +34,8 @@ const char kContentSecurityPolicy[] = "content_security_policy"; const char kContentSecurityPolicy_ExtensionPagesPath[] = "content_security_policy.extension_pages"; +const char kContentSecurityPolicy_IsolatedWorldPath[] = + "content_security_policy.isolated_world"; const char kContentSecurityPolicy_SandboxedPagesPath[] = "content_security_policy.sandbox"; const char kConvertedFromUserScript[] = "converted_from_user_script"; @@ -357,8 +359,10 @@ "Invalid value for 'content_scripts[*]'."; const char kInvalidContentScriptsList[] = "Invalid value for 'content_scripts'."; -const char kInvalidCSPInsecureValue[] = +const char kInvalidCSPInsecureValueIgnored[] = "'*': Ignored insecure CSP value \"*\" in directive '*'."; +const char kInvalidCSPInsecureValueError[] = + "'*': Insecure CSP value \"*\" in directive '*'."; const char kInvalidCSPMissingSecureSrc[] = "'*': CSP directive '*' must be specified (either explicitly, or " "implicitly via 'default-src') and must whitelist only secure resources.";
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h index 761075a..fa55992 100644 --- a/extensions/common/manifest_constants.h +++ b/extensions/common/manifest_constants.h
@@ -36,6 +36,7 @@ extern const char kContentScripts[]; extern const char kContentSecurityPolicy[]; extern const char kContentSecurityPolicy_ExtensionPagesPath[]; +extern const char kContentSecurityPolicy_IsolatedWorldPath[]; extern const char kContentSecurityPolicy_SandboxedPagesPath[]; extern const char kConvertedFromUserScript[]; extern const char kCss[]; @@ -303,7 +304,8 @@ extern const char kInvalidContentCapabilitiesPermission[]; extern const char kInvalidContentScript[]; extern const char kInvalidContentScriptsList[]; -extern const char kInvalidCSPInsecureValue[]; +extern const char kInvalidCSPInsecureValueIgnored[]; +extern const char kInvalidCSPInsecureValueError[]; extern const char kInvalidCSPMissingSecureSrc[]; extern const char kInvalidCss[]; extern const char kInvalidCssList[];
diff --git a/extensions/common/manifest_handlers/csp_info.cc b/extensions/common/manifest_handlers/csp_info.cc index 1a55589..e65517d 100644 --- a/extensions/common/manifest_handlers/csp_info.cc +++ b/extensions/common/manifest_handlers/csp_info.cc
@@ -5,6 +5,7 @@ #include "extensions/common/manifest_handlers/csp_info.h" #include <memory> +#include <utility> #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -31,6 +32,10 @@ "script-src 'self' blob: filesystem: chrome-extension-resource:; " "object-src 'self' blob: filesystem:;"; +const char kDefaultIsolatedWorldCSP_BypassMainWorld[] = ""; +const char kDefaultIsolatedWorldCSP_Secure[] = + "script-src 'self'; object-src 'self'; worker-src 'self'"; + const char kDefaultSandboxedPageContentSecurityPolicy[] = "sandbox allow-scripts allow-forms allow-popups allow-modals; " "script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';"; @@ -95,9 +100,8 @@ } // namespace -CSPInfo::CSPInfo(const std::string& security_policy) - : content_security_policy(security_policy) { -} +CSPInfo::CSPInfo(std::string extension_pages_csp) + : extension_pages_csp(std::move(extension_pages_csp)) {} CSPInfo::~CSPInfo() { } @@ -107,7 +111,18 @@ const Extension* extension) { CSPInfo* csp_info = static_cast<CSPInfo*>( extension->GetManifestData(keys::kContentSecurityPolicy)); - return csp_info ? &csp_info->content_security_policy : nullptr; + return csp_info ? &csp_info->extension_pages_csp : nullptr; +} + +// static +const std::string& CSPInfo::GetIsolatedWorldCSP(const Extension& extension) { + // TODO(crbug.com/914224): This should be only called for extensions which can + // have isolated worlds. Figure out the case of TYPE_USER_SCRIPT and add + // DCHECK(csp_info). + CSPInfo* csp_info = static_cast<CSPInfo*>( + extension.GetManifestData(keys::kContentSecurityPolicy)); + + return csp_info ? csp_info->isolated_world_csp : base::EmptyString(); } // static @@ -115,8 +130,7 @@ const Extension* extension) { CSPInfo* csp_info = static_cast<CSPInfo*>( extension->GetManifestData(keys::kContentSecurityPolicy)); - return csp_info ? csp_info->sandbox_content_security_policy - : base::EmptyString(); + return csp_info ? csp_info->sandbox_csp : base::EmptyString(); } // static @@ -151,14 +165,32 @@ bool csp_dictionary_supported = extension->GetType() == Manifest::TYPE_EXTENSION && GetCurrentChannel() == version_info::Channel::UNKNOWN; - if (csp_dictionary_supported && csp && csp->is_dict()) - return ParseCSPDictionary(extension, error); - // TODO(crbug.com/914224) Disallow the usages below in manifest v3 for - // extensions. - return ParseExtensionPagesCSP(extension, error, key, csp) && - ParseSandboxCSP(extension, error, keys::kSandboxedPagesCSP, - GetManifestPath(extension, keys::kSandboxedPagesCSP)); + if (csp_dictionary_supported) { + // CSP key as dictionary is mandatory for manifest v3 extensions. + if (extension->manifest_version() == 3) { + if (csp && !csp->is_dict()) { + *error = GetInvalidManifestKeyError(key); + return false; + } + return ParseCSPDictionary(extension, error); + } + + // CSP key as dictionary is optional for manifest v2 extensions. + if (csp && csp->is_dict()) + return ParseCSPDictionary(extension, error); + } + + if (!ParseExtensionPagesCSP(extension, error, key, csp)) + return false; + + if (!ParseSandboxCSP(extension, error, keys::kSandboxedPagesCSP, + GetManifestPath(extension, keys::kSandboxedPagesCSP))) { + return false; + } + + SetIsolatedWorldCSP(extension, kDefaultIsolatedWorldCSP_BypassMainWorld); + return true; } bool CSPHandler::ParseCSPDictionary(Extension* extension, @@ -178,9 +210,10 @@ } return ParseSandboxCSP( - extension, error, keys::kContentSecurityPolicy_SandboxedPagesPath, - GetManifestPath(extension, - keys::kContentSecurityPolicy_SandboxedPagesPath)); + extension, error, keys::kContentSecurityPolicy_SandboxedPagesPath, + GetManifestPath( + extension, keys::kContentSecurityPolicy_SandboxedPagesPath)) && + ParseIsolatedWorldCSP(extension, error); } bool CSPHandler::ParseExtensionPagesCSP( @@ -214,7 +247,36 @@ extension->SetManifestData( keys::kContentSecurityPolicy, - std::make_unique<CSPInfo>(sanitized_content_security_policy)); + std::make_unique<CSPInfo>(std::move(sanitized_content_security_policy))); + return true; +} + +bool CSPHandler::ParseIsolatedWorldCSP(Extension* extension, + base::string16* error) { + const char* key = keys::kContentSecurityPolicy_IsolatedWorldPath; + + const base::Value* isolated_world_csp = GetManifestPath(extension, key); + + if (!isolated_world_csp) { + SetIsolatedWorldCSP(extension, kDefaultIsolatedWorldCSP_Secure); + return true; + } + + if (!isolated_world_csp->is_string()) { + *error = GetInvalidManifestKeyError(key); + return false; + } + + const std::string& isolated_world_csp_str = isolated_world_csp->GetString(); + if (!ContentSecurityPolicyIsLegal(isolated_world_csp_str)) { + *error = GetInvalidManifestKeyError(key); + return false; + } + + if (!csp_validator::IsSecureIsolatedWorldCSP(isolated_world_csp_str, error)) + return false; + + SetIsolatedWorldCSP(extension, isolated_world_csp_str); return true; } @@ -233,7 +295,7 @@ } const std::string& sandbox_csp_str = sandbox_csp->GetString(); - if (!csp_validator::ContentSecurityPolicyIsLegal(sandbox_csp_str) || + if (!ContentSecurityPolicyIsLegal(sandbox_csp_str) || !csp_validator::ContentSecurityPolicyIsSandboxed(sandbox_csp_str, extension->GetType())) { *error = GetInvalidManifestKeyError(manifest_key); @@ -268,6 +330,15 @@ return true; } +void CSPHandler::SetIsolatedWorldCSP(Extension* extension, + std::string isolated_world_csp) { + // By now we must have parsed the extension page CSP. + CSPInfo* csp_info = static_cast<CSPInfo*>( + extension->GetManifestData(keys::kContentSecurityPolicy)); + DCHECK(csp_info); + csp_info->isolated_world_csp = std::move(isolated_world_csp); +} + void CSPHandler::SetSandboxCSP(Extension* extension, std::string sandbox_csp) { CHECK(csp_validator::ContentSecurityPolicyIsSandboxed(sandbox_csp, extension->GetType())); @@ -276,7 +347,7 @@ CSPInfo* csp_info = static_cast<CSPInfo*>( extension->GetManifestData(keys::kContentSecurityPolicy)); DCHECK(csp_info); - csp_info->sandbox_content_security_policy = std::move(sandbox_csp); + csp_info->sandbox_csp = std::move(sandbox_csp); } bool CSPHandler::AlwaysParseForType(Manifest::Type type) const {
diff --git a/extensions/common/manifest_handlers/csp_info.h b/extensions/common/manifest_handlers/csp_info.h index 8b4e7d1..8a6b8591 100644 --- a/extensions/common/manifest_handlers/csp_info.h +++ b/extensions/common/manifest_handlers/csp_info.h
@@ -16,26 +16,35 @@ // A structure to hold the Content-Security-Policy information. struct CSPInfo : public Extension::ManifestData { - explicit CSPInfo(const std::string& security_policy); + explicit CSPInfo(std::string extension_pages_csp); ~CSPInfo() override; - // The Content-Security-Policy for an extension. Extensions can use - // Content-Security-Policies to mitigate cross-site scripting and other - // vulnerabilities. - std::string content_security_policy; + // The Content-Security-Policy for an extension. This is applied to an + // extension's background contexts i.e. its background page, event page and + // service worker. Extensions can use Content-Security-Policies to mitigate + // cross-site scripting and other vulnerabilities. + std::string extension_pages_csp; + + // Content security policy to be used for extension isolated worlds. + std::string isolated_world_csp; // Content Security Policy that should be used to enforce the sandbox used // by sandboxed pages (guaranteed to have the "sandbox" directive without the // "allow-same-origin" token). - std::string sandbox_content_security_policy; + std::string sandbox_csp; // Returns the CSP for the extension, or null if there is no defined CSP. Note // that for extensions, platform apps and legacy packaged apps, a default CSP // is used even if the manifest didn't specify one, so this will never be null // for those types. + // TODO(karandeepb): Rename to GetExtensionPagesCSP(). static const std::string* GetContentSecurityPolicy( const Extension* extension); + // Returns the Content Security Policy to be used for extension isolated + // worlds. + static const std::string& GetIsolatedWorldCSP(const Extension& extension); + // Returns the extension's Content Security Policy for the sandboxed pages. static const std::string& GetSandboxContentSecurityPolicy( const Extension* extension); @@ -68,6 +77,10 @@ base::StringPiece manifest_key, const base::Value* content_security_policy); + // Parses the content security policy specified in the manifest for isolated + // worlds. + bool ParseIsolatedWorldCSP(Extension* extension, base::string16* error); + // Parses the content security policy specified in the manifest for sandboxed // pages. This should be called after ParseExtensionPagesCSP. bool ParseSandboxCSP(Extension* extension, @@ -79,6 +92,10 @@ bool SetDefaultExtensionPagesCSP(Extension* extension, base::StringPiece manifest_key); + // Helper to set the isolated world content security policy manifest data. + void SetIsolatedWorldCSP(Extension* extension, + std::string isolated_world_csp); + // Helper to set the sandbox content security policy manifest data. void SetSandboxCSP(Extension* extension, std::string sandbox_csp);
diff --git a/extensions/common/manifest_handlers/csp_info_unittest.cc b/extensions/common/manifest_handlers/csp_info_unittest.cc index 63119eef..6f8996e 100644 --- a/extensions/common/manifest_handlers/csp_info_unittest.cc +++ b/extensions/common/manifest_handlers/csp_info_unittest.cc
@@ -22,6 +22,16 @@ return ErrorUtils::FormatErrorMessage(errors::kInvalidManifestKey, key); }; +const char kDefaultSandboxedPageCSP[] = + "sandbox allow-scripts allow-forms allow-popups allow-modals; " + "script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';"; +const char kDefaultExtensionPagesCSP[] = + "script-src 'self' blob: filesystem: chrome-extension-resource:; " + "object-src 'self' blob: filesystem:;"; +const char kDefaultIsolatedWorldCSP_BypassMainWorld[] = ""; +const char kDefaultIsolatedWorldCSP_Secure[] = + "script-src 'self'; object-src 'self'; worker-src 'self'"; + } // namespace using CSPInfoUnitTest = ManifestTest; @@ -55,35 +65,33 @@ scoped_refptr<Extension> extension7( LoadAndExpectSuccess("sandboxed_pages_valid_7.json")); - const char kSandboxedCSP[] = - "sandbox allow-scripts allow-forms allow-popups allow-modals; " - "script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';"; - const char kDefaultCSP[] = - "script-src 'self' blob: filesystem: chrome-extension-resource:; " - "object-src 'self' blob: filesystem:;"; const char kCustomSandboxedCSP[] = "sandbox; script-src 'self'; child-src 'self';"; - EXPECT_EQ(kSandboxedCSP, CSPInfo::GetResourceContentSecurityPolicy( - extension1.get(), "/test")); - EXPECT_EQ(kDefaultCSP, CSPInfo::GetResourceContentSecurityPolicy( - extension1.get(), "/none")); - EXPECT_EQ(kDefaultCSP, CSPInfo::GetResourceContentSecurityPolicy( - extension2.get(), "/test")); + EXPECT_EQ(kDefaultSandboxedPageCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension1.get(), "/test")); + EXPECT_EQ( + kDefaultExtensionPagesCSP, + CSPInfo::GetResourceContentSecurityPolicy(extension1.get(), "/none")); + EXPECT_EQ( + kDefaultExtensionPagesCSP, + CSPInfo::GetResourceContentSecurityPolicy(extension2.get(), "/test")); EXPECT_EQ(kCustomSandboxedCSP, CSPInfo::GetResourceContentSecurityPolicy( extension3.get(), "/test")); - EXPECT_EQ(kDefaultCSP, CSPInfo::GetResourceContentSecurityPolicy( - extension3.get(), "/none")); - EXPECT_EQ(kSandboxedCSP, CSPInfo::GetResourceContentSecurityPolicy( - extension4.get(), "/test")); - EXPECT_EQ(kSandboxedCSP, CSPInfo::GetResourceContentSecurityPolicy( - extension5.get(), "/path/test.ext")); - EXPECT_EQ(kDefaultCSP, CSPInfo::GetResourceContentSecurityPolicy( - extension5.get(), "/test")); + EXPECT_EQ( + kDefaultExtensionPagesCSP, + CSPInfo::GetResourceContentSecurityPolicy(extension3.get(), "/none")); + EXPECT_EQ(kDefaultSandboxedPageCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension4.get(), "/test")); + EXPECT_EQ(kDefaultSandboxedPageCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension5.get(), "/path/test.ext")); + EXPECT_EQ( + kDefaultExtensionPagesCSP, + CSPInfo::GetResourceContentSecurityPolicy(extension5.get(), "/test")); EXPECT_EQ(kCustomSandboxedCSP, CSPInfo::GetResourceContentSecurityPolicy( extension6.get(), "/test")); - EXPECT_EQ(kSandboxedCSP, CSPInfo::GetResourceContentSecurityPolicy( - extension7.get(), "/test")); + EXPECT_EQ(kDefaultSandboxedPageCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension7.get(), "/test")); Testcase testcases[] = { Testcase("sandboxed_pages_invalid_1.json", @@ -112,16 +120,13 @@ } TEST_F(CSPInfoUnitTest, CSPDictionary_ExtensionPages) { - const char kDefaultCSP[] = - "script-src 'self' blob: filesystem: chrome-extension-resource:; " - "object-src 'self' blob: filesystem:;"; struct { const char* file_name; const char* csp; } cases[] = { {"csp_dictionary_valid.json", "default-src 'none';"}, {"csp_empty_valid.json", "script-src 'self'; object-src 'self';"}, - {"csp_empty_dictionary_valid.json", kDefaultCSP}}; + {"csp_empty_dictionary_valid.json", kDefaultExtensionPagesCSP}}; // Verify that keys::kContentSecurityPolicy key can be used as a dictionary on // trunk. @@ -171,12 +176,6 @@ const char kCustomSandboxedCSP[] = "sandbox; script-src 'self'; child-src 'self';"; - const char kDefaultSandboxedPageCSP[] = - "sandbox allow-scripts allow-forms allow-popups allow-modals; " - "script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';"; - const char kDefaultExtensionPagesCSP[] = - "script-src 'self' blob: filesystem: chrome-extension-resource:; " - "object-src 'self' blob: filesystem:;"; const char kCustomExtensionPagesCSP[] = "script-src; object-src;"; struct { @@ -214,4 +213,73 @@ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR); } +TEST_F(CSPInfoUnitTest, CSPDictionary_IsolatedWorlds) { + ScopedCurrentChannel channel(version_info::Channel::UNKNOWN); + + struct { + const char* file_name; + const char* expected_csp; + } success_cases[] = { + {"isolated_world_csp_dictionary_default_v2.json", + kDefaultIsolatedWorldCSP_Secure}, + {"isolated_world_csp_no_dictionary_default_v2.json", + kDefaultIsolatedWorldCSP_BypassMainWorld}, + {"csp_dictionary_empty_v3.json", kDefaultIsolatedWorldCSP_Secure}, + {"csp_dictionary_missing_v3.json", kDefaultIsolatedWorldCSP_Secure}, + {"isolated_world_csp_valid.json", + "script-src 'self'; object-src http://localhost:80;"}}; + + for (const auto& test_case : success_cases) { + SCOPED_TRACE(test_case.file_name); + scoped_refptr<Extension> extension = + LoadAndExpectSuccess(test_case.file_name); + ASSERT_TRUE(extension); + EXPECT_EQ(test_case.expected_csp, CSPInfo::GetIsolatedWorldCSP(*extension)); + } + + const char* key = keys::kContentSecurityPolicy_IsolatedWorldPath; + Testcase invalid_cases[] = { + {"isolated_world_csp_invalid_type.json", GetInvalidManifestKeyError(key)}, + {"isolated_world_csp_missing_src.json", + ErrorUtils::FormatErrorMessage( + errors::kInvalidCSPMissingSecureSrc, + keys::kContentSecurityPolicy_IsolatedWorldPath, "script-src")}, + {"isolated_world_csp_insecure_src.json", + ErrorUtils::FormatErrorMessage( + manifest_errors::kInvalidCSPInsecureValueError, + manifest_keys::kContentSecurityPolicy_IsolatedWorldPath, + "google.com", "object-src")}, + }; + + RunTestcases(invalid_cases, base::size(invalid_cases), EXPECT_TYPE_ERROR); +} + +// Ensures that using a dictionary for the keys::kContentSecurityPolicy manifest +// key is mandatory for manifest v3 extensions and that defaults are applied +// correctly. +TEST_F(CSPInfoUnitTest, CSPDictionaryMandatoryForV3) { + ScopedCurrentChannel channel(version_info::Channel::UNKNOWN); + + LoadAndExpectError("csp_invalid_type_v3.json", + GetInvalidManifestKeyError(keys::kContentSecurityPolicy)); + + const char* default_case_filenames[] = {"csp_dictionary_empty_v3.json", + "csp_dictionary_missing_v3.json"}; + + for (const char* filename : default_case_filenames) { + SCOPED_TRACE(filename); + scoped_refptr<Extension> extension = LoadAndExpectSuccess(filename); + ASSERT_TRUE(extension); + + EXPECT_EQ(kDefaultIsolatedWorldCSP_Secure, + CSPInfo::GetIsolatedWorldCSP(*extension)); + EXPECT_EQ(kDefaultSandboxedPageCSP, + CSPInfo::GetSandboxContentSecurityPolicy(extension.get())); + const std::string* extension_pages_csp = + CSPInfo::GetContentSecurityPolicy(extension.get()); + ASSERT_TRUE(extension_pages_csp); + EXPECT_EQ(kDefaultExtensionPagesCSP, *extension_pages_csp); + } +} + } // namespace extensions
diff --git a/extensions/test/data/manifest_tests/csp_dictionary_empty_v3.json b/extensions/test/data/manifest_tests/csp_dictionary_empty_v3.json new file mode 100644 index 0000000..2feedfd --- /dev/null +++ b/extensions/test/data/manifest_tests/csp_dictionary_empty_v3.json
@@ -0,0 +1,6 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 3, + "content_security_policy" : {} +}
diff --git a/extensions/test/data/manifest_tests/csp_dictionary_missing_v3.json b/extensions/test/data/manifest_tests/csp_dictionary_missing_v3.json new file mode 100644 index 0000000..d4995330 --- /dev/null +++ b/extensions/test/data/manifest_tests/csp_dictionary_missing_v3.json
@@ -0,0 +1,5 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 3 +}
diff --git a/extensions/test/data/manifest_tests/csp_invalid_type_v3.json b/extensions/test/data/manifest_tests/csp_invalid_type_v3.json new file mode 100644 index 0000000..ae68c02 --- /dev/null +++ b/extensions/test/data/manifest_tests/csp_invalid_type_v3.json
@@ -0,0 +1,6 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 3, + "content_security_policy" : "default-src;" +}
diff --git a/extensions/test/data/manifest_tests/isolated_world_csp_dictionary_default_v2.json b/extensions/test/data/manifest_tests/isolated_world_csp_dictionary_default_v2.json new file mode 100644 index 0000000..d60c34ab --- /dev/null +++ b/extensions/test/data/manifest_tests/isolated_world_csp_dictionary_default_v2.json
@@ -0,0 +1,6 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 2, + "content_security_policy" : {} +}
diff --git a/extensions/test/data/manifest_tests/isolated_world_csp_insecure_src.json b/extensions/test/data/manifest_tests/isolated_world_csp_insecure_src.json new file mode 100644 index 0000000..8036f535 --- /dev/null +++ b/extensions/test/data/manifest_tests/isolated_world_csp_insecure_src.json
@@ -0,0 +1,14 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 3, + "content_scripts": [ + { + "matches": ["*://*/*"], + "js": ["contentScript.js"] + } + ], + "content_security_policy" : { + "isolated_world" : "script-src; default-src google.com" + } +}
diff --git a/extensions/test/data/manifest_tests/isolated_world_csp_invalid_type.json b/extensions/test/data/manifest_tests/isolated_world_csp_invalid_type.json new file mode 100644 index 0000000..965e0684 --- /dev/null +++ b/extensions/test/data/manifest_tests/isolated_world_csp_invalid_type.json
@@ -0,0 +1,14 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 3, + "content_scripts": [ + { + "matches": ["*://*/*"], + "js": ["contentScript.js"] + } + ], + "content_security_policy" : { + "isolated_world" : [] + } +}
diff --git a/extensions/test/data/manifest_tests/isolated_world_csp_missing_src.json b/extensions/test/data/manifest_tests/isolated_world_csp_missing_src.json new file mode 100644 index 0000000..103a039 --- /dev/null +++ b/extensions/test/data/manifest_tests/isolated_world_csp_missing_src.json
@@ -0,0 +1,14 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 2, + "content_scripts": [ + { + "matches": ["*://*/*"], + "js": ["contentScript.js"] + } + ], + "content_security_policy" : { + "isolated_world" : "object-src; worker-src 'self'" + } +}
diff --git a/extensions/test/data/manifest_tests/isolated_world_csp_no_dictionary_default_v2.json b/extensions/test/data/manifest_tests/isolated_world_csp_no_dictionary_default_v2.json new file mode 100644 index 0000000..f2dd8b8 --- /dev/null +++ b/extensions/test/data/manifest_tests/isolated_world_csp_no_dictionary_default_v2.json
@@ -0,0 +1,6 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 2, + "content_security_policy" : "script-src; default-src;" +}
diff --git a/extensions/test/data/manifest_tests/isolated_world_csp_valid.json b/extensions/test/data/manifest_tests/isolated_world_csp_valid.json new file mode 100644 index 0000000..ca28fe5b6 --- /dev/null +++ b/extensions/test/data/manifest_tests/isolated_world_csp_valid.json
@@ -0,0 +1,14 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 2, + "content_scripts": [ + { + "matches": ["*://*/*"], + "js": ["contentScript.js"] + } + ], + "content_security_policy" : { + "isolated_world" : "script-src 'self'; object-src http://localhost:80;" + } +}
diff --git a/fuchsia/BUILD.gn b/fuchsia/BUILD.gn index 77b04559..e681ba0a 100644 --- a/fuchsia/BUILD.gn +++ b/fuchsia/BUILD.gn
@@ -15,106 +15,6 @@ defines = [ "WEBRUNNER_IMPLEMENTATION" ] } -fuchsia_package("castrunner_pkg") { - binary = ":castrunner_exe" - package_name_override = "cast_runner" - sandbox_policy = "app/cast/sandbox_policy" -} - -fuchsia_package_runner("castrunner") { - package = ":castrunner_pkg" - package_name_override = "cast_runner" - install_only = true - package_deps = [ [ - ":service_pkg", - "chromium", - ] ] -} - -source_set("castrunner_common") { - sources = [ - "app/cast/bindings/cast_channel.cc", - "app/cast/bindings/cast_channel.h", - "app/cast/cast_runner.cc", - "app/cast/cast_runner.h", - ] - data = [ - "app/cast/bindings/cast_channel.js", - ] - deps = [ - ":mem_buffer_common", - ":named_message_port_connector", - ":web_fidl", - "//base", - "//url", - ] - public_deps = [ - ":cast_fidl", - ":webrunner_common", - ] - configs += [ ":webrunner_implementation" ] -} - -executable("castrunner_exe") { - sources = [ - "app/cast/main.cc", - ] - deps = [ - ":castrunner_common", - ":webrunner_common", - "//base", - ] -} - -source_set("castrunner_test_support") { - testonly = true - sources = [ - "app/cast/fake_application_config_manager.cc", - "app/cast/fake_application_config_manager.h", - "app/cast/test_common.cc", - "app/cast/test_common.h", - ] - public_deps = [ - ":cast_fidl", - "//base", - "//net:test_support", - "//third_party/fuchsia-sdk/sdk:sys", - ] -} - -test("castrunner_unittests") { - sources = [ - "app/cast/cast_runner_unittest.cc", - ] - deps = [ - ":castrunner_common", - ":castrunner_test_support", - ":test_support", - "//base/test:run_all_unittests", - "//base/test:test_support", - "//testing/gtest", - ] -} - -test("castrunner_integration_tests") { - sources = [ - "app/cast/cast_runner_integration_test.cc", - ] - deps = [ - ":castrunner_common", - ":castrunner_test_support", - ":test_support", - "//base/test:run_all_unittests", - "//base/test:test_support", - "//net:test_support", - "//testing/gtest", - ] - package_deps = [ [ - ":service_pkg", - "chromium", - ] ] -} - source_set("named_message_port_connector") { sources = [ "common/named_message_port_connector.cc", @@ -132,29 +32,6 @@ configs += [ ":webrunner_implementation" ] } -test("castrunner_browsertests") { - sources = [ - "app/cast/bindings/cast_channel_browsertest.cc", - ] - defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] - data = [ - "app/cast/test/data", - ] - deps = [ - ":browsertest_common", - ":castrunner_common", - ":mem_buffer_common", - ":named_message_port_connector", - ":test_support", - ":web_fidl", - "//base/test:test_support", - "//content/public/browser", - "//testing/gmock", - "//testing/gtest", - "//ui/ozone", - ] -} - source_set("mem_buffer_common") { sources = [ "common/fuchsia_export.h", @@ -167,52 +44,6 @@ ] } -fuchsia_package("webrunner_pkg") { - binary = ":webrunner_exe" - package_name_override = "web_runner" - sandbox_policy = "app/web/sandbox_policy" -} - -fuchsia_package_runner("webrunner") { - package = ":webrunner_pkg" - package_name_override = "web_runner" - install_only = true - package_deps = [ [ - ":service_pkg", - "chromium", - ] ] -} - -source_set("webrunner_common") { - sources = [ - "app/common/web_component.cc", - "app/common/web_component.h", - "app/common/web_content_runner.cc", - "app/common/web_content_runner.h", - ] - deps = [ - ":web_fidl", - "//base", - "//third_party/fuchsia-sdk/sdk:ui_app", - "//third_party/fuchsia-sdk/sdk:ui_viewsv1", - "//url", - ] - public_deps = [ - "//third_party/fuchsia-sdk/sdk:sys", - ] -} - -executable("webrunner_exe") { - sources = [ - "app/web/main.cc", - ] - deps = [ - ":web_fidl", - ":webrunner_common", - "//base", - ] -} - source_set("test_support") { testonly = true sources = [ @@ -448,31 +279,6 @@ ] } -test("webrunner_smoketests") { - sources = [ - "app/web/webrunner_smoke_test.cc", - ] - deps = [ - ":test_support", - "//base", - "//base/test:run_all_unittests", - "//base/test:test_support", - "//net:test_support", - "//testing/gtest", - "//third_party/fuchsia-sdk/sdk:sys", - ] - package_deps = [ - [ - ":service_pkg", - "chromium", - ], - [ - ":webrunner_pkg", - "web_runner", - ], - ] -} - fidl_library("web_fidl") { library_name = "web" namespace = "chromium" @@ -554,19 +360,19 @@ # Puts copies of files at the top level of the CIPD archive's structure. copy("restaged_packages") { sources = [ - "$root_gen_dir/fuchsia/cast_runner/cast_runner.far", "$root_gen_dir/fuchsia/chromium/chromium.far", "$root_gen_dir/fuchsia/http/http/http.far", - "$root_gen_dir/fuchsia/web_runner/web_runner.far", + "$root_gen_dir/fuchsia/runners/cast_runner/cast_runner.far", + "$root_gen_dir/fuchsia/runners/web_runner/web_runner.far", ] outputs = [ "$_artifact_root/{{source_file_part}}", ] deps = [ - ":castrunner_pkg", ":service_pkg", - ":webrunner_pkg", - "http:http_pkg", + "//fuchsia/http:http_pkg", + "//fuchsia/runners:cast_runner_pkg", + "//fuchsia/runners:web_runner_pkg", ] }
diff --git a/fuchsia/fidl/cast/application_config.fidl b/fuchsia/fidl/cast/application_config.fidl index cb9b1b2..a312e26 100644 --- a/fuchsia/fidl/cast/application_config.fidl +++ b/fuchsia/fidl/cast/application_config.fidl
@@ -4,21 +4,21 @@ library chromium.cast; -// Describes the configuration under which a Cast application should run. +/// Describes the configuration under which a Cast application should run. struct ApplicationConfig { - // Cast application Id. + /// Cast application Id. string id; - // Name to display to the user when referring to this application. + /// Name to display to the user when referring to this application. string display_name; - // Standard web URL from which to load the application. + /// Standard web URL from which to load the application. string web_url; }; -// Service interface for working with application configurations. +/// Service interface for working with application configurations. [Discoverable] interface ApplicationConfigManager { - // Returns the ApplicationConfig for the specified application Id. + /// Returns the ApplicationConfig for the specified application Id. 1: GetConfig(string id) -> (ApplicationConfig? config); };
diff --git a/fuchsia/fidl/cast/cast_channel.fidl b/fuchsia/fidl/cast/cast_channel.fidl index 2b6331a6..3ec3374fb 100644 --- a/fuchsia/fidl/cast/cast_channel.fidl +++ b/fuchsia/fidl/cast/cast_channel.fidl
@@ -8,10 +8,10 @@ [Discoverable] interface CastChannel { - // Handles Cast Channel open calls from the webpage. - // The new Cast Channel's message port is returned asynchronously once - // opened by the webpage. The port is disconnected when the peer's Cast - // Channel is closed. + /// Handles Cast Channel open calls from the webpage. + /// The new Cast Channel's message port is returned asynchronously once + /// opened by the webpage. The port is disconnected when the peer's Cast + /// Channel is closed. 1: Connect() -> (chromium.web.MessagePort channel); };
diff --git a/fuchsia/fidl/web/context.fidl b/fuchsia/fidl/web/context.fidl index 7de9089e..923e99c 100644 --- a/fuchsia/fidl/web/context.fidl +++ b/fuchsia/fidl/web/context.fidl
@@ -4,11 +4,11 @@ library chromium.web; -// Manages browsing state (e.g. LocalStorage, cookies, etc) associated with -// a set of Frames. +/// Manages browsing state (e.g. LocalStorage, cookies, etc) associated with +/// a set of Frames. interface Context { - // Creates a new frame under this Context. - // - // |frame|: An interface request that will be bound to the created Frame. + /// Creates a new frame under this Context. + /// + /// |frame|: An interface request that will be bound to the created Frame. CreateFrame(request<Frame> frame); };
diff --git a/fuchsia/fidl/web/context_provider.fidl b/fuchsia/fidl/web/context_provider.fidl index 9559c2dc..dc92e47 100644 --- a/fuchsia/fidl/web/context_provider.fidl +++ b/fuchsia/fidl/web/context_provider.fidl
@@ -4,26 +4,26 @@ library chromium.web; -// The top-level service interface which allows for the creation of -// Context resources. +/// The top-level service interface which allows for the creation of +/// Context resources. [Discoverable] interface ContextProvider { - // Creates a new browser Context whose state is wholly independent and - // isolated from other Contexts. - // - // context: An interface request which will receive a bound Context - // service. + /// Creates a new browser Context whose state is wholly independent and + /// isolated from other Contexts. + /// + /// context: An interface request which will receive a bound Context + /// service. Create(CreateContextParams params, request<Context> context); }; struct CreateContextParams { - // Service directory to be used by the context. + /// Service directory to be used by the context. // TODO(https://crbug.com/870057): Document required and optional services // that Context needs. handle<channel> service_directory; - // Handle to the directory that will contain the Context's - // persistent data. If it is left unset, then the created Context will be - // stateless, with all of its data discarded upon Context destruction. + /// Handle to the directory that will contain the Context's + /// persistent data. If it is left unset, then the created Context will be + /// stateless, with all of its data discarded upon Context destruction. handle<channel>? data_directory; };
diff --git a/fuchsia/fidl/web/frame.fidl b/fuchsia/fidl/web/frame.fidl index e1cf627..9141a706 100644 --- a/fuchsia/fidl/web/frame.fidl +++ b/fuchsia/fidl/web/frame.fidl
@@ -9,24 +9,31 @@ using fuchsia.ui.viewsv1token; enum ExecuteMode { - IMMEDIATE_ONCE = 1; // Will evaluate the script immediately. - ON_PAGE_LOAD = 2; // Will evaluate the script on all subsequent page loads. + /// Evaluate the script immediately. + IMMEDIATE_ONCE = 1; + /// Evaluate the script on all subsequent page loads. + ON_PAGE_LOAD = 2; }; enum LogLevel : int32 { - NONE = 100; // No logging. - DEBUG = -1; // Outputs messages from console.debug(). - INFO = 0; // Outputs messages from console.log(). - WARN = 1; // Outputs messages from console.warn(). - ERROR = 2; // Outputs messages from console.error(). + /// No logging. + NONE = 100; + /// Outputs messages from console.debug(). + DEBUG = -1; + /// Outputs messages from console.log(). + INFO = 0; + /// Outputs messages from console.warn(). + WARN = 1; + /// Outputs messages from console.error(). + ERROR = 2; }; interface Frame { - // Creates a new view using the specified |view_token|. Caller should pass the - // other end of the token to CreateViewHolderCmd() to attach the new view to a - // the view tree. - // - // |view_token|: Token for the new view. + /// Creates a new view using the specified |view_token|. Caller should pass + /// the other end of the token to CreateViewHolderCmd() to attach the new view + /// to a the view tree. + /// + /// |view_token|: Token for the new view. CreateView2(handle<eventpair> view_token, request<fuchsia.sys.ServiceProvider>? incoming_services, fuchsia.sys.ServiceProvider? outgoing_services); @@ -37,70 +44,70 @@ CreateView(request<fuchsia.ui.viewsv1token.ViewOwner> view_owner, request<fuchsia.sys.ServiceProvider>? services); - // Returns an interface through which the frame may be navigated to - // a desired URL, reloaded, etc. - // - // |view_provider|: An interface request for the Frame's - // NavigationController. + /// Returns an interface through which the frame may be navigated to + /// a desired URL, reloaded, etc. + /// + /// |view_provider|: An interface request for the Frame's + /// NavigationController. GetNavigationController(request<NavigationController> controller); - // Executes |script| in the frame if the frame's URL has an origin which - // matches entries in |origins|. - // At least one |origins| entry must be specified. - // If a wildcard "*" is specified in |origins|, then the script will be - // evaluated for all documents. - // If |mode| is NOW, then the script is evaluated immediately. - // If |mode| is ON_PAGE_LOAD, then the script is evaluated on every future - // document load prior to the page's script's execution. - // - // Multiple scripts can be registered by calling ExecuteJavascript() - // repeatedly. - // - // Note that scripts share the same execution context as the document, - // meaning that document may modify variables, classes, or objects set by the - // script in arbitrary or unpredictable ways. + /// Executes |script| in the frame if the frame's URL has an origin which + /// matches entries in |origins|. + /// At least one |origins| entry must be specified. + /// If a wildcard "*" is specified in |origins|, then the script will be + /// evaluated for all documents. + /// If |mode| is NOW, then the script is evaluated immediately. + /// If |mode| is ON_PAGE_LOAD, then the script is evaluated on every future + /// document load prior to the page's script's execution. + /// + /// Multiple scripts can be registered by calling ExecuteJavascript() + /// repeatedly. + /// + /// Note that scripts share the same execution context as the document, + /// meaning that document may modify variables, classes, or objects set by the + /// script in arbitrary or unpredictable ways. // TODO(crbug.com/900391): Investigate if we can run the scripts in isolated // JS worlds. - // - // Returns |true| if the script was executed, |false| if the script was - // rejected due to injection being blocked by the parent Context, or because - // the script's text encoding was invalid. + /// + /// Returns |true| if the script was executed, |false| if the script was + /// rejected due to injection being blocked by the parent Context, or because + /// the script's text encoding was invalid. ExecuteJavaScript( vector<string> origins, fuchsia.mem.Buffer script, ExecuteMode mode) -> (bool success); - // Posts a message to the frame's onMessage handler. - // - // |targetOrigin| restricts message delivery to the specified origin. - // If |targetOrigin| is "*", then the message will be sent to the document - // regardless of its origin. - // See html.spec.whatwg.org/multipage/web-messaging.html sect. 9.4.3 - // for more details on how the target origin policy is applied. - // - // Returns |false| if |message| is invalid or |targetOrigin| is missing. + /// Posts a message to the frame's onMessage handler. + /// + /// |targetOrigin| restricts message delivery to the specified origin. + /// If |targetOrigin| is "*", then the message will be sent to the document + /// regardless of its origin. + /// See html.spec.whatwg.org/multipage/web-messaging.html sect. 9.4.3 + /// for more details on how the target origin policy is applied. + /// + /// Returns |false| if |message| is invalid or |targetOrigin| is missing. PostMessage(WebMessage message, string targetOrigin) -> (bool success); - // Sets the observer for handling page navigation events. - // - // |observer|: The observer to use. Unregisters any existing observers - // if null. + /// Sets the observer for handling page navigation events. + /// + /// |observer|: The observer to use. Unregisters any existing observers + /// if null. SetNavigationEventObserver(NavigationEventObserver? observer); - // If set to a value other than NONE, allows web content to log messages - // to the system logger using console.log(), console.info(), console.warn(), - // and console.error(). + /// If set to a value other than NONE, allows web content to log messages + /// to the system logger using console.log(), console.info(), console.warn(), + /// and console.error(). SetJavaScriptLogLevel(LogLevel level); }; struct WebMessage { - // The message payload, encoded as an UTF-8 string. + /// The message payload, encoded as an UTF-8 string. fuchsia.mem.Buffer data; - // List of objects transferred into the MessagePort from the FIDL client. + /// List of objects transferred into the MessagePort from the FIDL client. // TODO(crbug.com/893236): make this a vector when FIDL-354 is fixed. IncomingTransferable? incoming_transfer; - // List of objects transferred out of the MessagePort to the FIDL client. + /// List of objects transferred out of the MessagePort to the FIDL client. OutgoingTransferable? outgoing_transfer; }; @@ -112,19 +119,19 @@ MessagePort message_port; }; -// Represents one end of an HTML5 MessageChannel. Can be used to send -// and exchange Messages with the peered MessagePort in the Frame's script -// context. The port is destroyed when either end of the MessagePort channel -// is torn down. +/// Represents one end of an HTML5 MessageChannel. Can be used to send +/// and exchange Messages with the peered MessagePort in the Frame's script +/// context. The port is destroyed when either end of the MessagePort channel +/// is torn down. interface MessagePort { - // Sends a WebMessage to the peer. + /// Sends a WebMessage to the peer. PostMessage(WebMessage message) -> (bool success); - // Asynchronously reads the next message from the channel. - // The client should invoke the callback when it is ready to process - // another message. - // Unreceived messages are buffered on the sender's side and bounded - // by its available resources. + /// Asynchronously reads the next message from the channel. + /// The client should invoke the callback when it is ready to process + /// another message. + /// Unreceived messages are buffered on the sender's side and bounded + /// by its available resources. ReceiveMessage() -> (WebMessage message); };
diff --git a/fuchsia/fidl/web/navigation_controller.fidl b/fuchsia/fidl/web/navigation_controller.fidl index c30cbe9..4103cf3 100644 --- a/fuchsia/fidl/web/navigation_controller.fidl +++ b/fuchsia/fidl/web/navigation_controller.fidl
@@ -4,14 +4,14 @@ library chromium.web; -// Provides methods for controlling and querying the navigation state -// of a Frame. +/// Provides methods for controlling and querying the navigation state +/// of a Frame. interface NavigationController { - // Tells the Frame to navigate to a |url|. - // - // |url|: The address to navigate to. - // |params|: Additional parameters that affect how the resource will be - // loaded (e.g. cookies, HTTP headers, etc.) + /// Tells the Frame to navigate to a |url|. + /// + /// |url|: The address to navigate to. + /// |params|: Additional parameters that affect how the resource will be + /// loaded (e.g. cookies, HTTP headers, etc.) LoadUrl(string url, LoadUrlParams? params); GoBack(); @@ -19,48 +19,53 @@ Stop(); Reload(ReloadType type); - // Returns information for the currently visible content regardless of - // loading state, or a null entry if no content is being displayed. + /// Returns information for the currently visible content regardless of + /// loading state, or a null entry if no content is being displayed. GetVisibleEntry() -> (NavigationEntry? entry); }; -// Additional parameters for modifying the behavior of LoadUrl(). +/// Additional parameters for modifying the behavior of LoadUrl(). struct LoadUrlParams { - // Provides a hint to the browser UI about how LoadUrl was triggered. + /// Provides a hint to the browser UI about how LoadUrl was triggered. LoadUrlReason type; - // The URL that linked to the resource being requested. + /// The URL that linked to the resource being requested. string referrer; - // Should be set to true to propagate user activation to the frame. User - // activation implies that the user is interacting with the web frame. It - // enables some web features that are not available otherwise. For example - // autoplay will work only when this flag is set to true. + /// Should be set to true to propagate user activation to the frame. User + /// activation implies that the user is interacting with the web frame. It + /// enables some web features that are not available otherwise. For example + /// autoplay will work only when this flag is set to true. bool user_activated = false; - // Custom HTTP headers. + /// Custom HTTP headers. vector<vector<uint8>> headers; }; -// Characterizes the origin of a LoadUrl request. +/// Characterizes the origin of a LoadUrl request. enum LoadUrlReason { - LINK = 0; // Navigation was initiated by the user following a link. - TYPED = 1; // Navigation was initiated by a user-provided URL. + /// Navigation was initiated by the user following a link. + LINK = 0; + /// Navigation was initiated by a user-provided URL. + TYPED = 1; }; -// Contains information about the Frame's navigation state. -// The Frame's navigation history can be represented as an aggregation of -// NavigationEntries. +/// Contains information about the Frame's navigation state. +/// The Frame's navigation history can be represented as an aggregation of +/// NavigationEntries. struct NavigationEntry { - string url; // The page's URL. - string title; // The user-visible page title. - bool is_error; // Indicates if an error occurred during this navigation. + /// The page's URL. + string url; + /// The user-visible page title. + string title; + /// Indicates if an error occurred during this navigation. + bool is_error; }; enum ReloadType { - // Reloads the current entry, bypassing the cache for the main resource. + /// Reloads the current entry, bypassing the cache for the main resource. PARTIAL_CACHE = 0; - // Reloads the current entry, bypassing the cache entirely. + /// Reloads the current entry, bypassing the cache entirely. NO_CACHE = 1; };
diff --git a/fuchsia/fidl/web/navigation_event_observer.fidl b/fuchsia/fidl/web/navigation_event_observer.fidl index a724b629..5bb988b 100644 --- a/fuchsia/fidl/web/navigation_event_observer.fidl +++ b/fuchsia/fidl/web/navigation_event_observer.fidl
@@ -4,22 +4,22 @@ library chromium.web; -// Indicates the properties of the NavigationController's visible content -// which have changed since the last OnNavigationStateChanged() event. -// Any unchanged properties are left unset. +/// Indicates the properties of the NavigationController's visible content +/// which have changed since the last OnNavigationStateChanged() event. +/// Any unchanged properties are left unset. struct NavigationEvent { string? url; string? title; bool is_error; }; -// Interface supplied by the embedder for receiving notifications about -// navigation events in a Frame. +/// Interface supplied by the embedder for receiving notifications about +/// navigation events in a Frame. interface NavigationEventObserver { - // Called when user-visible navigation state has changed since Frame - // creation or the last acknowledgement callback, whichever occurred later. - // |change| will contain all the differences in navigation state since the - // last acknowledgement. + /// Called when user-visible navigation state has changed since Frame + /// creation or the last acknowledgement callback, whichever occurred later. + /// |change| will contain all the differences in navigation state since the + /// last acknowledgement. OnNavigationStateChanged(NavigationEvent change) -> (); };
diff --git a/fuchsia/runners/BUILD.gn b/fuchsia/runners/BUILD.gn new file mode 100644 index 0000000..e04a406c --- /dev/null +++ b/fuchsia/runners/BUILD.gn
@@ -0,0 +1,205 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_fuchsia) + +import("//build/config/fuchsia/rules.gni") +import("//testing/test.gni") + +# Files common to both cast_runner and web_runner targets. +source_set("common") { + sources = [ + "common/web_component.cc", + "common/web_component.h", + "common/web_content_runner.cc", + "common/web_content_runner.h", + ] + deps = [ + "//base", + "//third_party/fuchsia-sdk/sdk:ui_app", + "//third_party/fuchsia-sdk/sdk:ui_viewsv1", + "//url", + ] + public_deps = [ + "//fuchsia:web_fidl", + "//third_party/fuchsia-sdk/sdk:sys", + ] + visibility = [ ":*" ] +} + +source_set("cast_runner_core") { + sources = [ + "cast/bindings/cast_channel.cc", + "cast/bindings/cast_channel.h", + "cast/cast_runner.cc", + "cast/cast_runner.h", + ] + data = [ + "cast/bindings/cast_channel.js", + ] + deps = [ + "//base", + "//fuchsia:mem_buffer_common", + "//fuchsia:named_message_port_connector", + "//url", + ] + public_deps = [ + ":common", + "//fuchsia:cast_fidl", + ] + configs += [ "//fuchsia:webrunner_implementation" ] + visibility = [ ":*" ] +} + +executable("cast_runner_exe") { + sources = [ + "cast/main.cc", + ] + deps = [ + ":cast_runner_core", + ":common", + "//base", + ] + visibility = [ ":*" ] +} + +fuchsia_package("cast_runner_pkg") { + binary = ":cast_runner_exe" + package_name_override = "cast_runner" + sandbox_policy = "cast/sandbox_policy" +} + +fuchsia_package_runner("cast_runner") { + package = ":cast_runner_pkg" + package_name_override = "cast_runner" + install_only = true + package_deps = [ [ + "//fuchsia:service_pkg", + "chromium", + ] ] +} + +source_set("cast_runner_test_core") { + testonly = true + sources = [ + "cast/fake_application_config_manager.cc", + "cast/fake_application_config_manager.h", + "cast/test_common.cc", + "cast/test_common.h", + ] + public_deps = [ + "//base", + "//fuchsia:cast_fidl", + "//net:test_support", + "//third_party/fuchsia-sdk/sdk:sys", + ] + visibility = [ ":*" ] +} + +test("cast_runner_unittests") { + sources = [ + "cast/cast_runner_unittest.cc", + ] + deps = [ + ":cast_runner_core", + ":cast_runner_test_core", + "//base/test:run_all_unittests", + "//base/test:test_support", + "//fuchsia:test_support", + "//testing/gtest", + ] +} + +test("cast_runner_integration_tests") { + sources = [ + "cast/cast_runner_integration_test.cc", + ] + deps = [ + ":cast_runner_core", + ":cast_runner_test_core", + "//base/test:run_all_unittests", + "//base/test:test_support", + "//fuchsia:test_support", + "//net:test_support", + "//testing/gtest", + ] + package_deps = [ [ + "//fuchsia:service_pkg", + "chromium", + ] ] +} + +test("cast_runner_browsertests") { + sources = [ + "cast/bindings/cast_channel_browsertest.cc", + ] + defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + data = [ + "cast/testdata", + ] + deps = [ + ":cast_runner_core", + "//base/test:test_support", + "//content/public/browser", + "//fuchsia:browsertest_common", + "//fuchsia:mem_buffer_common", + "//fuchsia:named_message_port_connector", + "//fuchsia:test_support", + "//testing/gmock", + "//testing/gtest", + "//ui/ozone", + ] +} + +executable("web_runner_exe") { + sources = [ + "web/main.cc", + ] + deps = [ + ":common", + "//base", + ] + visibility = [ ":*" ] +} + +fuchsia_package("web_runner_pkg") { + binary = ":web_runner_exe" + package_name_override = "web_runner" + sandbox_policy = "web/sandbox_policy" +} + +fuchsia_package_runner("web_runner") { + package = ":web_runner_pkg" + package_name_override = "web_runner" + install_only = true + package_deps = [ [ + "//fuchsia:service_pkg", + "chromium", + ] ] +} + +test("web_runner_integration_tests") { + sources = [ + "web/web_runner_smoke_test.cc", + ] + deps = [ + "//base", + "//base/test:run_all_unittests", + "//base/test:test_support", + "//fuchsia:test_support", + "//net:test_support", + "//testing/gtest", + "//third_party/fuchsia-sdk/sdk:sys", + ] + package_deps = [ + [ + "//fuchsia:service_pkg", + "chromium", + ], + [ + ":web_runner_pkg", + "web_runner", + ], + ] +}
diff --git a/fuchsia/app/cast/bindings/cast_channel.cc b/fuchsia/runners/cast/bindings/cast_channel.cc similarity index 93% rename from fuchsia/app/cast/bindings/cast_channel.cc rename to fuchsia/runners/cast/bindings/cast_channel.cc index 99980cb..5066bd97 100644 --- a/fuchsia/app/cast/bindings/cast_channel.cc +++ b/fuchsia/runners/cast/bindings/cast_channel.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "fuchsia/app/cast/bindings/cast_channel.h" +#include "fuchsia/runners/cast/bindings/cast_channel.h" #include <lib/fit/function.h> #include <string> @@ -17,9 +17,6 @@ #include "base/threading/thread_task_runner_handle.h" #include "fuchsia/common/mem_buffer_util.h" #include "fuchsia/common/named_message_port_connector.h" -#include "fuchsia/fidl/chromium/web/cpp/fidl.h" - -namespace castrunner { // Unique identifier of the Cast Channel message port, used by the JavaScript // API to connect to the port. @@ -43,7 +40,7 @@ base::FilePath assets_path; CHECK(base::PathService::Get(base::DIR_ASSETS, &assets_path)); fuchsia::mem::Buffer bindings_buf = webrunner::MemBufferFromFile(base::File( - assets_path.AppendASCII("fuchsia/app/cast/bindings/cast_channel.js"), + assets_path.AppendASCII("fuchsia/runners/cast/bindings/cast_channel.js"), base::File::FLAG_OPEN | base::File::FLAG_READ)); CHECK(bindings_buf.vmo); @@ -118,5 +115,3 @@ pending_channel_ = std::move(message.incoming_transfer->message_port()); } - -} // namespace castrunner
diff --git a/fuchsia/app/cast/bindings/cast_channel.h b/fuchsia/runners/cast/bindings/cast_channel.h similarity index 89% rename from fuchsia/app/cast/bindings/cast_channel.h rename to fuchsia/runners/cast/bindings/cast_channel.h index f7bb683..e8d1601 100644 --- a/fuchsia/app/cast/bindings/cast_channel.h +++ b/fuchsia/runners/cast/bindings/cast_channel.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FUCHSIA_APP_CAST_BINDINGS_CAST_CHANNEL_H_ -#define FUCHSIA_APP_CAST_BINDINGS_CAST_CHANNEL_H_ +#ifndef FUCHSIA_RUNNERS_CAST_BINDINGS_CAST_CHANNEL_H_ +#define FUCHSIA_RUNNERS_CAST_BINDINGS_CAST_CHANNEL_H_ #include <string> @@ -12,14 +12,11 @@ #include "base/strings/string_piece.h" #include "fuchsia/common/fuchsia_export.h" #include "fuchsia/fidl/chromium/cast/cpp/fidl.h" -#include "fuchsia/fidl/chromium/web/cpp/fidl.h" namespace webrunner { class NamedMessagePortConnector; } -namespace castrunner { - // Handles the injection of cast.__platform__.channel bindings into pages' // scripting context, and establishes a bidirectional message pipe over // which the two communicate. @@ -66,6 +63,4 @@ DISALLOW_COPY_AND_ASSIGN(CastChannelImpl); }; -} // namespace castrunner - -#endif // FUCHSIA_APP_CAST_BINDINGS_CAST_CHANNEL_H_ +#endif // FUCHSIA_RUNNERS_CAST_BINDINGS_CAST_CHANNEL_H_
diff --git a/fuchsia/app/cast/bindings/cast_channel.js b/fuchsia/runners/cast/bindings/cast_channel.js similarity index 100% rename from fuchsia/app/cast/bindings/cast_channel.js rename to fuchsia/runners/cast/bindings/cast_channel.js
diff --git a/fuchsia/app/cast/bindings/cast_channel_browsertest.cc b/fuchsia/runners/cast/bindings/cast_channel_browsertest.cc similarity index 97% rename from fuchsia/app/cast/bindings/cast_channel_browsertest.cc rename to fuchsia/runners/cast/bindings/cast_channel_browsertest.cc index 9c146bc..65779fe0 100644 --- a/fuchsia/app/cast/bindings/cast_channel_browsertest.cc +++ b/fuchsia/runners/cast/bindings/cast_channel_browsertest.cc
@@ -11,16 +11,14 @@ #include "base/path_service.h" #include "base/test/test_timeouts.h" #include "base/threading/thread_restrictions.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/url_constants.h" -#include "fuchsia/app/cast/bindings/cast_channel.h" #include "fuchsia/common/mem_buffer_util.h" #include "fuchsia/common/named_message_port_connector.h" #include "fuchsia/common/test/test_common.h" #include "fuchsia/common/test/webrunner_browser_test.h" +#include "fuchsia/runners/cast/bindings/cast_channel.h" #include "fuchsia/test/promise.h" - -namespace castrunner { +#include "testing/gtest/include/gtest/gtest.h" +#include "url/url_constants.h" // Use a shorter name for NavigationEvent, because it is // referenced frequently in this file. @@ -30,7 +28,7 @@ public chromium::web::NavigationEventObserver { public: CastChannelImplTest() : run_timeout_(TestTimeouts::action_timeout()) { - set_test_server_root(base::FilePath("fuchsia/app/cast/test/data")); + set_test_server_root(base::FilePath("fuchsia/runners/cast/testdata")); } ~CastChannelImplTest() override = default; @@ -218,5 +216,3 @@ CheckLoadUrl(empty_url.spec(), controller.get()); } } - -} // namespace castrunner
diff --git a/fuchsia/app/cast/cast_runner.cc b/fuchsia/runners/cast/cast_runner.cc similarity index 80% rename from fuchsia/app/cast/cast_runner.cc rename to fuchsia/runners/cast/cast_runner.cc index 8482ace..10e4b80 100644 --- a/fuchsia/app/cast/cast_runner.cc +++ b/fuchsia/runners/cast/cast_runner.cc
@@ -2,25 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "fuchsia/app/cast/cast_runner.h" +#include "fuchsia/runners/cast/cast_runner.h" #include <fuchsia/sys/cpp/fidl.h> #include <utility> #include "base/logging.h" -#include "fuchsia/app/common/web_component.h" +#include "fuchsia/runners/common/web_component.h" #include "url/gurl.h" -namespace castrunner { - CastRunner::CastRunner( base::fuchsia::ServiceDirectory* service_directory, chromium::web::ContextPtr context, chromium::cast::ApplicationConfigManagerPtr app_config_manager, base::OnceClosure on_idle_closure) - : webrunner::WebContentRunner(service_directory, - std::move(context), - std::move(on_idle_closure)), + : WebContentRunner(service_directory, + std::move(context), + std::move(on_idle_closure)), app_config_manager_(std::move(app_config_manager)) {} CastRunner::~CastRunner() = default; @@ -65,15 +63,13 @@ // For test purposes, we need to call RegisterComponent even if there is no // URL to launch. - RegisterComponent(std::unique_ptr<webrunner::WebComponent>(nullptr)); + RegisterComponent(std::unique_ptr<WebComponent>(nullptr)); return; } // If a config was returned then use it to launch a component. GURL cast_app_url(app_config->web_url); - RegisterComponent(webrunner::WebComponent::ForUrlRequest( - this, std::move(cast_app_url), std::move(startup_info), - std::move(controller_request))); + RegisterComponent(WebComponent::ForUrlRequest(this, std::move(cast_app_url), + std::move(startup_info), + std::move(controller_request))); } - -} // namespace castrunner
diff --git a/fuchsia/app/cast/cast_runner.h b/fuchsia/runners/cast/cast_runner.h similarity index 82% rename from fuchsia/app/cast/cast_runner.h rename to fuchsia/runners/cast/cast_runner.h index 47cbe92..da1b86a 100644 --- a/fuchsia/app/cast/cast_runner.h +++ b/fuchsia/runners/cast/cast_runner.h
@@ -2,19 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FUCHSIA_APP_CAST_CAST_RUNNER_H_ -#define FUCHSIA_APP_CAST_CAST_RUNNER_H_ +#ifndef FUCHSIA_RUNNERS_CAST_CAST_RUNNER_H_ +#define FUCHSIA_RUNNERS_CAST_CAST_RUNNER_H_ #include "base/callback.h" #include "base/macros.h" -#include "fuchsia/app/common/web_content_runner.h" #include "fuchsia/fidl/chromium/cast/cpp/fidl.h" #include "fuchsia/fidl/chromium/web/cpp/fidl.h" - -namespace castrunner { +#include "fuchsia/runners/common/web_content_runner.h" // sys::Runner which instantiates Cast activities specified via cast/casts URIs. -class CastRunner : public webrunner::WebContentRunner { +class CastRunner : public WebContentRunner { public: CastRunner(base::fuchsia::ServiceDirectory* service_directory, chromium::web::ContextPtr context, @@ -41,6 +39,4 @@ DISALLOW_COPY_AND_ASSIGN(CastRunner); }; -} // namespace castrunner - -#endif // FUCHSIA_APP_CAST_CAST_RUNNER_H_ +#endif // FUCHSIA_RUNNERS_CAST_CAST_RUNNER_H_
diff --git a/fuchsia/app/cast/cast_runner_integration_test.cc b/fuchsia/runners/cast/cast_runner_integration_test.cc similarity index 90% rename from fuchsia/app/cast/cast_runner_integration_test.cc rename to fuchsia/runners/cast/cast_runner_integration_test.cc index 04febc93..3f8b577 100644 --- a/fuchsia/app/cast/cast_runner_integration_test.cc +++ b/fuchsia/runners/cast/cast_runner_integration_test.cc
@@ -11,16 +11,14 @@ #include "base/message_loop/message_loop.h" #include "base/strings/stringprintf.h" #include "base/test/test_timeouts.h" -#include "fuchsia/app/cast/cast_runner.h" -#include "fuchsia/app/cast/fake_application_config_manager.h" -#include "fuchsia/app/cast/test_common.h" -#include "fuchsia/app/common/web_component.h" -#include "fuchsia/app/common/web_content_runner.h" +#include "fuchsia/runners/cast/cast_runner.h" +#include "fuchsia/runners/cast/fake_application_config_manager.h" +#include "fuchsia/runners/cast/test_common.h" +#include "fuchsia/runners/common/web_component.h" +#include "fuchsia/runners/common/web_content_runner.h" #include "fuchsia/test/promise.h" #include "testing/gtest/include/gtest/gtest.h" -namespace castrunner { - namespace { void ComponentErrorHandler(zx_status_t status) { @@ -57,7 +55,7 @@ // Create the CastRunner, published into |test_service_directory_|. cast_runner_ = std::make_unique<CastRunner>( test_service_directory_.get(), - webrunner::WebContentRunner::CreateDefaultWebContext(), + WebContentRunner::CreateDefaultWebContext(), std::move(app_config_manager_interface), cast_runner_run_loop_.QuitClosure()); @@ -117,8 +115,7 @@ chromium::web::NavigationControllerPtr nav_controller; { base::RunLoop run_loop; - webrunner::Promise<webrunner::WebComponent*> web_component( - run_loop.QuitClosure()); + webrunner::Promise<WebComponent*> web_component(run_loop.QuitClosure()); cast_runner_->GetWebComponentForTest(web_component.GetReceiveCallback()); run_loop.Run(); ASSERT_NE(*web_component, nullptr); @@ -149,11 +146,8 @@ // Ensure no WebComponent was created. base::RunLoop run_loop; - webrunner::Promise<webrunner::WebComponent*> web_component( - run_loop.QuitClosure()); + webrunner::Promise<WebComponent*> web_component(run_loop.QuitClosure()); cast_runner_->GetWebComponentForTest(web_component.GetReceiveCallback()); run_loop.Run(); EXPECT_EQ(*web_component, nullptr); } - -} // namespace castrunner
diff --git a/fuchsia/app/cast/cast_runner_unittest.cc b/fuchsia/runners/cast/cast_runner_unittest.cc similarity index 95% rename from fuchsia/app/cast/cast_runner_unittest.cc rename to fuchsia/runners/cast/cast_runner_unittest.cc index cb6961c..0c6b4fa 100644 --- a/fuchsia/app/cast/cast_runner_unittest.cc +++ b/fuchsia/runners/cast/cast_runner_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "fuchsia/app/cast/cast_runner.h" +#include "fuchsia/runners/cast/cast_runner.h" #include <lib/fidl/cpp/binding.h> #include <lib/zx/channel.h> @@ -13,13 +13,11 @@ #include "base/fuchsia/service_directory.h" #include "base/message_loop/message_loop.h" #include "base/strings/stringprintf.h" -#include "fuchsia/app/cast/fake_application_config_manager.h" -#include "fuchsia/app/cast/test_common.h" +#include "fuchsia/runners/cast/fake_application_config_manager.h" +#include "fuchsia/runners/cast/test_common.h" #include "fuchsia/test/fake_context.h" #include "testing/gtest/include/gtest/gtest.h" -namespace castrunner { - class CastRunnerUnitTest : public testing::Test { public: CastRunnerUnitTest() @@ -125,5 +123,3 @@ component_controller_ptr.Unbind(); RunUntilCastRunnerIsIdle(); } - -} // namespace castrunner
diff --git a/fuchsia/app/cast/fake_application_config_manager.cc b/fuchsia/runners/cast/fake_application_config_manager.cc similarity index 90% rename from fuchsia/app/cast/fake_application_config_manager.cc rename to fuchsia/runners/cast/fake_application_config_manager.cc index b48763e..185b8ee 100644 --- a/fuchsia/app/cast/fake_application_config_manager.cc +++ b/fuchsia/runners/cast/fake_application_config_manager.cc
@@ -2,12 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "fuchsia/app/cast/fake_application_config_manager.h" +#include "fuchsia/runners/cast/fake_application_config_manager.h" #include "base/logging.h" -namespace castrunner { - const char FakeApplicationConfigManager::kTestCastAppId[] = "00000000"; FakeApplicationConfigManager::FakeApplicationConfigManager( @@ -30,5 +28,3 @@ app_config->web_url = embedded_test_server_->base_url().spec(); callback(std::move(app_config)); } - -} // namespace castrunner
diff --git a/fuchsia/app/cast/fake_application_config_manager.h b/fuchsia/runners/cast/fake_application_config_manager.h similarity index 76% rename from fuchsia/app/cast/fake_application_config_manager.h rename to fuchsia/runners/cast/fake_application_config_manager.h index 947243c..eee8008d 100644 --- a/fuchsia/app/cast/fake_application_config_manager.h +++ b/fuchsia/runners/cast/fake_application_config_manager.h
@@ -2,16 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FUCHSIA_APP_CAST_FAKE_APPLICATION_CONFIG_MANAGER_H_ -#define FUCHSIA_APP_CAST_FAKE_APPLICATION_CONFIG_MANAGER_H_ - -#include <fuchsia/fidl/chromium/cast/cpp/fidl.h> +#ifndef FUCHSIA_RUNNERS_CAST_FAKE_APPLICATION_CONFIG_MANAGER_H_ +#define FUCHSIA_RUNNERS_CAST_FAKE_APPLICATION_CONFIG_MANAGER_H_ #include "base/macros.h" +#include "fuchsia/fidl/chromium/cast/cpp/fidl.h" #include "net/test/embedded_test_server/embedded_test_server.h" -namespace castrunner { - // Test cast.ApplicationConfigManager implementation which maps a test Cast // AppId to an embedded test server address. class FakeApplicationConfigManager @@ -32,6 +29,4 @@ DISALLOW_COPY_AND_ASSIGN(FakeApplicationConfigManager); }; -} // namespace castrunner - -#endif // FUCHSIA_APP_CAST_FAKE_APPLICATION_CONFIG_MANAGER_H_ +#endif // FUCHSIA_RUNNERS_CAST_FAKE_APPLICATION_CONFIG_MANAGER_H_
diff --git a/fuchsia/app/cast/main.cc b/fuchsia/runners/cast/main.cc similarity index 84% rename from fuchsia/app/cast/main.cc rename to fuchsia/runners/cast/main.cc index 73ff569..e04adb878 100644 --- a/fuchsia/app/cast/main.cc +++ b/fuchsia/runners/cast/main.cc
@@ -6,15 +6,15 @@ #include "base/fuchsia/service_directory.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" -#include "fuchsia/app/cast/cast_runner.h" +#include "fuchsia/runners/cast/cast_runner.h" int main(int argc, char** argv) { base::MessageLoopForIO message_loop; base::RunLoop run_loop; - castrunner::CastRunner runner( + CastRunner runner( base::fuchsia::ServiceDirectory::GetDefault(), - webrunner::WebContentRunner::CreateDefaultWebContext(), + WebContentRunner::CreateDefaultWebContext(), base::fuchsia::ComponentContext::GetDefault() ->ConnectToService<chromium::cast::ApplicationConfigManager>(), run_loop.QuitClosure());
diff --git a/fuchsia/app/cast/sandbox_policy b/fuchsia/runners/cast/sandbox_policy similarity index 100% rename from fuchsia/app/cast/sandbox_policy rename to fuchsia/runners/cast/sandbox_policy
diff --git a/fuchsia/app/cast/test_common.cc b/fuchsia/runners/cast/test_common.cc similarity index 93% rename from fuchsia/app/cast/test_common.cc rename to fuchsia/runners/cast/test_common.cc index cf134bb..2f56a7e 100644 --- a/fuchsia/app/cast/test_common.cc +++ b/fuchsia/runners/cast/test_common.cc
@@ -2,12 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "fuchsia/app/cast/test_common.h" +#include "fuchsia/runners/cast/test_common.h" #include "base/fuchsia/fuchsia_logging.h" -namespace castrunner { - zx::channel StartCastComponent( const base::StringPiece& cast_url, fuchsia::sys::RunnerPtr* sys_runner, @@ -37,5 +35,3 @@ std::move(component_controller_request)); return service_directory_client; } - -} // namespace castrunner
diff --git a/fuchsia/app/cast/test_common.h b/fuchsia/runners/cast/test_common.h similarity index 77% rename from fuchsia/app/cast/test_common.h rename to fuchsia/runners/cast/test_common.h index f60295e..a811210 100644 --- a/fuchsia/app/cast/test_common.h +++ b/fuchsia/runners/cast/test_common.h
@@ -2,15 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FUCHSIA_APP_CAST_TEST_COMMON_H_ -#define FUCHSIA_APP_CAST_TEST_COMMON_H_ +#ifndef FUCHSIA_RUNNERS_CAST_TEST_COMMON_H_ +#define FUCHSIA_RUNNERS_CAST_TEST_COMMON_H_ #include <fuchsia/sys/cpp/fidl.h> #include "base/strings/string_piece.h" -namespace castrunner { - // Starts a cast component from the runner |sys_runner| with the URL |cast_url| // and returns the service directory client channel. zx::channel StartCastComponent( @@ -19,6 +17,4 @@ fidl::InterfaceRequest<fuchsia::sys::ComponentController> component_controller_request); -} // namespace castrunner - -#endif // FUCHSIA_APP_CAST_TEST_COMMON_H_ \ No newline at end of file +#endif // FUCHSIA_RUNNERS_CAST_TEST_COMMON_H_ \ No newline at end of file
diff --git a/fuchsia/app/cast/test/data/cast_channel.html b/fuchsia/runners/cast/testdata/cast_channel.html similarity index 100% rename from fuchsia/app/cast/test/data/cast_channel.html rename to fuchsia/runners/cast/testdata/cast_channel.html
diff --git a/fuchsia/app/cast/test/data/cast_channel_reconnect.html b/fuchsia/runners/cast/testdata/cast_channel_reconnect.html similarity index 100% rename from fuchsia/app/cast/test/data/cast_channel_reconnect.html rename to fuchsia/runners/cast/testdata/cast_channel_reconnect.html
diff --git a/fuchsia/app/common/web_component.cc b/fuchsia/runners/common/web_component.cc similarity index 95% rename from fuchsia/app/common/web_component.cc rename to fuchsia/runners/common/web_component.cc index 434e73e..e410f79 100644 --- a/fuchsia/app/common/web_component.cc +++ b/fuchsia/runners/common/web_component.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "fuchsia/app/common/web_component.h" +#include "fuchsia/runners/common/web_component.h" #include <fuchsia/sys/cpp/fidl.h> #include <lib/fidl/cpp/binding_set.h> @@ -12,10 +12,7 @@ #include "base/fuchsia/scoped_service_binding.h" #include "base/fuchsia/service_directory.h" #include "base/logging.h" -#include "fuchsia/app/common/web_content_runner.h" -#include "fuchsia/fidl/chromium/web/cpp/fidl.h" - -namespace webrunner { +#include "fuchsia/runners/common/web_content_runner.h" WebComponent::~WebComponent() { // Send process termination details to the client. @@ -122,5 +119,3 @@ termination_exit_code_ = termination_exit_code; runner_->DestroyComponent(this); } - -} // namespace webrunner
diff --git a/fuchsia/app/common/web_component.h b/fuchsia/runners/common/web_component.h similarity index 95% rename from fuchsia/app/common/web_component.h rename to fuchsia/runners/common/web_component.h index be0ae57..3bd4334 100644 --- a/fuchsia/app/common/web_component.h +++ b/fuchsia/runners/common/web_component.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FUCHSIA_APP_COMMON_WEB_COMPONENT_H_ -#define FUCHSIA_APP_COMMON_WEB_COMPONENT_H_ +#ifndef FUCHSIA_RUNNERS_COMMON_WEB_COMPONENT_H_ +#define FUCHSIA_RUNNERS_COMMON_WEB_COMPONENT_H_ #include <fuchsia/sys/cpp/fidl.h> #include <fuchsia/ui/app/cpp/fidl.h> @@ -20,8 +20,6 @@ #include "fuchsia/fidl/chromium/web/cpp/fidl.h" #include "url/gurl.h" -namespace webrunner { - class WebContentRunner; // Base component implementation for web-based content Runners. Each instance @@ -109,6 +107,4 @@ DISALLOW_COPY_AND_ASSIGN(WebComponent); }; -} // namespace webrunner - -#endif // FUCHSIA_APP_COMMON_COMPONENT_CONTROLLER_IMPL_H_ +#endif // FUCHSIA_RUNNERS_COMMON_WEB_COMPONENT_H_
diff --git a/fuchsia/app/common/web_content_runner.cc b/fuchsia/runners/common/web_content_runner.cc similarity index 94% rename from fuchsia/app/common/web_content_runner.cc rename to fuchsia/runners/common/web_content_runner.cc index 3d78e56..01e6717 100644 --- a/fuchsia/app/common/web_content_runner.cc +++ b/fuchsia/runners/common/web_content_runner.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "fuchsia/app/common/web_content_runner.h" +#include "fuchsia/runners/common/web_content_runner.h" #include <fuchsia/sys/cpp/fidl.h> #include <lib/fidl/cpp/binding_set.h> @@ -15,12 +15,9 @@ #include "base/fuchsia/scoped_service_binding.h" #include "base/fuchsia/service_directory.h" #include "base/logging.h" -#include "fuchsia/app/common/web_component.h" -#include "fuchsia/fidl/chromium/web/cpp/fidl.h" +#include "fuchsia/runners/common/web_component.h" #include "url/gurl.h" -namespace webrunner { - // static chromium::web::ContextPtr WebContentRunner::CreateDefaultWebContext() { auto web_context_provider = @@ -110,5 +107,3 @@ if (on_idle_closure_) std::move(on_idle_closure_).Run(); } - -} // namespace webrunner
diff --git a/fuchsia/app/common/web_content_runner.h b/fuchsia/runners/common/web_content_runner.h similarity index 93% rename from fuchsia/app/common/web_content_runner.h rename to fuchsia/runners/common/web_content_runner.h index 50db91f..c65f30e 100644 --- a/fuchsia/app/common/web_content_runner.h +++ b/fuchsia/runners/common/web_content_runner.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FUCHSIA_APP_COMMON_WEB_CONTENT_RUNNER_H_ -#define FUCHSIA_APP_COMMON_WEB_CONTENT_RUNNER_H_ +#ifndef FUCHSIA_RUNNERS_COMMON_WEB_CONTENT_RUNNER_H_ +#define FUCHSIA_RUNNERS_COMMON_WEB_CONTENT_RUNNER_H_ #include <fuchsia/sys/cpp/fidl.h> #include <memory> @@ -16,8 +16,6 @@ #include "base/macros.h" #include "fuchsia/fidl/chromium/web/cpp/fidl.h" -namespace webrunner { - class WebComponent; // sys::Runner that instantiates components hosting standard web content. @@ -80,6 +78,4 @@ DISALLOW_COPY_AND_ASSIGN(WebContentRunner); }; -} // namespace webrunner - -#endif // FUCHSIA_APP_COMMON_WEB_CONTENT_RUNNER_H_ +#endif // FUCHSIA_RUNNERS_COMMON_WEB_CONTENT_RUNNER_H_
diff --git a/fuchsia/app/web/main.cc b/fuchsia/runners/web/main.cc similarity index 66% rename from fuchsia/app/web/main.cc rename to fuchsia/runners/web/main.cc index b640ce0..b4f8896 100644 --- a/fuchsia/app/web/main.cc +++ b/fuchsia/runners/web/main.cc
@@ -5,16 +5,15 @@ #include "base/fuchsia/service_directory.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" -#include "fuchsia/app/common/web_content_runner.h" +#include "fuchsia/runners/common/web_content_runner.h" int main(int argc, char** argv) { base::MessageLoopForIO message_loop; base::RunLoop run_loop; - webrunner::WebContentRunner runner( - base::fuchsia::ServiceDirectory::GetDefault(), - webrunner::WebContentRunner::CreateDefaultWebContext(), - run_loop.QuitClosure()); + WebContentRunner runner(base::fuchsia::ServiceDirectory::GetDefault(), + WebContentRunner::CreateDefaultWebContext(), + run_loop.QuitClosure()); // Run until there are no Components, or the last service client channel is // closed.
diff --git a/fuchsia/app/web/sandbox_policy b/fuchsia/runners/web/sandbox_policy similarity index 100% rename from fuchsia/app/web/sandbox_policy rename to fuchsia/runners/web/sandbox_policy
diff --git a/fuchsia/app/web/webrunner_smoke_test.cc b/fuchsia/runners/web/web_runner_smoke_test.cc similarity index 97% rename from fuchsia/app/web/webrunner_smoke_test.cc rename to fuchsia/runners/web/web_runner_smoke_test.cc index 50b60e7d7..d4182e5 100644 --- a/fuchsia/app/web/webrunner_smoke_test.cc +++ b/fuchsia/runners/web/web_runner_smoke_test.cc
@@ -15,8 +15,6 @@ using net::test_server::HttpRequest; using net::test_server::HttpResponse; -namespace webrunner { - namespace { class WebRunnerSmokeTest : public testing::Test { @@ -78,5 +76,3 @@ } } // anonymous namespace - -} // namespace webrunner
diff --git a/google_apis/drive/base_requests.cc b/google_apis/drive/base_requests.cc index b345502..3188980 100644 --- a/google_apis/drive/base_requests.cc +++ b/google_apis/drive/base_requests.cc
@@ -399,7 +399,7 @@ } // static -bool UrlFetchRequestBase::WriteFileData(base::StringPiece string_piece, +bool UrlFetchRequestBase::WriteFileData(std::string file_data, DownloadData* download_data) { if (!download_data->output_file.IsValid()) { download_data->output_file.Initialize( @@ -408,8 +408,8 @@ if (!download_data->output_file.IsValid()) return false; } - if (download_data->output_file.WriteAtCurrentPos(string_piece.data(), - string_piece.size()) == -1) { + if (download_data->output_file.WriteAtCurrentPos(file_data.data(), + file_data.size()) == -1) { download_data->output_file.Close(); return false; } @@ -419,10 +419,9 @@ // errors. The size limit is to avoid consuming too much redundant memory. const size_t kMaxStringSize = 1024 * 1024; if (download_data->response_body.size() < kMaxStringSize) { - size_t bytes_to_copy = - std::min(string_piece.size(), - kMaxStringSize - download_data->response_body.size()); - download_data->response_body.append(string_piece.data(), bytes_to_copy); + size_t bytes_to_copy = std::min( + file_data.size(), kMaxStringSize - download_data->response_body.size()); + download_data->response_body.append(file_data.data(), bytes_to_copy); } return true; @@ -456,7 +455,7 @@ base::PostTaskAndReplyWithResult( blocking_task_runner(), FROM_HERE, base::BindOnce(&UrlFetchRequestBase::WriteFileData, - std::move(string_piece), download_data_ptr), + string_piece.as_string(), download_data_ptr), base::BindOnce(&UrlFetchRequestBase::OnWriteComplete, weak_ptr_factory_.GetWeakPtr(), std::move(download_data_), std::move(resume)));
diff --git a/google_apis/drive/base_requests.h b/google_apis/drive/base_requests.h index 995350a..874bd109 100644 --- a/google_apis/drive/base_requests.h +++ b/google_apis/drive/base_requests.h
@@ -223,10 +223,9 @@ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; }; - // Write the data in |string_piece| to disk and call |resume| once complete on + // Write the data in |file_data| to disk and call |resume| once complete on // a blocking sequence. - static bool WriteFileData(base::StringPiece string_piece, - DownloadData* download_data); + static bool WriteFileData(std::string file_data, DownloadData* download_data); // Called by SimpleURLLoader to report download progress. void OnDownloadProgress(const ProgressCallback& progress_callback,
diff --git a/gpu/command_buffer/common/mailbox.cc b/gpu/command_buffer/common/mailbox.cc index 7681b4e..2a7a038 100644 --- a/gpu/command_buffer/common/mailbox.cc +++ b/gpu/command_buffer/common/mailbox.cc
@@ -14,6 +14,37 @@ #include "base/strings/stringprintf.h" namespace gpu { +namespace { + +// The last byte of the mailbox's name stores the SharedImage flag. This avoids +// conflicts with Verify logic, which uses the first byte. +constexpr size_t kSharedImageFlagIndex = GL_MAILBOX_SIZE_CHROMIUM - 1; + +// Use the lowest bit for the SharedImage flag (any bit would work). +constexpr int8_t kSharedImageFlag = 0x1; + +void MarkMailboxAsSharedImage(bool is_shared_image, int8_t* name) { + if (is_shared_image) + name[kSharedImageFlagIndex] |= kSharedImageFlag; + else + name[kSharedImageFlagIndex] &= ~kSharedImageFlag; +} + +Mailbox GenerateMailbox(bool is_shared_image) { + Mailbox result; + // Generates cryptographically-secure bytes. + base::RandBytes(result.name, sizeof(result.name)); + MarkMailboxAsSharedImage(is_shared_image, result.name); +#if !defined(NDEBUG) + int8_t value = 1; + for (size_t i = 1; i < sizeof(result.name); ++i) + value ^= result.name[i]; + result.name[0] = value; +#endif + return result; +} + +} // namespace Mailbox::Mailbox() { memset(name, 0, sizeof(name)); @@ -36,17 +67,16 @@ memcpy(name, n, sizeof(name)); } +bool Mailbox::IsSharedImage() const { + return name[kSharedImageFlagIndex] & kSharedImageFlag; +} + Mailbox Mailbox::Generate() { - Mailbox result; - // Generates cryptographically-secure bytes. - base::RandBytes(result.name, sizeof(result.name)); -#if !defined(NDEBUG) - int8_t value = 1; - for (size_t i = 1; i < sizeof(result.name); ++i) - value ^= result.name[i]; - result.name[0] = value; -#endif - return result; + return GenerateMailbox(false /* is_shared_image */); +} + +Mailbox Mailbox::GenerateForSharedImage() { + return GenerateMailbox(true /* is_shared_image */); } bool Mailbox::Verify() const {
diff --git a/gpu/command_buffer/common/mailbox.h b/gpu/command_buffer/common/mailbox.h index 6db8cb2..5cd2083 100644 --- a/gpu/command_buffer/common/mailbox.h +++ b/gpu/command_buffer/common/mailbox.h
@@ -40,9 +40,16 @@ void SetZero(); void SetName(const int8_t* name); + // Indicates whether this mailbox is used with the SharedImage system. + bool IsSharedImage() const; + // Generate a unique unguessable mailbox name. static Mailbox Generate(); + // Generate a unique unguessable mailbox name for use with the SharedImage + // system. + static Mailbox GenerateForSharedImage(); + // Verify that the mailbox was created through Mailbox::Generate. This only // works in Debug (always returns true in Release). This is not a secure // check, only to catch bugs where clients forgot to call Mailbox::Generate.
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn index bd70014..c0fd9ed 100644 --- a/gpu/command_buffer/service/BUILD.gn +++ b/gpu/command_buffer/service/BUILD.gn
@@ -205,8 +205,6 @@ "raster_cmd_validation_implementation_autogen.h", "raster_decoder.cc", "raster_decoder.h", - "raster_decoder_context_state.cc", - "raster_decoder_context_state.h", "renderbuffer_manager.cc", "renderbuffer_manager.h", "sampler_manager.cc", @@ -225,6 +223,8 @@ "shader_translator.h", "shader_translator_cache.cc", "shader_translator_cache.h", + "shared_context_state.cc", + "shared_context_state.h", "shared_image_backing.cc", "shared_image_backing.h", "shared_image_backing_factory.h",
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc index 40dca5a..eac90b80 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_unittest_textures.cc
@@ -91,7 +91,7 @@ TEST_F(GLES2DecoderPassthroughTest, CreateAndTexStorage2DSharedImageCHROMIUM) { MemoryTypeTracker memory_tracker(nullptr); - Mailbox mailbox = Mailbox::Generate(); + Mailbox mailbox = Mailbox::GenerateForSharedImage(); std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image = GetSharedImageManager()->Register( std::make_unique<TestSharedImageBackingPassthrough>( @@ -154,7 +154,7 @@ CreateAndTexStorage2DSharedImageCHROMIUMPreexistingTexture) { MemoryTypeTracker memory_tracker(nullptr); // Create a texture with kNewClientId. - Mailbox mailbox = Mailbox::Generate(); + Mailbox mailbox = Mailbox::GenerateForSharedImage(); std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image = GetSharedImageManager()->Register( std::make_unique<TestSharedImageBackingPassthrough>( @@ -186,7 +186,7 @@ TEST_F(GLES2DecoderPassthroughTest, BeginEndSharedImageAccessCRHOMIUM) { MemoryTypeTracker memory_tracker(nullptr); - Mailbox mailbox = Mailbox::Generate(); + Mailbox mailbox = Mailbox::GenerateForSharedImage(); std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image = GetSharedImageManager()->Register( std::make_unique<TestSharedImageBackingPassthrough>( @@ -249,7 +249,7 @@ BeginSharedImageAccessDirectCHROMIUMCantBeginAccess) { // Create a shared image. MemoryTypeTracker memory_tracker(nullptr); - Mailbox mailbox = Mailbox::Generate(); + Mailbox mailbox = Mailbox::GenerateForSharedImage(); std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image = GetSharedImageManager()->Register( std::make_unique<TestSharedImageBackingPassthrough>(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc index 098085c..b94cd64 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -3260,7 +3260,7 @@ TEST_P(GLES2DecoderTest, CreateAndTexStorage2DSharedImageCHROMIUM) { MemoryTypeTracker memory_tracker(memory_tracker_.get()); - Mailbox mailbox = Mailbox::Generate(); + Mailbox mailbox = Mailbox::GenerateForSharedImage(); std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image = GetSharedImageManager()->Register( std::make_unique<TestSharedImageBacking>( @@ -3321,7 +3321,7 @@ CreateAndTexStorage2DSharedImageCHROMIUMPreexistingTexture) { // Try to create a mailbox with kNewClientId. MemoryTypeTracker memory_tracker(memory_tracker_.get()); - Mailbox mailbox = Mailbox::Generate(); + Mailbox mailbox = Mailbox::GenerateForSharedImage(); std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image = GetSharedImageManager()->Register( std::make_unique<TestSharedImageBacking>( @@ -3344,7 +3344,7 @@ TEST_P(GLES2DecoderTest, BeginEndSharedImageAccessCRHOMIUM) { MemoryTypeTracker memory_tracker(memory_tracker_.get()); - Mailbox mailbox = Mailbox::Generate(); + Mailbox mailbox = Mailbox::GenerateForSharedImage(); std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image = GetSharedImageManager()->Register( std::make_unique<TestSharedImageBacking>( @@ -3404,7 +3404,7 @@ TEST_P(GLES2DecoderTest, BeginSharedImageAccessDirectCHROMIUMCantBeginAccess) { // Create a shared image. MemoryTypeTracker memory_tracker(memory_tracker_.get()); - Mailbox mailbox = Mailbox::Generate(); + Mailbox mailbox = Mailbox::GenerateForSharedImage(); std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image = GetSharedImageManager()->Register( std::make_unique<TestSharedImageBacking>(
diff --git a/gpu/command_buffer/service/gr_cache_controller.cc b/gpu/command_buffer/service/gr_cache_controller.cc index 1196a992..2a0b7db 100644 --- a/gpu/command_buffer/service/gr_cache_controller.cc +++ b/gpu/command_buffer/service/gr_cache_controller.cc
@@ -6,7 +6,7 @@ #include <chrono> -#include "gpu/command_buffer/service/raster_decoder_context_state.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "ui/gl/gl_context.h" namespace gpu {
diff --git a/gpu/command_buffer/service/gr_cache_controller_unittest.cc b/gpu/command_buffer/service/gr_cache_controller_unittest.cc index f6b9626..0deb744a 100644 --- a/gpu/command_buffer/service/gr_cache_controller_unittest.cc +++ b/gpu/command_buffer/service/gr_cache_controller_unittest.cc
@@ -7,7 +7,7 @@ #include "base/bind_helpers.h" #include "base/test/test_mock_time_task_runner.h" #include "gpu/command_buffer/service/feature_info.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/config/gpu_driver_bug_workarounds.h" #include "gpu/config/gpu_feature_info.h" #include "gpu/config/gpu_preferences.h"
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc index 25105c22..c16915d 100644 --- a/gpu/command_buffer/service/raster_decoder.cc +++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -50,9 +50,9 @@ #include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/query_manager.h" #include "gpu/command_buffer/service/raster_cmd_validation.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" #include "gpu/command_buffer/service/service_font_manager.h" #include "gpu/command_buffer/service/service_transfer_cache.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image_factory.h" #include "gpu/command_buffer/service/shared_image_representation.h" #include "gpu/command_buffer/service/skia_utils.h"
diff --git a/gpu/command_buffer/service/raster_decoder_unittest.cc b/gpu/command_buffer/service/raster_decoder_unittest.cc index 0a1ad35e..f9ec337 100644 --- a/gpu/command_buffer/service/raster_decoder_unittest.cc +++ b/gpu/command_buffer/service/raster_decoder_unittest.cc
@@ -15,8 +15,8 @@ #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/program_manager.h" #include "gpu/command_buffer/service/query_manager.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" #include "gpu/command_buffer/service/raster_decoder_unittest_base.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image_manager.h" #include "gpu/command_buffer/service/test_helper.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/gpu/command_buffer/service/raster_decoder_unittest_base.cc b/gpu/command_buffer/service/raster_decoder_unittest_base.cc index 2de7f28a..7c953e1c 100644 --- a/gpu/command_buffer/service/raster_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/raster_decoder_unittest_base.cc
@@ -24,8 +24,8 @@ #include "gpu/command_buffer/service/logger.h" #include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/program_manager.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" #include "gpu/command_buffer/service/service_utils.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/test_helper.h" #include "gpu/command_buffer/service/vertex_attrib_manager.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/gpu/command_buffer/service/raster_decoder_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc similarity index 99% rename from gpu/command_buffer/service/raster_decoder_context_state.cc rename to gpu/command_buffer/service/shared_context_state.cc index 7018d980..7b4ccdb 100644 --- a/gpu/command_buffer/service/raster_decoder_context_state.cc +++ b/gpu/command_buffer/service/shared_context_state.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "gpu/command_buffer/service/raster_decoder_context_state.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/memory_dump_manager.h"
diff --git a/gpu/command_buffer/service/raster_decoder_context_state.h b/gpu/command_buffer/service/shared_context_state.h similarity index 96% rename from gpu/command_buffer/service/raster_decoder_context_state.h rename to gpu/command_buffer/service/shared_context_state.h index a9443d1..51a28b2e 100644 --- a/gpu/command_buffer/service/raster_decoder_context_state.h +++ b/gpu/command_buffer/service/shared_context_state.h
@@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef GPU_COMMAND_BUFFER_SERVICE_RASTER_DECODER_CONTEXT_STATE_H_ -#define GPU_COMMAND_BUFFER_SERVICE_RASTER_DECODER_CONTEXT_STATE_H_ +#ifndef GPU_COMMAND_BUFFER_SERVICE_SHARED_CONTEXT_STATE_H_ +#define GPU_COMMAND_BUFFER_SERVICE_SHARED_CONTEXT_STATE_H_ + +#include <memory> +#include <vector> #include "base/memory/memory_pressure_listener.h" #include "base/memory/ref_counted.h" @@ -158,4 +161,4 @@ } // namespace gpu -#endif // GPU_COMMAND_BUFFER_SERVICE_RASTER_DECODER_CONTEXT_STATE_H_ +#endif // GPU_COMMAND_BUFFER_SERVICE_SHARED_CONTEXT_STATE_H_
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc index ab41c03..8f3f505 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc +++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
@@ -18,7 +18,7 @@ #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/memory_tracking.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image_backing.h" #include "gpu/command_buffer/service/shared_image_representation.h" #include "gpu/command_buffer/service/skia_utils.h"
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc index cc05f7f2..839e44aa 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc +++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc
@@ -9,7 +9,7 @@ #include "gpu/command_buffer/common/mailbox.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/command_buffer/service/mailbox_manager_impl.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image_backing.h" #include "gpu/command_buffer/service/shared_image_factory.h" #include "gpu/command_buffer/service/shared_image_manager.h"
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc index d37dd7e..a1ee348 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc +++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
@@ -11,8 +11,8 @@ #include "gpu/command_buffer/common/mailbox.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/command_buffer/service/mailbox_manager_impl.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" #include "gpu/command_buffer/service/service_utils.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image_backing.h" #include "gpu/command_buffer/service/shared_image_factory.h" #include "gpu/command_buffer/service/shared_image_manager.h" @@ -110,7 +110,7 @@ }; TEST_P(SharedImageBackingFactoryGLTextureTest, Basic) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::RGBA_8888; gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -202,7 +202,7 @@ } TEST_P(SharedImageBackingFactoryGLTextureTest, Image) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::RGBA_8888; gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -318,7 +318,7 @@ if (format == viz::ResourceFormat::ETC1 && !supports_etc1()) continue; - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB(); uint32_t usage = SHARED_IMAGE_USAGE_GLES2; @@ -367,7 +367,7 @@ } TEST_P(SharedImageBackingFactoryGLTextureTest, InitialDataImage) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::RGBA_8888; gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -406,7 +406,7 @@ } TEST_P(SharedImageBackingFactoryGLTextureTest, InitialDataWrongSize) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::RGBA_8888; gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -422,7 +422,7 @@ } TEST_P(SharedImageBackingFactoryGLTextureTest, InvalidFormat) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::UYVY_422; gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -433,7 +433,7 @@ } TEST_P(SharedImageBackingFactoryGLTextureTest, InvalidSize) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::RGBA_8888; gfx::Size size(0, 0); auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -449,7 +449,7 @@ } TEST_P(SharedImageBackingFactoryGLTextureTest, EstimatedSize) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::RGBA_8888; gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -591,7 +591,7 @@ TEST_P(SharedImageBackingFactoryGLTextureWithGMBTest, GpuMemoryBufferImportEmpty) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); gfx::Size size(256, 256); gfx::BufferFormat format = gfx::BufferFormat::RGBA_8888; auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -606,7 +606,7 @@ TEST_P(SharedImageBackingFactoryGLTextureWithGMBTest, GpuMemoryBufferImportNative) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); gfx::Size size(256, 256); gfx::BufferFormat format = gfx::BufferFormat::RGBA_8888; auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -634,7 +634,7 @@ TEST_P(SharedImageBackingFactoryGLTextureWithGMBTest, GpuMemoryBufferImportSharedMemory) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); gfx::Size size(256, 256); gfx::BufferFormat format = gfx::BufferFormat::RGBA_8888; auto color_space = gfx::ColorSpace::CreateSRGB();
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc index e23e823..e848d6c 100644 --- a/gpu/command_buffer/service/shared_image_factory.cc +++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -15,8 +15,8 @@ #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/image_factory.h" #include "gpu/command_buffer/service/mailbox_manager.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" #include "gpu/command_buffer/service/service_utils.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image_backing.h" #include "gpu/command_buffer/service/shared_image_backing_factory_gl_texture.h" #include "gpu/command_buffer/service/shared_image_manager.h" @@ -179,18 +179,15 @@ return false; } - Mailbox mailbox = backing->mailbox(); - if (shared_image_manager_->IsSharedImage(mailbox)) { - LOG(ERROR) << "CreateSharedImage: mailbox is already associated with a " - "SharedImage"; - backing->Destroy(); - return false; - } - std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image = shared_image_manager_->Register(std::move(backing), memory_tracker_.get()); + if (!shared_image) { + LOG(ERROR) << "CreateSharedImage: could not register backing."; + return false; + } + // TODO(ericrk): Remove this once no legacy cases remain. if (legacy_mailbox && !shared_image->ProduceLegacyMailbox(mailbox_manager_)) { LOG(ERROR) << "CreateSharedImage: could not convert shared_image to legacy "
diff --git a/gpu/command_buffer/service/shared_image_factory.h b/gpu/command_buffer/service/shared_image_factory.h index 1d50926..8968052f 100644 --- a/gpu/command_buffer/service/shared_image_factory.h +++ b/gpu/command_buffer/service/shared_image_factory.h
@@ -102,10 +102,6 @@ MemoryTracker* tracker); ~SharedImageRepresentationFactory(); - bool IsSharedImage(const Mailbox& mailbox) const { - return manager_->IsSharedImage(mailbox); - } - // Helpers which call similar classes on SharedImageManager, providing a // MemoryTypeTracker. std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture(
diff --git a/gpu/command_buffer/service/shared_image_factory_unittest.cc b/gpu/command_buffer/service/shared_image_factory_unittest.cc index c6e82086..fbc5770 100644 --- a/gpu/command_buffer/service/shared_image_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image_factory_unittest.cc
@@ -58,7 +58,7 @@ }; TEST_F(SharedImageFactoryTest, Basic) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::RGBA_8888; gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -74,7 +74,7 @@ } TEST_F(SharedImageFactoryTest, DuplicateMailbox) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::RGBA_8888; gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -95,7 +95,7 @@ } TEST_F(SharedImageFactoryTest, DestroyInexistentMailbox) { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); EXPECT_FALSE(factory_->DestroySharedImage(mailbox)); }
diff --git a/gpu/command_buffer/service/shared_image_manager.cc b/gpu/command_buffer/service/shared_image_manager.cc index 162caf8..d9abf9b 100644 --- a/gpu/command_buffer/service/shared_image_manager.cc +++ b/gpu/command_buffer/service/shared_image_manager.cc
@@ -41,6 +41,13 @@ std::unique_ptr<SharedImageRepresentationFactoryRef> SharedImageManager::Register(std::unique_ptr<SharedImageBacking> backing, MemoryTypeTracker* tracker) { + DCHECK(backing->mailbox().IsSharedImage()); + if (images_.find(backing->mailbox()) != images_.end()) { + LOG(ERROR) << "ShraedImageManager::Register: Trying to register an " + "already registered mailbox."; + backing->Destroy(); + return nullptr; + } auto factory_ref = std::make_unique<SharedImageRepresentationFactoryRef>( this, backing.get(), tracker); images_.emplace(std::move(backing)); @@ -58,11 +65,6 @@ (*found)->OnContextLost(); } -bool SharedImageManager::IsSharedImage(const Mailbox& mailbox) { - auto found = images_.find(mailbox); - return found != images_.end(); -} - std::unique_ptr<SharedImageRepresentationGLTexture> SharedImageManager::ProduceGLTexture(const Mailbox& mailbox, MemoryTypeTracker* tracker) {
diff --git a/gpu/command_buffer/service/shared_image_manager.h b/gpu/command_buffer/service/shared_image_manager.h index 682eba3..51134762 100644 --- a/gpu/command_buffer/service/shared_image_manager.h +++ b/gpu/command_buffer/service/shared_image_manager.h
@@ -28,9 +28,6 @@ // Marks the backing associated with a mailbox as context lost. void OnContextLost(const Mailbox& mailbox); - // Indicates whether a mailbox is associated with a SharedImage. - bool IsSharedImage(const Mailbox& mailbox); - // Accessors which return a SharedImageRepresentation. Representations also // take a ref on the mailbox, releasing it when the representation is // destroyed.
diff --git a/gpu/command_buffer/service/shared_image_manager_unittest.cc b/gpu/command_buffer/service/shared_image_manager_unittest.cc index 277b048c..c0d3defd 100644 --- a/gpu/command_buffer/service/shared_image_manager_unittest.cc +++ b/gpu/command_buffer/service/shared_image_manager_unittest.cc
@@ -76,7 +76,7 @@ SharedImageManager manager; auto tracker = std::make_unique<MemoryTypeTracker>(nullptr); - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::RGBA_8888; gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -116,7 +116,7 @@ SharedImageManager manager; auto tracker = std::make_unique<MemoryTypeTracker>(nullptr); - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::RGBA_8888; gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB(); @@ -148,7 +148,7 @@ auto tracker = std::make_unique<MemoryTypeTracker>(nullptr); auto tracker2 = std::make_unique<MemoryTypeTracker>(nullptr); - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); auto format = viz::ResourceFormat::RGBA_8888; gfx::Size size(256, 256); auto color_space = gfx::ColorSpace::CreateSRGB();
diff --git a/gpu/command_buffer/service/wrapped_sk_image.cc b/gpu/command_buffer/service/wrapped_sk_image.cc index f60e5a4b..b551da6 100644 --- a/gpu/command_buffer/service/wrapped_sk_image.cc +++ b/gpu/command_buffer/service/wrapped_sk_image.cc
@@ -12,7 +12,7 @@ #include "components/viz/common/resources/resource_format_utils.h" #include "gpu/command_buffer/common/shared_image_trace_utils.h" #include "gpu/command_buffer/service/mailbox_manager.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image_backing.h" #include "gpu/command_buffer/service/shared_image_representation.h" #include "third_party/skia/include/core/SkPromiseImageTexture.h"
diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc index 82482ba..c4a6446 100644 --- a/gpu/command_buffer/tests/fuzzer_main.cc +++ b/gpu/command_buffer/tests/fuzzer_main.cc
@@ -32,8 +32,8 @@ #include "gpu/command_buffer/service/mailbox_manager_impl.h" #include "gpu/command_buffer/service/passthrough_discardable_manager.h" #include "gpu/command_buffer/service/raster_decoder.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" #include "gpu/command_buffer/service/service_discardable_manager.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image_manager.h" #include "gpu/command_buffer/service/transfer_buffer_manager.h" #include "ui/gfx/geometry/size.h"
diff --git a/gpu/ipc/client/shared_image_interface_proxy.cc b/gpu/ipc/client/shared_image_interface_proxy.cc index dc5247a..57be230 100644 --- a/gpu/ipc/client/shared_image_interface_proxy.cc +++ b/gpu/ipc/client/shared_image_interface_proxy.cc
@@ -61,7 +61,7 @@ const gfx::ColorSpace& color_space, uint32_t usage) { GpuChannelMsg_CreateSharedImage_Params params; - params.mailbox = Mailbox::Generate(); + params.mailbox = Mailbox::GenerateForSharedImage(); params.format = format; params.size = size; params.color_space = color_space; @@ -104,7 +104,7 @@ } GpuChannelMsg_CreateSharedImageWithData_Params params; - params.mailbox = Mailbox::Generate(); + params.mailbox = Mailbox::GenerateForSharedImage(); params.format = format; params.size = size; params.color_space = color_space; @@ -125,7 +125,7 @@ uint32_t usage) { DCHECK(gpu_memory_buffer_manager); GpuChannelMsg_CreateGMBSharedImage_Params params; - params.mailbox = Mailbox::Generate(); + params.mailbox = Mailbox::GenerateForSharedImage(); params.handle = gpu_memory_buffer->CloneHandle(); params.size = gpu_memory_buffer->GetSize(); params.format = gpu_memory_buffer->GetFormat();
diff --git a/gpu/ipc/command_buffer_task_executor.cc b/gpu/ipc/command_buffer_task_executor.cc index 104dbdb..fb1b239e 100644 --- a/gpu/ipc/command_buffer_task_executor.cc +++ b/gpu/ipc/command_buffer_task_executor.cc
@@ -20,13 +20,15 @@ MailboxManager* mailbox_manager, scoped_refptr<gl::GLShareGroup> share_group, gl::GLSurfaceFormat share_group_surface_format, - SharedImageManager* shared_image_manager) + SharedImageManager* shared_image_manager, + gles2::ProgramCache* program_cache) : gpu_preferences_(gpu_preferences), gpu_feature_info_(gpu_feature_info), sync_point_manager_(sync_point_manager), mailbox_manager_(mailbox_manager), share_group_(share_group), share_group_surface_format_(share_group_surface_format), + program_cache_(program_cache), shader_translator_cache_(gpu_preferences_), shared_image_manager_(shared_image_manager) { DCHECK(mailbox_manager_); @@ -57,13 +59,14 @@ bool disable_disk_cache = gpu_preferences_.disable_gpu_shader_disk_cache || gpu_feature_info_.IsWorkaroundEnabled(gpu::DISABLE_PROGRAM_DISK_CACHE); - program_cache_ = std::make_unique<gles2::MemoryProgramCache>( + owned_program_cache_ = std::make_unique<gles2::MemoryProgramCache>( gpu_preferences_.gpu_program_cache_size, disable_disk_cache, gpu_feature_info_.IsWorkaroundEnabled( gpu::DISABLE_PROGRAM_CACHING_FOR_TRANSFORM_FEEDBACK), &activity_flags_); + program_cache_ = owned_program_cache_.get(); } - return program_cache_.get(); + return program_cache_; } } // namespace gpu
diff --git a/gpu/ipc/command_buffer_task_executor.h b/gpu/ipc/command_buffer_task_executor.h index 7613e1c..455a412 100644 --- a/gpu/ipc/command_buffer_task_executor.h +++ b/gpu/ipc/command_buffer_task_executor.h
@@ -6,6 +6,7 @@ #define GPU_IPC_COMMAND_BUFFER_TASK_EXECUTOR_H_ #include <memory> +#include <vector> #include "base/callback.h" #include "base/macros.h" @@ -73,7 +74,8 @@ MailboxManager* mailbox_manager, scoped_refptr<gl::GLShareGroup> share_group, gl::GLSurfaceFormat share_group_surface_format, - SharedImageManager* shared_image_manager); + SharedImageManager* shared_image_manager, + gles2::ProgramCache* program_cache); // Always use virtualized GL contexts if this returns true. virtual bool ForceVirtualizedGLContexts() const = 0; @@ -133,7 +135,8 @@ std::unique_ptr<gles2::Outputter> outputter_; scoped_refptr<gl::GLShareGroup> share_group_; gl::GLSurfaceFormat share_group_surface_format_; - std::unique_ptr<gles2::ProgramCache> program_cache_; + std::unique_ptr<gles2::ProgramCache> owned_program_cache_; + gles2::ProgramCache* program_cache_; gles2::ImageManager image_manager_; ServiceDiscardableManager discardable_manager_; PassthroughDiscardableManager passthrough_discardable_manager_;
diff --git a/gpu/ipc/gpu_in_process_thread_service.cc b/gpu/ipc/gpu_in_process_thread_service.cc index ca9ad51b..9dca370 100644 --- a/gpu/ipc/gpu_in_process_thread_service.cc +++ b/gpu/ipc/gpu_in_process_thread_service.cc
@@ -4,6 +4,9 @@ #include "gpu/ipc/gpu_in_process_thread_service.h" +#include <utility> +#include <vector> + #include "base/threading/thread_task_runner_handle.h" #include "gpu/command_buffer/service/scheduler.h" @@ -56,14 +59,16 @@ gl::GLSurfaceFormat share_group_surface_format, const GpuFeatureInfo& gpu_feature_info, const GpuPreferences& gpu_preferences, - SharedImageManager* shared_image_manager) + SharedImageManager* shared_image_manager, + gles2::ProgramCache* program_cache) : CommandBufferTaskExecutor(gpu_preferences, gpu_feature_info, sync_point_manager, mailbox_manager, share_group, share_group_surface_format, - shared_image_manager), + shared_image_manager, + program_cache), task_runner_(task_runner), scheduler_(scheduler) {}
diff --git a/gpu/ipc/gpu_in_process_thread_service.h b/gpu/ipc/gpu_in_process_thread_service.h index b280a2af..35116b6 100644 --- a/gpu/ipc/gpu_in_process_thread_service.h +++ b/gpu/ipc/gpu_in_process_thread_service.h
@@ -5,6 +5,8 @@ #ifndef GPU_IPC_GPU_IN_PROCESS_THREAD_SERVICE_H_ #define GPU_IPC_GPU_IN_PROCESS_THREAD_SERVICE_H_ +#include <memory> + #include "base/compiler_specific.h" #include "base/single_thread_task_runner.h" #include "gpu/command_buffer/service/mailbox_manager.h" @@ -14,9 +16,12 @@ #include "ui/gl/gl_share_group.h" namespace gpu { - class Scheduler; +namespace gles2 { +class ProgramCache; +} // namespace gles2 + // Default Service class when no service is specified. GpuInProcessThreadService // is used by Mus and unit tests. class GL_IN_PROCESS_CONTEXT_EXPORT GpuInProcessThreadService @@ -31,7 +36,8 @@ gl::GLSurfaceFormat share_group_surface_format, const GpuFeatureInfo& gpu_feature_info, const GpuPreferences& gpu_preferences, - SharedImageManager* shared_image_manager); + SharedImageManager* shared_image_manager, + gles2::ProgramCache* program_cache); // CommandBufferTaskExecutor implementation. bool ForceVirtualizedGLContexts() const override;
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc index 3f93d10..753f26832 100644 --- a/gpu/ipc/in_process_command_buffer.cc +++ b/gpu/ipc/in_process_command_buffer.cc
@@ -49,9 +49,9 @@ #include "gpu/command_buffer/service/memory_tracking.h" #include "gpu/command_buffer/service/query_manager.h" #include "gpu/command_buffer/service/raster_decoder.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" #include "gpu/command_buffer/service/scheduler.h" #include "gpu/command_buffer/service/service_utils.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image_factory.h" #include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/command_buffer/service/transfer_buffer_manager.h" @@ -132,7 +132,7 @@ const gfx::Size& size, const gfx::ColorSpace& color_space, uint32_t usage) override { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); { base::AutoLock lock(lock_); // Note: we enqueue the task under the lock to guarantee monotonicity of @@ -152,7 +152,7 @@ const gfx::ColorSpace& color_space, uint32_t usage, base::span<const uint8_t> pixel_data) override { - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); std::vector<uint8_t> pixel_data_copy(pixel_data.begin(), pixel_data.end()); { base::AutoLock lock(lock_); @@ -179,7 +179,7 @@ DCHECK(gpu::IsImageSizeValidForGpuMemoryBufferFormat( gpu_memory_buffer->GetSize(), gpu_memory_buffer->GetFormat())); - auto mailbox = Mailbox::Generate(); + auto mailbox = Mailbox::GenerateForSharedImage(); gfx::GpuMemoryBufferHandle handle = gpu_memory_buffer->CloneHandle(); bool requires_sync_token = handle.type == gfx::IO_SURFACE_BUFFER; SyncToken sync_token;
diff --git a/gpu/ipc/in_process_gpu_thread_holder.cc b/gpu/ipc/in_process_gpu_thread_holder.cc index 1fa5b2f..24545c0 100644 --- a/gpu/ipc/in_process_gpu_thread_holder.cc +++ b/gpu/ipc/in_process_gpu_thread_holder.cc
@@ -73,7 +73,7 @@ task_executor_ = base::MakeRefCounted<GpuInProcessThreadService>( task_runner(), scheduler_.get(), sync_point_manager_.get(), mailbox_manager_.get(), nullptr, gl::GLSurfaceFormat(), gpu_feature_info_, - gpu_preferences_, shared_image_manager_.get()); + gpu_preferences_, shared_image_manager_.get(), nullptr); completion->Signal(); }
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc index 557737ff..b0bc3bc 100644 --- a/gpu/ipc/service/gpu_channel_manager.cc +++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -93,13 +93,14 @@ DCHECK(io_task_runner); DCHECK(scheduler); - const bool enable_raster_transport = - gpu_feature_info_.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] == - gpu::kGpuFeatureStatusEnabled; + const bool enable_gr_shader_cache = + (gpu_feature_info_.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] == + gpu::kGpuFeatureStatusEnabled) || + features::IsUsingSkiaRenderer(); const bool disable_disk_cache = gpu_preferences_.disable_gpu_shader_disk_cache || gpu_driver_bug_workarounds_.disable_program_disk_cache; - if (enable_raster_transport && !disable_disk_cache) + if (enable_gr_shader_cache && !disable_disk_cache) gr_shader_cache_.emplace(gpu_preferences.gpu_program_cache_size, this); }
diff --git a/gpu/ipc/service/gpu_channel_manager.h b/gpu/ipc/service/gpu_channel_manager.h index bd829ce..665ee36a 100644 --- a/gpu/ipc/service/gpu_channel_manager.h +++ b/gpu/ipc/service/gpu_channel_manager.h
@@ -24,9 +24,9 @@ #include "gpu/command_buffer/service/gr_cache_controller.h" #include "gpu/command_buffer/service/gr_shader_cache.h" #include "gpu/command_buffer/service/passthrough_discardable_manager.h" -#include "gpu/command_buffer/service/raster_decoder_context_state.h" #include "gpu/command_buffer/service/service_discardable_manager.h" #include "gpu/command_buffer/service/shader_translator_cache.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image_manager.h" #include "gpu/config/gpu_driver_bug_workarounds.h" #include "gpu/config/gpu_feature_info.h"
diff --git a/gpu/ipc/service/shared_image_stub.cc b/gpu/ipc/service/shared_image_stub.cc index d842fe7..6ee676a 100644 --- a/gpu/ipc/service/shared_image_stub.cc +++ b/gpu/ipc/service/shared_image_stub.cc
@@ -64,6 +64,13 @@ const GpuChannelMsg_CreateSharedImage_Params& params) { TRACE_EVENT2("gpu", "SharedImageStub::OnCreateSharedImage", "width", params.size.width(), "height", params.size.height()); + if (!params.mailbox.IsSharedImage()) { + LOG(ERROR) << "SharedImageStub: Trying to create a SharedImage with a " + "non-SharedImage mailbox."; + OnError(); + return; + } + if (!MakeContextCurrentAndCreateFactory()) { OnError(); return; @@ -88,6 +95,13 @@ const GpuChannelMsg_CreateSharedImageWithData_Params& params) { TRACE_EVENT2("gpu", "SharedImageStub::OnCreateSharedImageWithData", "width", params.size.width(), "height", params.size.height()); + if (!params.mailbox.IsSharedImage()) { + LOG(ERROR) << "SharedImageStub: Trying to create a SharedImage with a " + "non-SharedImage mailbox."; + OnError(); + return; + } + if (!MakeContextCurrentAndCreateFactory()) { OnError(); return; @@ -139,6 +153,13 @@ GpuChannelMsg_CreateGMBSharedImage_Params params) { TRACE_EVENT2("gpu", "SharedImageStub::OnCreateSharedImage", "width", params.size.width(), "height", params.size.height()); + if (!params.mailbox.IsSharedImage()) { + LOG(ERROR) << "SharedImageStub: Trying to create a SharedImage with a " + "non-SharedImage mailbox."; + OnError(); + return; + } + if (!MakeContextCurrentAndCreateFactory()) { OnError(); return; @@ -166,6 +187,13 @@ void SharedImageStub::OnUpdateSharedImage(const Mailbox& mailbox, uint32_t release_id) { TRACE_EVENT0("gpu", "SharedImageStub::OnDestroySharedImage"); + if (!mailbox.IsSharedImage()) { + LOG(ERROR) << "SharedImageStub: Trying to access a SharedImage with a " + "non-SharedImage mailbox."; + OnError(); + return; + } + if (!MakeContextCurrentAndCreateFactory()) { OnError(); return; @@ -187,6 +215,13 @@ void SharedImageStub::OnDestroySharedImage(const Mailbox& mailbox) { TRACE_EVENT0("gpu", "SharedImageStub::OnDestroySharedImage"); + if (!mailbox.IsSharedImage()) { + LOG(ERROR) << "SharedImageStub: Trying to destroy a SharedImage with a " + "non-SharedImage mailbox."; + OnError(); + return; + } + if (!MakeContextCurrentAndCreateFactory()) { OnError(); return;
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc index c0d4db7..ab337433 100644 --- a/headless/lib/browser/headless_web_contents_impl.cc +++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -163,6 +163,7 @@ load_url_params.is_renderer_initiated = params.is_renderer_initiated; load_url_params.should_replace_current_entry = params.should_replace_current_entry; + load_url_params.reload_type = params.reload_type; if (params.uses_post) { load_url_params.load_type =
diff --git a/infra/config/branch/cq.cfg b/infra/config/branch/cq.cfg index 3399856..ae3217da 100644 --- a/infra/config/branch/cq.cfg +++ b/infra/config/branch/cq.cfg
@@ -81,16 +81,16 @@ builders { name: "linux-jumbo-rel" } builders { name: "linux-libfuzzer-asan-rel" } builders { name: "linux-ozone-rel" } + builders { name: "linux-rel" } builders { name: "linux_chromium_asan_rel_ng" } builders { name: "linux_chromium_compile_dbg_ng" } builders { name: "linux_chromium_headless_rel" } - builders { name: "linux_chromium_rel_ng" } builders { name: "linux_chromium_tsan_rel_ng" } + builders { name: "mac-rel" } builders { name: "mac_chromium_compile_dbg_ng" } - builders { name: "mac_chromium_rel_ng" } builders { name: "win-libfuzzer-asan-rel" } builders { name: "win10_chromium_x64_rel_ng" } - builders { name: "win7_chromium_rel_ng"} + builders { name: "win7-rel"} builders { name: "win_chromium_compile_dbg_ng" } ######################
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg index 1b2b3be..1202bc2 100644 --- a/infra/config/global/cr-buildbucket.cfg +++ b/infra/config/global/cr-buildbucket.cfg
@@ -1000,6 +1000,11 @@ # ChromeOS bots. builders { + name: "chromeos-amd64-generic-cfi-thin-lto-rel" + mixins: "chromeos-ci" + } + + builders { name: "chromeos-amd64-generic-rel" mixins: "chromeos-ci" } @@ -3024,6 +3029,11 @@ # TODO(hinoka): Make this 16 core after crbug.com/875708 dimensions: "cores:" } + builders { + mixins: "android-try" + name: "android-oreo-arm64-cts-networkservice-dbg" + dimensions: "os:Ubuntu-14.04" + } # TODO(jbudorick): Remove this after fully migrating ANSR. builders { mixins: "android-try" @@ -3148,6 +3158,7 @@ name: "try-nougat-phone-tester" } + builders { mixins: "chromeos-try" name: "chromeos-amd64-generic-cfi-thin-lto-rel" } builders { mixins: "chromeos-try" name: "chromeos-amd64-generic-rel" } builders { mixins: "chromeos-try" name: "chromeos-daisy-rel" } builders { mixins: "chromeos-try" name: "chromeos-kevin-rel" }
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg index 1ac8016a..5d7e0d3 100644 --- a/infra/config/global/luci-milo.cfg +++ b/infra/config/global/luci-milo.cfg
@@ -602,6 +602,11 @@ short_name: "dbg" } builders { + name: "buildbucket/luci.chromium.ci/chromeos-amd64-generic-cfi-thin-lto-rel" + category: "chromium.chromiumos|simple|release" + short_name: "x64" + } + builders { name: "buildbucket/luci.chromium.ci/chromeos-amd64-generic-rel" category: "chromium.chromiumos|simple|release" short_name: "x64" @@ -1018,6 +1023,11 @@ short_name: "dbg" } builders { + name: "buildbucket/luci.chromium.ci/chromeos-amd64-generic-cfi-thin-lto-rel" + category: "simple|release" + short_name: "x64" + } + builders { name: "buildbucket/luci.chromium.ci/chromeos-amd64-generic-rel" category: "simple|release" short_name: "x64" @@ -1891,31 +1901,26 @@ manifest_name: "REVISION" builders { - name: "buildbot/chromium.clang/ToTLinux" name: "buildbucket/luci.chromium.ci/ToTLinux" category: "ToT Linux" short_name: "rel" } builders { - name: "buildbot/chromium.clang/ToTLinux (dbg)" name: "buildbucket/luci.chromium.ci/ToTLinux (dbg)" category: "ToT Linux" short_name: "dbg" } builders { - name: "buildbot/chromium.clang/ToTLinuxASan" name: "buildbucket/luci.chromium.ci/ToTLinuxASan" category: "ToT Linux" short_name: "asn" } builders { - name: "buildbot/chromium.clang/ToTLinuxASanLibfuzzer" name: "buildbucket/luci.chromium.ci/ToTLinuxASanLibfuzzer" category: "ToT Linux" short_name: "fuz" } builders { - name: "buildbot/chromium.clang/ToTLinuxMSan" name: "buildbucket/luci.chromium.ci/ToTLinuxMSan" category: "ToT Linux" short_name: "msn" @@ -1926,37 +1931,31 @@ short_name: "tsn" } builders { - name: "buildbot/chromium.clang/ToTLinuxThinLTO" name: "buildbucket/luci.chromium.ci/ToTLinuxThinLTO" category: "ToT Linux" short_name: "lto" } builders { - name: "buildbot/chromium.clang/ToTLinuxUBSanVptr" name: "buildbucket/luci.chromium.ci/ToTLinuxUBSanVptr" category: "ToT Linux" short_name: "usn" } builders { - name: "buildbot/chromium.clang/ToTAndroid" name: "buildbucket/luci.chromium.ci/ToTAndroid" category: "ToT Android" short_name: "rel" } builders { - name: "buildbot/chromium.clang/ToTAndroid (dbg)" name: "buildbucket/luci.chromium.ci/ToTAndroid (dbg)" category: "ToT Android" short_name: "dbg" } builders { - name: "buildbot/chromium.clang/ToTAndroid x64" name: "buildbucket/luci.chromium.ci/ToTAndroid x64" category: "ToT Android" short_name: "x64" } builders { - name: "buildbot/chromium.clang/ToTAndroid64" name: "buildbucket/luci.chromium.ci/ToTAndroid64" category: "ToT Android" short_name: "a64" @@ -2003,13 +2002,11 @@ short_name: "rel" } builders { - name: "buildbot/chromium.clang/ToTWin(dbg)" name: "buildbucket/luci.chromium.ci/ToTWin(dbg)" category: "ToT Windows" short_name: "dbg" } builders { - name: "buildbot/chromium.clang/ToTWin(dll)" name: "buildbucket/luci.chromium.ci/ToTWin(dll)" category: "ToT Windows" short_name: "dll" @@ -2021,13 +2018,11 @@ short_name: "rel" } builders { - name: "buildbot/chromium.clang/ToTWin64(dbg)" name: "buildbucket/luci.chromium.ci/ToTWin64(dbg)" category: "ToT Windows|x64" short_name: "dbg" } builders { - name: "buildbot/chromium.clang/ToTWin64(dll)" name: "buildbucket/luci.chromium.ci/ToTWin64(dll)" category: "ToT Windows|x64" short_name: "dll" @@ -2044,13 +2039,11 @@ short_name: "lto" } builders { - name: "buildbot/chromium.clang/ToTWinLibcxx64" name: "buildbucket/luci.chromium.ci/ToTWinLibcxx64" category: "ToT Windows|x64" short_name: "cxx" } builders { - name: "buildbot/chromium.clang/CrWinAsan" name: "buildbucket/luci.chromium.ci/CrWinAsan" category: "ToT Windows|Asan" short_name: "asn" @@ -2062,7 +2055,6 @@ short_name: "dll" } builders { - name: "buildbot/chromium.clang/CrWinAsanCov" name: "buildbucket/luci.chromium.ci/CrWinAsanCov" category: "ToT Windows|Asan" short_name: "cov" @@ -2074,7 +2066,6 @@ short_name: "lxw" } builders { - name: "buildbot/chromium.clang/ToTLinuxCoverage" name: "buildbucket/luci.chromium.ci/ToTLinuxCoverage" category: "ToT Code Coverage" short_name: "linux" @@ -2086,43 +2077,36 @@ short_name: "mac" } builders { - name: "buildbot/chromium.clang/CFI Linux CF" name: "buildbucket/luci.chromium.ci/CFI Linux CF" category: "CFI|Linux" short_name: "CF" } builders { - name: "buildbot/chromium.clang/CFI Linux ToT" name: "buildbucket/luci.chromium.ci/CFI Linux ToT" category: "CFI|Linux" short_name: "ToT" } builders { - name: "buildbot/chromium.clang/ToTWinCFI" name: "buildbucket/luci.chromium.ci/ToTWinCFI" category: "CFI|Win" short_name: "x86" } builders { - name: "buildbot/chromium.clang/ToTWinCFI64" name: "buildbucket/luci.chromium.ci/ToTWinCFI64" category: "CFI|Win" short_name: "x64" } builders { - name: "buildbot/chromium.clang/ToTiOS" name: "buildbucket/luci.chromium.ci/ToTiOS" category: "iOS" short_name: "sim" } builders { - name: "buildbot/chromium.clang/ToTiOSDevice" name: "buildbucket/luci.chromium.ci/ToTiOSDevice" category: "iOS" short_name: "dev" } builders { - name: "buildbot/chromium.clang/UBSanVptr Linux" name: "buildbucket/luci.chromium.ci/UBSanVptr Linux" short_name: "usn" } @@ -4372,6 +4356,9 @@ name: "buildbucket/luci.chromium.try/android-marshmallow-arm64-rel" } builders { + name: "buildbucket/luci.chromium.try/android-oreo-arm64-cts-networkservice-dbg" + } + builders { name: "buildbucket/luci.chromium.try/android_arm64_dbg_recipe" } builders { @@ -4408,6 +4395,9 @@ name: "buildbucket/luci.chromium.try/cast_shell_linux" } builders { + name: "buildbucket/luci.chromium.try/chromeos-amd64-generic-cfi-thin-lto-rel" + } + builders { name: "buildbucket/luci.chromium.try/chromeos-amd64-generic-rel" } builders {
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg index 4649d23..97471714 100644 --- a/infra/config/global/luci-scheduler.cfg +++ b/infra/config/global/luci-scheduler.cfg
@@ -301,6 +301,7 @@ triggers: "android-marshmallow-arm64-rel" triggers: "android-mojo-webview-rel" triggers: "android-rel" + triggers: "chromeos-amd64-generic-cfi-thin-lto-rel" triggers: "chromeos-amd64-generic-rel" triggers: "chromeos-amd64-generic-rel-goma-canary" triggers: "chromeos-amd64-generic-rel-goma-latest-client" @@ -1086,6 +1087,16 @@ ################################################################################ job { + id: "chromeos-amd64-generic-cfi-thin-lto-rel" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "chromeos-amd64-generic-cfi-thin-lto-rel" + } +} + +job { id: "chromeos-amd64-generic-rel" acl_sets: "default" buildbucket: {
diff --git a/infra/config/global/tricium-prod.cfg b/infra/config/global/tricium-prod.cfg index 6301358..bef9ff6 100644 --- a/infra/config/global/tricium-prod.cfg +++ b/infra/config/global/tricium-prod.cfg
@@ -11,7 +11,11 @@ platform: UBUNTU configs { name: "filter" - value: "-,+readability/todo,+readability/check,+readability/casting,+readability/fn_size,+build/include_what_you_use,+build/include_order" + value: "-,+readability/todo,+readability/check,+readability/fn_size,+build/include_what_you_use,+build/include_order" + } + configs { + name: "verbose" + value: "4" } }
diff --git a/ios/chrome/app/DEPS b/ios/chrome/app/DEPS index 2ede3f3c..a16b778f 100644 --- a/ios/chrome/app/DEPS +++ b/ios/chrome/app/DEPS
@@ -1,7 +1,6 @@ include_rules = [ "+components/bookmarks/browser", "+components/bookmarks/test", - "+components/browser_sync", "+components/browsing_data/core", "+components/component_updater", "+components/content_settings", @@ -18,6 +17,7 @@ "+components/prefs", "+components/reading_list/core", "+components/suggestions", + "+components/sync/driver", "+components/task_scheduler_util", "+components/url_formatter", "+components/web_resource",
diff --git a/ios/chrome/app/resources/inspect/inspect.js b/ios/chrome/app/resources/inspect/inspect.js index c17ba56f..788dbe6 100644 --- a/ios/chrome/app/resources/inspect/inspect.js +++ b/ios/chrome/app/resources/inspect/inspect.js
@@ -99,6 +99,18 @@ } /** + * Removes the messages and UI associated with |mainFrameId| and all children. + * @param {!string} mainFrameId The frame ID for the main frame of the webpage + * which sent the message. + */ +function tabClosed(mainFrameId) { + let tab = $(getFrameIdString_(mainFrameId)); + if (tab) { + $('tabs').removeChild(tab); + } +} + +/** * Notify the application to start collecting console logs. */ function startLogging() { @@ -121,8 +133,9 @@ $('start-logging').onclick = startLogging; $('stop-logging').onclick = stopLogging; - // Expose |logMessageReceived| function through global namespace as it will be - // called from native app. + // Expose |logMessageReceived| and |tabClosed| functions through global + // namespace as they will be called from the native app. __gCrWeb.inspectWebUI = {}; __gCrWeb.inspectWebUI.logMessageReceived = logMessageReceived; + __gCrWeb.inspectWebUI.tabClosed = tabClosed; });
diff --git a/ios/chrome/app/spotlight/topsites_spotlight_manager.mm b/ios/chrome/app/spotlight/topsites_spotlight_manager.mm index 067249a..ff07b381 100644 --- a/ios/chrome/app/spotlight/topsites_spotlight_manager.mm +++ b/ios/chrome/app/spotlight/topsites_spotlight_manager.mm
@@ -9,11 +9,11 @@ #include "base/memory/ref_counted.h" #include "base/strings/sys_string_conversions.h" #include "components/bookmarks/browser/bookmark_model.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/history/core/browser/history_types.h" #include "components/history/core/browser/top_sites.h" #include "components/history/core/browser/top_sites_observer.h" #include "components/suggestions/suggestions_service.h" +#include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h" #include "ios/chrome/browser/history/top_sites_factory.h" @@ -46,7 +46,7 @@ bookmarks::BookmarkModel* _bookmarkModel; // weak suggestions::SuggestionsService* _suggestionService; // weak - browser_sync::ProfileSyncService* _syncService; // weak + syncer::SyncService* _syncService; // weak scoped_refptr<history::TopSites> _topSites; std::unique_ptr< @@ -60,11 +60,12 @@ @property(nonatomic, readonly) scoped_refptr<history::TopSites> topSites; - (instancetype) -initWithLargeIconService:(favicon::LargeIconService*)largeIconService - topSites:(scoped_refptr<history::TopSites>)topSites - bookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel - profileSyncService:(browser_sync::ProfileSyncService*)syncService - suggestionsService:(suggestions::SuggestionsService*)suggestionsService; + initWithLargeIconService:(favicon::LargeIconService*)largeIconService + topSites:(scoped_refptr<history::TopSites>)topSites + bookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel + syncService:(syncer::SyncService*)syncService + suggestionsService: + (suggestions::SuggestionsService*)suggestionsService; // Updates all indexed top sites from appropriate source, within limit of number // of sites shown on NTP. @@ -157,18 +158,19 @@ browserState) bookmarkModel:ios::BookmarkModelFactory::GetForBrowserState( browserState) - profileSyncService:ProfileSyncServiceFactory::GetForBrowserState( + syncService:ProfileSyncServiceFactory::GetForBrowserState( browserState) suggestionsService:suggestions::SuggestionsServiceFactory:: GetForBrowserState(browserState)]; } - (instancetype) -initWithLargeIconService:(favicon::LargeIconService*)largeIconService - topSites:(scoped_refptr<history::TopSites>)topSites - bookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel - profileSyncService:(browser_sync::ProfileSyncService*)syncService - suggestionsService:(suggestions::SuggestionsService*)suggestionsService { + initWithLargeIconService:(favicon::LargeIconService*)largeIconService + topSites:(scoped_refptr<history::TopSites>)topSites + bookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel + syncService:(syncer::SyncService*)syncService + suggestionsService: + (suggestions::SuggestionsService*)suggestionsService { self = [super initWithLargeIconService:largeIconService domain:spotlight::DOMAIN_TOPSITES]; if (self) {
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 4140216..62ea035 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -801,6 +801,9 @@ <message name="IDS_IOS_LONG_PRESS_TOOLBAR_IPH_PROMOTION_TEXT" desc="Text for the LongPress Toolbar Tip in-product help promotion, explaining that the user can long press on the toolbar's button to display more options. [iOS only]"> Press and hold for more tab options </message> + <message name="IDS_IOS_MANAGE_SYNC_SETTINGS_TITLE" desc="Title for the view in the Settings for enabling/disabling Sync. [iOS only]"> + Manage Sync + </message> <message name="IDS_IOS_MANAGED_DISCONNECT_DIALOG_ACCEPT" desc="Label on the button to proceed with signout and clear all Chrome data.[Length: 30em]."> Accept and sign out </message>
diff --git a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.mm b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.mm index 102e34ac..84e5f8b4 100644 --- a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.mm +++ b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.mm
@@ -6,7 +6,6 @@ #include "base/logging.h" #include "base/strings/utf_string_conversions.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/history/core/browser/history_service.h" #include "components/keyed_service/core/service_access_type.h" #include "components/omnibox/browser/autocomplete_classifier.h"
diff --git a/ios/chrome/browser/autofill/autofill_controller_unittest.mm b/ios/chrome/browser/autofill/autofill_controller_unittest.mm index 366d68ed..a8c548f 100644 --- a/ios/chrome/browser/autofill/autofill_controller_unittest.mm +++ b/ios/chrome/browser/autofill/autofill_controller_unittest.mm
@@ -36,7 +36,7 @@ #include "ios/chrome/browser/ssl/ios_security_state_tab_helper.h" #import "ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h" #import "ios/chrome/browser/ui/autofill/form_input_accessory_mediator.h" -#include "ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.h" +#include "ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.h" #include "ios/chrome/browser/web/chrome_web_client.h" #import "ios/chrome/browser/web/chrome_web_test.h" #include "ios/chrome/browser/web_data_service_factory.h" @@ -460,6 +460,8 @@ PersonalDataManager* personal_data_manager = PersonalDataManagerFactory::GetForBrowserState( ios::ChromeBrowserState::FromBrowserState(GetBrowserState())); + PersonalDataManagerFinishedProfileTasksWaiter waiter(personal_data_manager); + AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/"); profile.SetRawInfo(NAME_FULL, base::UTF8ToUTF16("Homer Simpson")); profile.SetRawInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("123 Main Street")); @@ -467,7 +469,10 @@ profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("IL")); profile.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("55123")); EXPECT_EQ(0U, personal_data_manager->GetProfiles().size()); + personal_data_manager->SaveImportedProfile(profile); + waiter.Wait(); + EXPECT_EQ(1U, personal_data_manager->GetProfiles().size()); AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com/"); profile2.SetRawInfo(NAME_FULL, base::UTF8ToUTF16("Larry Page")); @@ -646,9 +651,9 @@ // This call cause a modification of the PersonalDataManager, so wait until // the asynchronous task complete in addition to waiting for the UI update. - PersonalDataManagerDataChangedObserver observer(personal_data_manager); + PersonalDataManagerFinishedProfileTasksWaiter waiter(personal_data_manager); confirm_infobar->Accept(); - observer.Wait(); + waiter.Wait(); const std::vector<CreditCard*>& credit_cards = personal_data_manager->GetCreditCards();
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state.mm b/ios/chrome/browser/browser_state/chrome_browser_state.mm index d2a958c..9fc6b65 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state.mm +++ b/ios/chrome/browser/browser_state/chrome_browser_state.mm
@@ -12,7 +12,7 @@ #include "base/sequenced_task_runner.h" #include "components/sync_preferences/pref_service_syncable.h" #include "ios/chrome/browser/chrome_url_constants.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ios/web/public/web_thread.h" #include "ios/web/public/webui/web_ui_ios.h" #include "ios/web/webui/url_data_manager_ios_backend.h"
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc index a217bdd6..e8918ff 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc +++ b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
@@ -15,7 +15,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/task/post_task.h" #include "base/threading/scoped_blocking_call.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/invalidation/impl/profile_invalidation_provider.h" #include "components/password_manager/core/browser/password_store.h" #include "components/prefs/pref_service.h" @@ -36,7 +35,6 @@ #include "ios/chrome/browser/signin/account_reconcilor_factory.h" #include "ios/chrome/browser/signin/gaia_cookie_manager_service_factory.h" #include "ios/chrome/browser/signin/identity_manager_factory.h" -#include "ios/chrome/browser/sync/profile_sync_service_factory.h" #include "ios/chrome/browser/unified_consent/unified_consent_service_factory.h" #include "services/identity/public/cpp/identity_manager.h" @@ -222,7 +220,7 @@ ->SetupInvalidationsOnProfileLoad(invalidation_service); ios::AccountReconcilorFactory::GetForBrowserState(browser_state); // Initialization needs to happen after the browser context is available - // because ProfileSyncService needs the URL context getter. + // because UnifiedConsentService's dependencies needs the URL context getter. UnifiedConsentServiceFactory::GetForBrowserState(browser_state); }
diff --git a/ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.cc b/ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.cc index 01174da..0f4e4bff 100644 --- a/ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.cc +++ b/ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.cc
@@ -7,7 +7,6 @@ #include "base/bind.h" #include "base/callback.h" #include "base/memory/ptr_util.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/browsing_data/core/counters/autofill_counter.h" #include "components/browsing_data/core/counters/browsing_data_counter.h" #include "components/browsing_data/core/counters/history_counter.h" @@ -15,6 +14,7 @@ #include "components/browsing_data/core/pref_names.h" #include "components/keyed_service/core/service_access_type.h" #include "components/prefs/pref_service.h" +#include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/browsing_data/cache_counter.h" #include "ios/chrome/browser/experimental_flags.h"
diff --git a/ios/chrome/browser/crash_report/crash_report_helper.mm b/ios/chrome/browser/crash_report/crash_report_helper.mm index 8093d02a..2bdafb39a 100644 --- a/ios/chrome/browser/crash_report/crash_report_helper.mm +++ b/ios/chrome/browser/crash_report/crash_report_helper.mm
@@ -26,7 +26,7 @@ #import "ios/chrome/browser/web_state_list/web_state_list.h" #include "ios/web/public/browser_state.h" #import "ios/web/public/navigation_item.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ios/web/public/web_thread.h" #import "net/base/mac/url_conversions.h"
diff --git a/ios/chrome/browser/find_in_page/find_in_page_controller.mm b/ios/chrome/browser/find_in_page/find_in_page_controller.mm index ce8454c..c91075d66 100644 --- a/ios/chrome/browser/find_in_page/find_in_page_controller.mm +++ b/ios/chrome/browser/find_in_page/find_in_page_controller.mm
@@ -9,7 +9,7 @@ #import <cmath> #include <memory> -#import "base/logging.h" +#include "base/logging.h" #import "base/mac/foundation_util.h" #import "ios/chrome/browser/find_in_page/find_in_page_model.h" #import "ios/chrome/browser/find_in_page/js_findinpage_manager.h"
diff --git a/ios/chrome/browser/history/web_history_service_factory.cc b/ios/chrome/browser/history/web_history_service_factory.cc index d0fd8a8..01954cac 100644 --- a/ios/chrome/browser/history/web_history_service_factory.cc +++ b/ios/chrome/browser/history/web_history_service_factory.cc
@@ -5,7 +5,6 @@ #include "ios/chrome/browser/history/web_history_service_factory.h" #include "base/no_destructor.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/history/core/browser/web_history_service.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" #include "components/prefs/pref_service.h"
diff --git a/ios/chrome/browser/infobars/infobar_manager_impl.mm b/ios/chrome/browser/infobars/infobar_manager_impl.mm index 6edcc7d6..c95b2870 100644 --- a/ios/chrome/browser/infobars/infobar_manager_impl.mm +++ b/ios/chrome/browser/infobars/infobar_manager_impl.mm
@@ -14,7 +14,7 @@ #include "ios/web/public/navigation_item.h" #include "ios/web/public/navigation_manager.h" #import "ios/web/public/web_state/navigation_context.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ui/base/page_transition_types.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm b/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm index b1d4b7b5..3bcc994 100644 --- a/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm +++ b/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm
@@ -12,7 +12,7 @@ #include "ios/web/public/interstitials/web_interstitial.h" #import "ios/web/public/navigation_manager.h" #include "ios/web/public/reload_type.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/interstitials/ios_chrome_metrics_helper.mm b/ios/chrome/browser/interstitials/ios_chrome_metrics_helper.mm index 93e14db2..bbacf3d 100644 --- a/ios/chrome/browser/interstitials/ios_chrome_metrics_helper.mm +++ b/ios/chrome/browser/interstitials/ios_chrome_metrics_helper.mm
@@ -10,7 +10,7 @@ #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/history/history_service_factory.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm b/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm index ead53fc2..0acced4 100644 --- a/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm +++ b/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm
@@ -15,7 +15,7 @@ #include "ios/chrome/browser/pref_names.h" #include "ios/chrome/browser/ui/util/dynamic_type_util.h" #include "ios/web/public/interstitials/web_interstitial.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/webui/jstemplate_builder.h" #include "ui/base/webui/web_ui_util.h"
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm index f2ee33b..4462781 100644 --- a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm +++ b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
@@ -19,7 +19,6 @@ #include "base/rand_util.h" #include "base/strings/string16.h" #include "base/threading/platform_thread.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/crash/core/common/crash_keys.h" #include "components/history/core/browser/history_service.h" #include "components/keyed_service/core/service_access_type.h" @@ -41,6 +40,7 @@ #include "components/prefs/pref_service.h" #include "components/signin/core/browser/signin_status_metrics_provider.h" #include "components/sync/device_info/device_count_metrics_provider.h" +#include "components/sync/driver/sync_service.h" #include "components/ukm/ukm_service.h" #include "components/variations/variations_associated_data.h" #include "components/version_info/version_info.h" @@ -293,11 +293,10 @@ ios::HistoryServiceFactory::GetForBrowserState( browser_state, ServiceAccessType::IMPLICIT_ACCESS); ObserveServiceForDeletions(history_service); - browser_sync::ProfileSyncService* sync = + syncer::SyncService* sync = ProfileSyncServiceFactory::GetInstance()->GetForBrowserState( browser_state); - ObserveServiceForSyncDisables(static_cast<syncer::SyncService*>(sync), - browser_state->GetPrefs()); + ObserveServiceForSyncDisables(sync, browser_state->GetPrefs()); return (history_service != nullptr && sync != nullptr); }
diff --git a/ios/chrome/browser/metrics/ios_profile_session_durations_service_factory.mm b/ios/chrome/browser/metrics/ios_profile_session_durations_service_factory.mm index a170495..1d9ec34 100644 --- a/ios/chrome/browser/metrics/ios_profile_session_durations_service_factory.mm +++ b/ios/chrome/browser/metrics/ios_profile_session_durations_service_factory.mm
@@ -10,8 +10,8 @@ #include <memory> -#include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" +#include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/metrics/ios_profile_session_durations_service.h"
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm index 8b400485..a089019 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm +++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
@@ -9,7 +9,6 @@ #include "base/no_destructor.h" #include "components/autofill/core/common/password_form.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/core/service_access_type.h" #include "components/password_manager/core/browser/log_manager.h" #include "components/password_manager/core/browser/password_form_manager_for_ui.h" @@ -18,6 +17,7 @@ #include "components/password_manager/core/browser/password_manager_util.h" #include "components/password_manager/core/browser/store_metrics_reporter.h" #include "components/password_manager/core/common/password_manager_pref_names.h" +#include "components/sync/driver/sync_service.h" #include "components/translate/core/browser/translate_manager.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" @@ -76,7 +76,7 @@ IOSChromePasswordManagerClient::~IOSChromePasswordManagerClient() = default; SyncState IOSChromePasswordManagerClient::GetPasswordSyncState() const { - browser_sync::ProfileSyncService* sync_service = + syncer::SyncService* sync_service = ProfileSyncServiceFactory::GetForBrowserState(delegate_.browserState); return password_manager_util::GetPasswordSyncState(sync_service); }
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc b/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc index 8cbcf3f..24f734c 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc +++ b/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc
@@ -13,7 +13,6 @@ #include "base/sequenced_task_runner.h" #include "base/task/post_task.h" #include "base/threading/sequenced_task_runner_handle.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/core/service_access_type.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
diff --git a/ios/chrome/browser/passwords/js_credential_manager.mm b/ios/chrome/browser/passwords/js_credential_manager.mm index f555dbb6..51638b40 100644 --- a/ios/chrome/browser/passwords/js_credential_manager.mm +++ b/ios/chrome/browser/passwords/js_credential_manager.mm
@@ -8,7 +8,7 @@ #include "base/strings/string16.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm index a73ac1f..96cbca5 100644 --- a/ios/chrome/browser/passwords/password_controller.mm +++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -29,7 +29,6 @@ #include "components/autofill/core/common/password_form_generation_data.h" #include "components/autofill/ios/browser/autofill_util.h" #import "components/autofill/ios/form_util/form_activity_observer_bridge.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/infobars/core/infobar_manager.h" #include "components/password_manager/core/browser/form_parsing/ios_form_parser.h" #include "components/password_manager/core/browser/password_bubble_experiment.h"
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm b/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm index 8c6c598..1b34e0e9 100644 --- a/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm +++ b/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm
@@ -19,7 +19,7 @@ #include "ios/web/public/navigation_item.h" #include "ios/web/public/navigation_manager.h" #include "ios/web/public/ssl_status.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "net/base/mac/url_conversions.h" #include "net/base/url_util.h" #include "net/cert/x509_certificate.h"
diff --git a/ios/chrome/browser/payments/payment_request.mm b/ios/chrome/browser/payments/payment_request.mm index a80bed1..b271ae9 100644 --- a/ios/chrome/browser/payments/payment_request.mm +++ b/ios/chrome/browser/payments/payment_request.mm
@@ -34,7 +34,7 @@ #import "ios/chrome/browser/payments/ios_payment_instrument.h" #import "ios/chrome/browser/payments/payment_request_util.h" #include "ios/chrome/browser/signin/identity_manager_factory.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "services/identity/public/cpp/identity_manager.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
diff --git a/ios/chrome/browser/payments/payment_request_cache.h b/ios/chrome/browser/payments/payment_request_cache.h index fabcc4aca..47ac39e 100644 --- a/ios/chrome/browser/payments/payment_request_cache.h +++ b/ios/chrome/browser/payments/payment_request_cache.h
@@ -12,7 +12,7 @@ #include "base/macros.h" #include "components/keyed_service/core/keyed_service.h" #include "ios/chrome/browser/payments/payment_request.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" namespace payments {
diff --git a/ios/chrome/browser/prerender/prerender_service.mm b/ios/chrome/browser/prerender/prerender_service.mm index 59876a4..17ba5ef 100644 --- a/ios/chrome/browser/prerender/prerender_service.mm +++ b/ios/chrome/browser/prerender/prerender_service.mm
@@ -13,7 +13,7 @@ #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/web/public/navigation_manager.h" #include "ios/web/public/web_client.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ui/base/page_transition_types.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/signin/authentication_service.h b/ios/chrome/browser/signin/authentication_service.h index 233295b3..dc8217a 100644 --- a/ios/chrome/browser/signin/authentication_service.h +++ b/ios/chrome/browser/signin/authentication_service.h
@@ -17,8 +17,8 @@ #include "google_apis/gaia/oauth2_token_service.h" #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" -namespace browser_sync { -class ProfileSyncService; +namespace syncer { +class SyncService; } namespace identity { @@ -43,7 +43,7 @@ SyncSetupService* sync_setup_service, AccountTrackerService* account_tracker, identity::IdentityManager* identity_manager, - browser_sync::ProfileSyncService* sync_service); + syncer::SyncService* sync_service); ~AuthenticationService() override; // Registers the preferences used by AuthenticationService; @@ -202,7 +202,7 @@ SyncSetupService* sync_setup_service_ = nullptr; AccountTrackerService* account_tracker_ = nullptr; identity::IdentityManager* identity_manager_ = nullptr; - browser_sync::ProfileSyncService* sync_service_ = nullptr; + syncer::SyncService* sync_service_ = nullptr; // Whether Initialized has been called. bool initialized_ = false;
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm index 5cd174e..d890a2e 100644 --- a/ios/chrome/browser/signin/authentication_service.mm +++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -12,7 +12,6 @@ #include "base/single_thread_task_runner.h" #include "base/strings/sys_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" #include "components/signin/core/browser/account_info.h" @@ -73,7 +72,7 @@ SyncSetupService* sync_setup_service, AccountTrackerService* account_tracker, identity::IdentityManager* identity_manager, - browser_sync::ProfileSyncService* sync_service) + syncer::SyncService* sync_service) : pref_service_(pref_service), token_service_(token_service), sync_setup_service_(sync_setup_service),
diff --git a/ios/chrome/browser/signin/authentication_service_fake.h b/ios/chrome/browser/signin/authentication_service_fake.h index 0fde8cb3..331e400 100644 --- a/ios/chrome/browser/signin/authentication_service_fake.h +++ b/ios/chrome/browser/signin/authentication_service_fake.h
@@ -48,7 +48,7 @@ SyncSetupService* sync_setup_service, AccountTrackerService* account_tracker, identity::IdentityManager* identity_manager, - browser_sync::ProfileSyncService* sync_service); + syncer::SyncService* sync_service); __strong ChromeIdentity* authenticated_identity_; bool have_accounts_changed_;
diff --git a/ios/chrome/browser/signin/authentication_service_fake.mm b/ios/chrome/browser/signin/authentication_service_fake.mm index 3c7e808..f4cf4a9 100644 --- a/ios/chrome/browser/signin/authentication_service_fake.mm +++ b/ios/chrome/browser/signin/authentication_service_fake.mm
@@ -27,7 +27,7 @@ SyncSetupService* sync_setup_service, AccountTrackerService* account_tracker, identity::IdentityManager* identity_manager, - browser_sync::ProfileSyncService* sync_service) + syncer::SyncService* sync_service) : AuthenticationService(pref_service, token_service, sync_setup_service,
diff --git a/ios/chrome/browser/ssl/ios_security_state_tab_helper.mm b/ios/chrome/browser/ssl/ios_security_state_tab_helper.mm index 49791f8f..aeba092 100644 --- a/ios/chrome/browser/ssl/ios_security_state_tab_helper.mm +++ b/ios/chrome/browser/ssl/ios_security_state_tab_helper.mm
@@ -16,7 +16,7 @@ #import "ios/web/public/origin_util.h" #include "ios/web/public/security_style.h" #include "ios/web/public/ssl_status.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "net/cert/x509_certificate.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm b/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm index 23b3c57..56715bc8 100644 --- a/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm +++ b/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
@@ -18,7 +18,7 @@ #include "ios/chrome/browser/interstitials/ios_chrome_metrics_helper.h" #import "ios/web/public/navigation_item.h" #include "ios/web/public/ssl_status.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "net/base/net_errors.h" #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h"
diff --git a/ios/chrome/browser/suggestions/suggestions_service_factory.mm b/ios/chrome/browser/suggestions/suggestions_service_factory.mm index aec31f0..a01a5583 100644 --- a/ios/chrome/browser/suggestions/suggestions_service_factory.mm +++ b/ios/chrome/browser/suggestions/suggestions_service_factory.mm
@@ -11,11 +11,11 @@ #include "base/memory/singleton.h" #include "base/task/post_task.h" #include "base/time/default_tick_clock.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" #include "components/suggestions/blacklist_store.h" #include "components/suggestions/suggestions_service_impl.h" #include "components/suggestions/suggestions_store.h" +#include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/signin/identity_manager_factory.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" @@ -60,7 +60,7 @@ ios::ChromeBrowserState::FromBrowserState(context); identity::IdentityManager* identity_manager = IdentityManagerFactory::GetForBrowserState(browser_state); - browser_sync::ProfileSyncService* sync_service = + syncer::SyncService* sync_service = ProfileSyncServiceFactory::GetForBrowserState(browser_state); std::unique_ptr<SuggestionsStore> suggestions_store(
diff --git a/ios/chrome/browser/sync/glue/sync_start_util.cc b/ios/chrome/browser/sync/glue/sync_start_util.cc index 3ab5672..4f211db 100644 --- a/ios/chrome/browser/sync/glue/sync_start_util.cc +++ b/ios/chrome/browser/sync/glue/sync_start_util.cc
@@ -8,7 +8,6 @@ #include "base/files/file_path.h" #include "base/location.h" #include "base/task/post_task.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm index 2da7c9d..ff2a9e6 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -37,6 +37,7 @@ #include "components/search_engines/search_engine_data_type_controller.h" #include "components/sync/base/report_unrecoverable_error.h" #include "components/sync/driver/sync_api_component_factory.h" +#include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_util.h" #include "components/sync/engine/passive_model_worker.h" #include "components/sync/engine/sequenced_model_worker.h" @@ -61,7 +62,6 @@ #include "ios/chrome/browser/sync/device_info_sync_service_factory.h" #include "ios/chrome/browser/sync/ios_user_event_service_factory.h" #include "ios/chrome/browser/sync/model_type_store_service_factory.h" -#include "ios/chrome/browser/sync/profile_sync_service_factory.h" #include "ios/chrome/browser/sync/session_sync_service_factory.h" #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h" #include "ios/chrome/browser/web_data_service_factory.h"
diff --git a/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm b/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm index 2b9d553..9bee2a3 100644 --- a/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm +++ b/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm
@@ -14,7 +14,7 @@ #include "ios/web/public/favicon_status.h" #include "ios/web/public/navigation_item.h" #import "ios/web/public/navigation_manager.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/sync/ios_user_event_service_factory.cc b/ios/chrome/browser/sync/ios_user_event_service_factory.cc index a0ceb70..27361c3 100644 --- a/ios/chrome/browser/sync/ios_user_event_service_factory.cc +++ b/ios/chrome/browser/sync/ios_user_event_service_factory.cc
@@ -8,10 +8,10 @@ #include <utility> #include "base/no_destructor.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" #include "components/sync/base/model_type.h" #include "components/sync/base/report_unrecoverable_error.h" +#include "components/sync/driver/sync_service.h" #include "components/sync/model/model_type_store_service.h" #include "components/sync/model_impl/client_tag_based_model_type_processor.h" #include "components/sync/user_events/no_op_user_event_service.h"
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.cc b/ios/chrome/browser/sync/profile_sync_service_factory.cc index 993e8a73..86e2564 100644 --- a/ios/chrome/browser/sync/profile_sync_service_factory.cc +++ b/ios/chrome/browser/sync/profile_sync_service_factory.cc
@@ -15,6 +15,7 @@ #include "components/keyed_service/ios/browser_state_dependency_manager.h" #include "components/network_time/network_time_tracker.h" #include "components/sync/driver/startup_controller.h" +#include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_util.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/autofill/personal_data_manager_factory.h" @@ -44,8 +45,6 @@ #include "services/network/public/cpp/shared_url_loader_factory.h" #include "url/gurl.h" -using browser_sync::ProfileSyncService; - namespace { void UpdateNetworkTimeOnUIThread(base::Time network_time, @@ -74,25 +73,41 @@ } // static -ProfileSyncService* ProfileSyncServiceFactory::GetForBrowserState( +syncer::SyncService* ProfileSyncServiceFactory::GetForBrowserState( ios::ChromeBrowserState* browser_state) { - if (!ProfileSyncService::IsSyncAllowedByFlag()) + if (!browser_sync::ProfileSyncService::IsSyncAllowedByFlag()) return nullptr; - return static_cast<ProfileSyncService*>( + return static_cast<syncer::SyncService*>( GetInstance()->GetServiceForBrowserState(browser_state, true)); } // static -ProfileSyncService* ProfileSyncServiceFactory::GetForBrowserStateIfExists( +syncer::SyncService* ProfileSyncServiceFactory::GetForBrowserStateIfExists( ios::ChromeBrowserState* browser_state) { - if (!ProfileSyncService::IsSyncAllowedByFlag()) + if (!browser_sync::ProfileSyncService::IsSyncAllowedByFlag()) return nullptr; - return static_cast<ProfileSyncService*>( + return static_cast<syncer::SyncService*>( GetInstance()->GetServiceForBrowserState(browser_state, false)); } +// static +browser_sync::ProfileSyncService* +ProfileSyncServiceFactory::GetAsProfileSyncServiceForBrowserState( + ios::ChromeBrowserState* browser_state) { + return static_cast<browser_sync::ProfileSyncService*>( + GetForBrowserState(browser_state)); +} + +// static +browser_sync::ProfileSyncService* +ProfileSyncServiceFactory::GetAsProfileSyncServiceForBrowserStateIfExists( + ios::ChromeBrowserState* browser_state) { + return static_cast<browser_sync::ProfileSyncService*>( + GetForBrowserStateIfExists(browser_state)); +} + ProfileSyncServiceFactory::ProfileSyncServiceFactory() : BrowserStateKeyedServiceFactory( "ProfileSyncService", @@ -139,10 +154,10 @@ // startup once bug has been fixed. ios::AboutSigninInternalsFactory::GetForBrowserState(browser_state); - ProfileSyncService::InitParams init_params; + browser_sync::ProfileSyncService::InitParams init_params; init_params.identity_manager = IdentityManagerFactory::GetForBrowserState(browser_state); - init_params.start_behavior = ProfileSyncService::MANUAL_START; + init_params.start_behavior = browser_sync::ProfileSyncService::MANUAL_START; init_params.sync_client = std::make_unique<IOSChromeSyncClient>(browser_state); init_params.network_time_update_callback = base::Bind(&UpdateNetworkTime); @@ -174,7 +189,8 @@ deprecated_invalidation_provider->GetIdentityProvider()); } - auto pss = std::make_unique<ProfileSyncService>(std::move(init_params)); + auto pss = std::make_unique<browser_sync::ProfileSyncService>( + std::move(init_params)); pss->Initialize(); return pss; }
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.h b/ios/chrome/browser/sync/profile_sync_service_factory.h index cbc871f..59748b5 100644 --- a/ios/chrome/browser/sync/profile_sync_service_factory.h +++ b/ios/chrome/browser/sync/profile_sync_service_factory.h
@@ -15,18 +15,30 @@ class ProfileSyncService; } // namespace browser_sync +namespace syncer { +class SyncService; +} // namespace syncer + namespace ios { class ChromeBrowserState; } // namespace ios -// Singleton that owns all ProfileSyncService and associates them with +// Singleton that owns all SyncServices and associates them with // ios::ChromeBrowserState. class ProfileSyncServiceFactory : public BrowserStateKeyedServiceFactory { public: - static browser_sync::ProfileSyncService* GetForBrowserState( + static syncer::SyncService* GetForBrowserState( ios::ChromeBrowserState* browser_state); - static browser_sync::ProfileSyncService* GetForBrowserStateIfExists( + static syncer::SyncService* GetForBrowserStateIfExists( + ios::ChromeBrowserState* browser_state); + + static browser_sync::ProfileSyncService* + GetAsProfileSyncServiceForBrowserState( + ios::ChromeBrowserState* browser_state); + + static browser_sync::ProfileSyncService* + GetAsProfileSyncServiceForBrowserStateIfExists( ios::ChromeBrowserState* browser_state); static ProfileSyncServiceFactory* GetInstance();
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc b/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc index 2ebf3586..cf3eb278 100644 --- a/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc +++ b/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc
@@ -12,11 +12,11 @@ #include "base/feature_list.h" #include "base/task/task_scheduler/task_scheduler.h" #include "components/browser_sync/browser_sync_switches.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/sync/base/model_type.h" #include "components/sync/base/pref_names.h" #include "components/sync/driver/data_type_controller.h" #include "components/sync/driver/sync_driver_switches.h" +#include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #include "ios/web/public/test/test_web_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" @@ -118,9 +118,9 @@ // Verify that a normal (no command line flags) PSS can be created and // properly initialized. TEST_F(ProfileSyncServiceFactoryTest, CreatePSSDefault) { - browser_sync::ProfileSyncService* pss = + syncer::SyncService* sync_service = ProfileSyncServiceFactory::GetForBrowserState(chrome_browser_state()); - syncer::ModelTypeSet types = pss->GetRegisteredDataTypes(); + syncer::ModelTypeSet types = sync_service->GetRegisteredDataTypes(); EXPECT_EQ(DefaultDatatypesCount(), types.Size()); CheckDefaultDatatypesInSetExcept(types, syncer::ModelTypeSet()); } @@ -130,9 +130,9 @@ TEST_F(ProfileSyncServiceFactoryTest, CreatePSSDisableOne) { syncer::ModelTypeSet disabled_types(syncer::AUTOFILL); SetDisabledTypes(disabled_types); - browser_sync::ProfileSyncService* pss = + syncer::SyncService* sync_service = ProfileSyncServiceFactory::GetForBrowserState(chrome_browser_state()); - syncer::ModelTypeSet types = pss->GetRegisteredDataTypes(); + syncer::ModelTypeSet types = sync_service->GetRegisteredDataTypes(); EXPECT_EQ(DefaultDatatypesCount() - disabled_types.Size(), types.Size()); CheckDefaultDatatypesInSetExcept(types, disabled_types); } @@ -143,9 +143,9 @@ syncer::ModelTypeSet disabled_types(syncer::AUTOFILL_PROFILE, syncer::BOOKMARKS); SetDisabledTypes(disabled_types); - browser_sync::ProfileSyncService* pss = + syncer::SyncService* sync_service = ProfileSyncServiceFactory::GetForBrowserState(chrome_browser_state()); - syncer::ModelTypeSet types = pss->GetRegisteredDataTypes(); + syncer::ModelTypeSet types = sync_service->GetRegisteredDataTypes(); EXPECT_EQ(DefaultDatatypesCount() - disabled_types.Size(), types.Size()); CheckDefaultDatatypesInSetExcept(types, disabled_types); }
diff --git a/ios/chrome/browser/sync/session_sync_service_factory.mm b/ios/chrome/browser/sync/session_sync_service_factory.mm index f274a50f..6a41eb2 100644 --- a/ios/chrome/browser/sync/session_sync_service_factory.mm +++ b/ios/chrome/browser/sync/session_sync_service_factory.mm
@@ -13,6 +13,7 @@ #include "components/keyed_service/core/service_access_type.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" #include "components/sync/device_info/local_device_info_provider.h" +#include "components/sync/driver/sync_service.h" #include "components/sync/model/model_type_store_service.h" #include "components/sync_sessions/local_session_event_router.h" #include "components/sync_sessions/session_sync_prefs.h" @@ -94,7 +95,8 @@ const syncer::DeviceInfo* GetLocalDeviceInfo() override { DCHECK_CURRENTLY_ON(web::WebThread::UI); browser_sync::ProfileSyncService* profile_sync_service = - ProfileSyncServiceFactory::GetForBrowserStateIfExists(browser_state_); + ProfileSyncServiceFactory:: + GetAsProfileSyncServiceForBrowserStateIfExists(browser_state_); if (!profile_sync_service) { return nullptr; }
diff --git a/ios/chrome/browser/sync/sync_setup_service_factory.cc b/ios/chrome/browser/sync/sync_setup_service_factory.cc index 61975b1..ffed08c 100644 --- a/ios/chrome/browser/sync/sync_setup_service_factory.cc +++ b/ios/chrome/browser/sync/sync_setup_service_factory.cc
@@ -5,8 +5,8 @@ #include "ios/chrome/browser/sync/sync_setup_service_factory.h" #include "base/no_destructor.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" +#include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" #include "ios/chrome/browser/sync/sync_setup_service.h"
diff --git a/ios/chrome/browser/translate/chrome_ios_translate_client.mm b/ios/chrome/browser/translate/chrome_ios_translate_client.mm index 78be270..447c61e0 100644 --- a/ios/chrome/browser/translate/chrome_ios_translate_client.mm +++ b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
@@ -42,7 +42,7 @@ #include "ios/web/public/browser_state.h" #include "ios/web/public/navigation_item.h" #include "ios/web/public/navigation_manager.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "third_party/metrics_proto/translate_event.pb.h" #include "url/gurl.h"
diff --git a/ios/chrome/browser/ui/UIView+SizeClassSupport.mm b/ios/chrome/browser/ui/UIView+SizeClassSupport.mm index 9a31298..137d6e8 100644 --- a/ios/chrome/browser/ui/UIView+SizeClassSupport.mm +++ b/ios/chrome/browser/ui/UIView+SizeClassSupport.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/UIView+SizeClassSupport.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/chrome/browser/ui/util/ui_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.mm b/ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.mm index e58c42ce..20dd3d1 100644 --- a/ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.mm +++ b/ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h" -#import "base/logging.h" +#include "base/logging.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn index 6d19bcb..78b4323 100644 --- a/ios/chrome/browser/ui/authentication/BUILD.gn +++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -136,6 +136,7 @@ "//ios/chrome/test:test_support", "//ios/public/provider/chrome/browser/signin:test_support", "//ios/web/public/test", + "//services/identity/public/cpp", "//testing/gtest", "//third_party/ocmock", "//ui/base",
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm index 1a700de..a366421 100644 --- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm
@@ -13,15 +13,14 @@ #include "components/consent_auditor/consent_auditor.h" #include "components/consent_auditor/fake_consent_auditor.h" #include "components/signin/core/browser/account_consistency_method.h" -#include "components/signin/core/browser/account_tracker_service.h" #include "components/unified_consent/feature.h" #include "components/unified_consent/scoped_unified_consent.h" #include "components/version_info/version_info.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" -#include "ios/chrome/browser/signin/account_tracker_service_factory.h" #import "ios/chrome/browser/signin/authentication_service_factory.h" #import "ios/chrome/browser/signin/authentication_service_fake.h" +#include "ios/chrome/browser/signin/identity_manager_factory.h" #include "ios/chrome/browser/sync/consent_auditor_factory.h" #include "ios/chrome/browser/sync/ios_user_event_service_factory.h" #include "ios/chrome/browser/unified_consent/unified_consent_service_factory.h" @@ -30,6 +29,7 @@ #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h" #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h" #include "ios/web/public/test/test_web_thread_bundle.h" +#include "services/identity/public/cpp/identity_manager.h" #import "testing/platform_test.h" #import "third_party/ocmock/OCMock/OCMock.h" #include "third_party/ocmock/gtest_support.h" @@ -131,9 +131,8 @@ ios::FakeChromeIdentityService* identity_service = ios::FakeChromeIdentityService::GetInstanceFromChromeProvider(); identity_service->AddIdentity(identity_); - account_tracker_service_ = - ios::AccountTrackerServiceFactory::GetForBrowserState(context_.get()); - + identity_manager_ = + IdentityManagerFactory::GetForBrowserState(context_.get()); fake_consent_auditor_ = static_cast<consent_auditor::FakeConsentAuditor*>( ConsentAuditorFactory::GetForBrowserState(context_.get())); @@ -372,7 +371,7 @@ UIWindow* window_; ChromeSigninViewController* vc_; consent_auditor::FakeConsentAuditor* fake_consent_auditor_; - AccountTrackerService* account_tracker_service_; + identity::IdentityManager* identity_manager_; base::MockOneShotTimer* mock_timer_ptr_ = nullptr; FakeChromeSigninViewControllerDelegate* vc_delegate_; }; @@ -407,7 +406,7 @@ fake_consent_auditor_->recorded_statuses().at(0)); EXPECT_EQ(consent_auditor::Feature::CHROME_SYNC, fake_consent_auditor_->recorded_features().at(0)); - EXPECT_EQ(account_tracker_service_->PickAccountIdForAccount( + EXPECT_EQ(identity_manager_->LegacyPickAccountIdForAccount( base::SysNSStringToUTF8([identity_ gaiaID]), base::SysNSStringToUTF8([identity_ userEmail])), fake_consent_auditor_->account_id()); @@ -435,7 +434,7 @@ fake_consent_auditor_->recorded_statuses().at(0)); EXPECT_EQ(consent_auditor::Feature::CHROME_SYNC, fake_consent_auditor_->recorded_features().at(0)); - EXPECT_EQ(account_tracker_service_->PickAccountIdForAccount( + EXPECT_EQ(identity_manager_->LegacyPickAccountIdForAccount( base::SysNSStringToUTF8([identity_ gaiaID]), base::SysNSStringToUTF8([identity_ userEmail])), fake_consent_auditor_->account_id());
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h index 08cf210..56d647f 100644 --- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h +++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
@@ -71,6 +71,7 @@ base::OnceClosure show_migration_dialog_closure) override; void ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) override; void ShowLocalCardMigrationResults(
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm index 157ec63a..6785b20d 100644 --- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm +++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
@@ -18,9 +18,9 @@ #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/ios/browser/autofill_util.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/infobars/core/infobar.h" #include "components/keyed_service/core/service_access_type.h" +#include "components/sync/driver/sync_service.h" #include "components/translate/core/browser/translate_manager.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/autofill/address_normalizer_factory.h" @@ -216,6 +216,7 @@ void ChromeAutofillClientIOS::ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) { NOTIMPLEMENTED();
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm index 368ea24d..cbeca5e7 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm +++ b/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm
@@ -31,7 +31,7 @@ #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" #include "ios/web/public/web_state/web_frame.h" #include "ios/web/public/web_state/web_frames_manager.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.mm b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.mm index 6d9026c..2a950d30 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.mm
@@ -7,7 +7,7 @@ #import "components/autofill/ios/form_util/form_activity_observer_bridge.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm index 2b624cd..a17a831 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm
@@ -26,7 +26,7 @@ #include "ios/web/public/web_state/web_frame.h" #include "ios/web/public/web_state/web_frame_util.h" #include "ios/web/public/web_state/web_frames_manager.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ui/base/l10n/l10n_util_mac.h" #include "url/gurl.h"
diff --git a/ios/chrome/browser/ui/bookmarks/synced_bookmarks_bridge.mm b/ios/chrome/browser/ui/bookmarks/synced_bookmarks_bridge.mm index 16b741a..4454757 100644 --- a/ios/chrome/browser/ui/bookmarks/synced_bookmarks_bridge.mm +++ b/ios/chrome/browser/ui/bookmarks/synced_bookmarks_bridge.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/bookmarks/synced_bookmarks_bridge.h" -#include "components/browser_sync/profile_sync_service.h" +#include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/signin/identity_manager_factory.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
diff --git a/ios/chrome/browser/ui/broadcaster/chrome_broadcaster.mm b/ios/chrome/browser/ui/broadcaster/chrome_broadcaster.mm index c4f077c..e9076cf5 100644 --- a/ios/chrome/browser/ui/broadcaster/chrome_broadcaster.mm +++ b/ios/chrome/browser/ui/broadcaster/chrome_broadcaster.mm
@@ -8,7 +8,7 @@ #include <memory> #import "base/ios/crb_protocol_observers.h" -#import "base/logging.h" +#include "base/logging.h" #import "base/mac/foundation_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/browser_container/browser_container_coordinator.mm b/ios/chrome/browser/ui/browser_container/browser_container_coordinator.mm index c230415..d2b9495 100644 --- a/ios/chrome/browser/ui/browser_container/browser_container_coordinator.mm +++ b/ios/chrome/browser/ui/browser_container/browser_container_coordinator.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/browser_container/browser_container_coordinator.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/chrome/browser/ui/browser_container/browser_container_view_controller.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_item.mm b/ios/chrome/browser/ui/collection_view/cells/collection_view_item.mm index dea0fabd..9005acb5 100644 --- a/ios/chrome/browser/ui/collection_view/cells/collection_view_item.mm +++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_item.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/dialogs/dialog_presenter.mm b/ios/chrome/browser/ui/dialogs/dialog_presenter.mm index b0d112a2..4b3d5bc 100644 --- a/ios/chrome/browser/ui/dialogs/dialog_presenter.mm +++ b/ios/chrome/browser/ui/dialogs/dialog_presenter.mm
@@ -19,7 +19,7 @@ #import "ios/chrome/browser/ui/dialogs/nsurl_protection_space_util.h" #include "ios/chrome/browser/ui/util/ui_util.h" #include "ios/chrome/grit/ios_strings.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h"
diff --git a/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm b/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm index 551cd4b..345409b2 100644 --- a/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm +++ b/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
@@ -25,7 +25,7 @@ #import "ios/web/public/test/earl_grey/web_view_matchers.h" #include "ios/web/public/test/element_selector.h" #include "ios/web/public/test/url_test_util.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" #include "net/test/embedded_test_server/request_handler_util.h"
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator.mm b/ios/chrome/browser/ui/download/download_manager_coordinator.mm index 2c42ee93..0702bf1 100644 --- a/ios/chrome/browser/ui/download/download_manager_coordinator.mm +++ b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
@@ -9,7 +9,7 @@ #include <memory> -#import "base/logging.h" +#include "base/logging.h" #include "base/mac/scoped_cftyperef.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h"
diff --git a/ios/chrome/browser/ui/external_file_remover_impl.mm b/ios/chrome/browser/ui/external_file_remover_impl.mm index cb592723..1e44a9f 100644 --- a/ios/chrome/browser/ui/external_file_remover_impl.mm +++ b/ios/chrome/browser/ui/external_file_remover_impl.mm
@@ -21,7 +21,7 @@ #import "ios/chrome/browser/ui/external_file_controller.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #include "ios/web/public/navigation_item.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ios/web/public/web_thread.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm index 3f046ff..8bd70eb 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm
@@ -126,8 +126,8 @@ assertWithMatcher:grey_scrollViewContentOffset(CGPointMake(0, yOffset))]; } -// Verifies that the toolbar properly appears/disappears when scrolling up/down -// on a PDF that is short in length and wide in width. +// Verifies that the toolbar is not hidden when scrolling a short pdf, as the +// entire document is visible without hiding the toolbar. - (void)testSmallWidePDFScroll { web::test::SetUpFileBasedHttpServer(); GURL URL = web::test::HttpServer::MakeUrl( @@ -149,16 +149,10 @@ performAction:grey_swipeFastInDirection(kGREYDirectionDown)]; [ChromeEarlGreyUI waitForToolbarVisible:YES]; - if (base::ios::IsRunningOnIOS12OrLater()) { - // Test that the toolbar is still visible even after attempting to hide it - // on swipe up. - HideToolbarUsingUI(); - [ChromeEarlGreyUI waitForToolbarVisible:YES]; - } else { - // Test that the toolbar is no longer visible after a user swipes up. - HideToolbarUsingUI(); - [ChromeEarlGreyUI waitForToolbarVisible:NO]; - } + // Test that the toolbar is still visible even after attempting to hide it + // on swipe up. + HideToolbarUsingUI(); + [ChromeEarlGreyUI waitForToolbarVisible:YES]; // Reenable synchronization. if (@available(iOS 12, *)) {
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_model.h b/ios/chrome/browser/ui/fullscreen/fullscreen_model.h index 6dbeae97..4cd9cb8b 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_model.h +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_model.h
@@ -143,6 +143,10 @@ void SetScrollViewIsDragging(bool dragging); bool IsScrollViewDragging() const; + // Setter for whether the scroll view is resized for fullscreen events. + void SetResizesScrollView(bool resizes_scroll_view); + bool ResizesScrollView() const; + private: // Returns how a scroll to the current |y_content_offset_| from |from_offset| // should be handled. @@ -214,6 +218,8 @@ bool dragging_ = false; // Whether the in-progress scroll is being ignored. bool ignoring_current_scroll_ = false; + // Whether the scroll view is resized for fullscreen events. + bool resizes_scroll_view_ = false; // The number of FullscreenModelObserver callbacks currently being executed. size_t observer_callback_count_ = 0;
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_model.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_model.mm index c6a1133..daa1aadb 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_model.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_model.mm
@@ -220,6 +220,14 @@ return dragging_; } +void FullscreenModel::SetResizesScrollView(bool resizes_scroll_view) { + resizes_scroll_view_ = resizes_scroll_view; +} + +bool FullscreenModel::ResizesScrollView() const { + return resizes_scroll_view_; +} + FullscreenModel::ScrollAction FullscreenModel::ActionForScrollFromOffset( CGFloat from_offset) const { // Update the base offset but don't recalculate progress if: @@ -264,7 +272,20 @@ } void FullscreenModel::UpdateDisabledCounterForContentHeight() { - bool disable = content_height_ < scroll_view_height_; + // The model should be disabled when the content fits. + CGFloat disabling_threshold = scroll_view_height_; + if (resizes_scroll_view_) { + // When the FullscreenProvider is disabled, the scroll view can sometimes be + // resized to account for the viewport insets after the page has been + // rendered, so account for the maximum toolbar insets in the threshold. + disabling_threshold += expanded_toolbar_height_ + bottom_toolbar_height_; + } + + // Don't disable fullscreen if both heights have not been received. + bool areBothHeightsSet = !AreCGFloatsEqual(content_height_, 0.0) && + !AreCGFloatsEqual(scroll_view_height_, 0.0); + + bool disable = areBothHeightsSet && content_height_ <= disabling_threshold; if (disabled_for_short_content_ == disable) return; disabled_for_short_content_ = disable;
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_model_unittest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_model_unittest.mm index a763d782..2dd4b7f 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_model_unittest.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_model_unittest.mm
@@ -256,9 +256,10 @@ ASSERT_TRUE(model().enabled()); // The model should be disabled when the rendered content height is less than // the height of the scroll view. - model().SetContentHeight(model().GetScrollViewHeight() - 1.0); + model().SetContentHeight(model().GetScrollViewHeight()); EXPECT_FALSE(model().enabled()); // Reset the height to kContentHeight and verify that the model is re-enabled. - model().SetContentHeight(model().GetScrollViewHeight() + 1.0); + model().SetContentHeight(model().GetScrollViewHeight() + 2 * kToolbarHeight + + 1.0); EXPECT_TRUE(model().enabled()); }
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm index cb592a21..9a434e9 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
@@ -13,6 +13,8 @@ #import "ios/chrome/browser/ui/fullscreen/fullscreen_web_view_proxy_observer.h" #import "ios/chrome/browser/ui/fullscreen/scoped_fullscreen_disabler.h" #include "ios/chrome/browser/ui/util/ui_util.h" +#include "ios/public/provider/chrome/browser/chrome_browser_provider.h" +#import "ios/public/provider/chrome/browser/ui/fullscreen_provider.h" #import "ios/web/public/navigation_item.h" #import "ios/web/public/navigation_manager.h" #include "ios/web/public/ssl_status.h" @@ -115,6 +117,11 @@ id<CRWWebViewProxy> web_view_proxy = web_state->GetWebViewProxy(); web_view_proxy.shouldUseViewContentInset = use_content_inset; + model_->SetResizesScrollView(!use_content_inset && + !ios::GetChromeBrowserProvider() + ->GetFullscreenProvider() + ->IsInitialized()); + // On iOS 12, resetting WKScrollView.contentInset at this point in the load // will push the content down by the top inset. On iOS 11, however, this does // not occur. Manually push the content below the toolbars the first time a
diff --git a/ios/chrome/browser/ui/history/history_coordinator.mm b/ios/chrome/browser/ui/history/history_coordinator.mm index 5cd2ed3..fda4a92 100644 --- a/ios/chrome/browser/ui/history/history_coordinator.mm +++ b/ios/chrome/browser/ui/history/history_coordinator.mm
@@ -4,9 +4,9 @@ #include "ios/chrome/browser/ui/history/history_coordinator.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/history/core/browser/browsing_history_service.h" #include "components/keyed_service/core/service_access_type.h" +#include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/history/history_service_factory.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" #import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h"
diff --git a/ios/chrome/browser/ui/list_model/list_item.mm b/ios/chrome/browser/ui/list_model/list_item.mm index e628f6e..6b902388 100644 --- a/ios/chrome/browser/ui/list_model/list_item.mm +++ b/ios/chrome/browser/ui/list_model/list_item.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/list_model/list_item.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/chrome/browser/ui/list_model/list_item+Controller.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm b/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm index 043ce50d..fe993ccf 100644 --- a/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm +++ b/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
@@ -21,7 +21,7 @@ #import "ios/web/public/navigation_manager.h" #include "ios/web/public/ssl_status.h" #import "ios/web/public/web_client.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #import "ios/web/public/web_state/web_state_observer_bridge.h" #include "skia/ext/skia_utils_ios.h"
diff --git a/ios/chrome/browser/ui/main/browser_coordinator.mm b/ios/chrome/browser/ui/main/browser_coordinator.mm index e6ad27a..5659651 100644 --- a/ios/chrome/browser/ui/main/browser_coordinator.mm +++ b/ios/chrome/browser/ui/main/browser_coordinator.mm
@@ -243,12 +243,17 @@ [self.ARQuickLookCoordinator start]; } - self.formInputAccessoryCoordinator = [[FormInputAccessoryCoordinator alloc] - initWithBaseViewController:self.viewController - browserState:self.browserState - webStateList:self.tabModel.webStateList]; - self.formInputAccessoryCoordinator.delegate = self; - [self.formInputAccessoryCoordinator start]; + // TODO(crbug.com/923857): add manual fallback to incognito mode. Right now + // two formInputAccessoryViews are (lazy) created for normal and incognito, + // and the incognito remains on top when going back to normal. + if (!self.browserState->IsOffTheRecord()) { + self.formInputAccessoryCoordinator = [[FormInputAccessoryCoordinator alloc] + initWithBaseViewController:self.viewController + browserState:self.browserState + webStateList:self.tabModel.webStateList]; + self.formInputAccessoryCoordinator.delegate = self; + [self.formInputAccessoryCoordinator start]; + } if (base::FeatureList::IsEnabled(translate::kCompactTranslateInfobarIOS)) { self.translatePopupMenuCoordinator = [[TranslatePopupMenuCoordinator alloc]
diff --git a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm index 90328250..b9947ff 100644 --- a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm +++ b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm
@@ -24,7 +24,7 @@ #include "ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.h" #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" #import "ios/web/public/navigation_manager.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "url/gurl.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm index 26fd7fe..e39d75fc 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
@@ -546,7 +546,7 @@ void OmniboxViewIOS::OnDidChange(bool processing_user_event) { omnibox_interacted_while_focused_ = YES; - DCHECK(processing_user_event); + // Sanitize pasted text. if (model()->is_pasting()) { base::string16 pastedText = base::SysNSStringToUTF16([field_ text]);
diff --git a/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_gesture_recognizer.mm b/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_gesture_recognizer.mm index 617baea..5264814e 100644 --- a/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_gesture_recognizer.mm +++ b/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_gesture_recognizer.mm
@@ -6,7 +6,7 @@ #import <UIKit/UIGestureRecognizerSubclass.h> -#import "base/logging.h" +#include "base/logging.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm b/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm index 1605620..29aa382 100644 --- a/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm +++ b/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/payments/payment_request_picker_view_controller.h" -#import "base/logging.h" +#include "base/logging.h" #import "base/mac/foundation_util.h" #import "ios/chrome/browser/ui/icons/chrome_icon.h" #import "ios/chrome/browser/ui/material_components/chrome_app_bar_view_controller.h"
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm index 7b19ac74..3fd9d0d7 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -40,7 +40,7 @@ #include "ios/web/public/navigation_manager.h" #include "ios/web/public/user_agent.h" #include "ios/web/public/web_client.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #import "ios/web/public/web_state/web_state_observer_bridge.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/image/image.h"
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator_unittest.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator_unittest.mm index 9e96bb0..a96b50c 100644 --- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator_unittest.mm
@@ -8,7 +8,7 @@ #include <memory> -#include "components/browser_sync/profile_sync_service.h" +#include "components/sync/driver/sync_service.h" #include "components/sync/model/fake_model_type_controller_delegate.h" #include "components/sync_sessions/open_tabs_ui_delegate.h" #include "components/sync_sessions/session_sync_service.h"
diff --git a/ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.mm b/ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.mm index 95f87eca..9006d74 100644 --- a/ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.mm +++ b/ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.h" -#import "base/logging.h" +#include "base/logging.h" #include "ios/chrome/browser/crash_loop_detection_util.h" #import "ios/chrome/browser/ui/safe_mode/safe_mode_view_controller.h"
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn index eaca48b5..bb5610f22 100644 --- a/ios/chrome/browser/ui/settings/BUILD.gn +++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -56,6 +56,10 @@ "handoff_table_view_controller.mm", "import_data_table_view_controller.h", "import_data_table_view_controller.mm", + "manage_sync_settings_coordinator.h", + "manage_sync_settings_coordinator.mm", + "manage_sync_settings_table_view_controller.h", + "manage_sync_settings_table_view_controller.mm", "material_cell_catalog_view_controller.h", "material_cell_catalog_view_controller.mm", "password_details_table_view_controller.h", @@ -228,8 +232,8 @@ "passphrase_table_view_controller_test.mm", "password_details_table_view_controller+testing.h", "password_exporter_for_testing.h", - "personal_data_manager_data_changed_observer.cc", - "personal_data_manager_data_changed_observer.h", + "personal_data_manager_finished_profile_tasks_waiter.cc", + "personal_data_manager_finished_profile_tasks_waiter.h", "reauthentication_module_for_testing.h", ] deps = [
diff --git a/ios/chrome/browser/ui/settings/accounts_table_egtest.mm b/ios/chrome/browser/ui/settings/accounts_table_egtest.mm index 38f520f..4813e1b 100644 --- a/ios/chrome/browser/ui/settings/accounts_table_egtest.mm +++ b/ios/chrome/browser/ui/settings/accounts_table_egtest.mm
@@ -8,6 +8,10 @@ #include "base/strings/sys_string_conversions.h" #include "components/browser_sync/profile_sync_service.h" #include "components/strings/grit/components_strings.h" +#include "components/sync/base/nigori.h" +#include "components/sync/driver/sync_service.h" +#include "components/sync/engine/sync_encryption_handler.h" +#include "components/sync/protocol/proto_value_conversions.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/experimental_flags.h" #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.h" @@ -288,7 +292,8 @@ ios::ChromeBrowserState* browser_state = chrome_test_util::GetOriginalBrowserState(); browser_sync::ProfileSyncService* profile_sync_service = - ProfileSyncServiceFactory::GetForBrowserState(browser_state); + ProfileSyncServiceFactory::GetAsProfileSyncServiceForBrowserState( + browser_state); profile_sync_service->GetEncryptionObserverForTest()->OnPassphraseRequired( syncer::REASON_DECRYPTION, syncer::KeyDerivationParams::CreateForPbkdf2(),
diff --git a/ios/chrome/browser/ui/settings/accounts_table_view_controller.mm b/ios/chrome/browser/ui/settings/accounts_table_view_controller.mm index 8e7937a..38fa29b 100644 --- a/ios/chrome/browser/ui/settings/accounts_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/accounts_table_view_controller.mm
@@ -8,8 +8,8 @@ #include "base/metrics/user_metrics.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/strings/grit/components_strings.h" +#include "components/sync/driver/sync_service.h" #include "components/unified_consent/feature.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/signin/authentication_service.h" @@ -128,7 +128,7 @@ if (self) { _browserState = browserState; _closeSettingsOnAddAccount = closeSettingsOnAddAccount; - browser_sync::ProfileSyncService* syncService = + syncer::SyncService* syncService = ProfileSyncServiceFactory::GetForBrowserState(_browserState); if (!unified_consent::IsUnifiedConsentFeatureEnabled()) { // When unified consent flag is enabled, the sync settings are available
diff --git a/ios/chrome/browser/ui/settings/autofill_credit_card_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/autofill_credit_card_table_view_controller_unittest.mm index be41c32c..9271822 100644 --- a/ios/chrome/browser/ui/settings/autofill_credit_card_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/autofill_credit_card_table_view_controller_unittest.mm
@@ -12,7 +12,7 @@ #include "components/autofill/core/browser/personal_data_manager.h" #include "ios/chrome/browser/autofill/personal_data_manager_factory.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" -#include "ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.h" +#include "ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller_test.h" #include "ios/web/public/test/test_web_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" @@ -46,7 +46,7 @@ autofill::PersonalDataManager* personal_data_manager = autofill::PersonalDataManagerFactory::GetForBrowserState( chrome_browser_state_.get()); - PersonalDataManagerDataChangedObserver observer(personal_data_manager); + PersonalDataManagerFinishedProfileTasksWaiter waiter(personal_data_manager); autofill::CreditCard credit_card(base::GenerateGUID(), origin); credit_card.SetRawInfo(autofill::CREDIT_CARD_NAME_FULL, @@ -54,7 +54,7 @@ credit_card.SetRawInfo(autofill::CREDIT_CARD_NUMBER, base::ASCIIToUTF16(card_number)); personal_data_manager->OnAcceptedLocalCreditCardSave(credit_card); - observer.Wait(); // Wait for completion of the asynchronous operation. + waiter.Wait(); // Wait for completion of the asynchronous operation. } // Deletes the item at (section, row) and waits util condition returns true or
diff --git a/ios/chrome/browser/ui/settings/autofill_profile_edit_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/autofill_profile_edit_table_view_controller_unittest.mm index 540aec7..90e0c5a 100644 --- a/ios/chrome/browser/ui/settings/autofill_profile_edit_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/autofill_profile_edit_table_view_controller_unittest.mm
@@ -14,7 +14,7 @@ #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/autofill/personal_data_manager_factory.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" -#include "ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.h" +#include "ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.h" #import "ios/chrome/browser/ui/table_view/table_view_model.h" #include "ios/web/public/test/test_web_thread_bundle.h" #include "testing/platform_test.h" @@ -55,7 +55,8 @@ personal_data_manager_ = autofill::PersonalDataManagerFactory::GetForBrowserState( chrome_browser_state_.get()); - PersonalDataManagerDataChangedObserver observer(personal_data_manager_); + PersonalDataManagerFinishedProfileTasksWaiter waiter( + personal_data_manager_); std::string guid = base::GenerateGUID(); @@ -68,7 +69,7 @@ base::UTF8ToUTF16(kTestAddressLine1)); personal_data_manager_->SaveImportedProfile(autofill_profile); - observer.Wait(); // Wait for the completion of the asynchronous operation. + waiter.Wait(); // Wait for the completion of the asynchronous operation. autofill_profile_edit_controller_ = [AutofillProfileEditTableViewController controllerWithProfile:autofill_profile
diff --git a/ios/chrome/browser/ui/settings/autofill_profile_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/autofill_profile_table_view_controller_unittest.mm index e587f86c..bd0aa7c 100644 --- a/ios/chrome/browser/ui/settings/autofill_profile_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/autofill_profile_table_view_controller_unittest.mm
@@ -13,7 +13,7 @@ #include "components/strings/grit/components_strings.h" #include "ios/chrome/browser/autofill/personal_data_manager_factory.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" -#include "ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.h" +#include "ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.h" #import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller_test.h" #include "ios/web/public/test/test_web_thread_bundle.h" @@ -48,14 +48,14 @@ autofill::PersonalDataManager* personal_data_manager = autofill::PersonalDataManagerFactory::GetForBrowserState( chrome_browser_state_.get()); - PersonalDataManagerDataChangedObserver observer(personal_data_manager); + PersonalDataManagerFinishedProfileTasksWaiter waiter(personal_data_manager); autofill::AutofillProfile autofill_profile(base::GenerateGUID(), origin); autofill_profile.SetRawInfo(autofill::NAME_FULL, base::ASCIIToUTF16(name)); autofill_profile.SetRawInfo(autofill::ADDRESS_HOME_LINE1, base::ASCIIToUTF16(address)); personal_data_manager->SaveImportedProfile(autofill_profile); - observer.Wait(); // Wait for completion of the asynchronous operation. + waiter.Wait(); // Wait for completion of the asynchronous operation. } web::TestWebThreadBundle thread_bundle_; @@ -81,8 +81,7 @@ } // Adding a single address results in an address section. -// TODO(crbug.com/919967): Reenable this test. -TEST_F(AutofillProfileTableViewControllerTest, DISABLED_TestOneProfile) { +TEST_F(AutofillProfileTableViewControllerTest, TestOneProfile) { AddProfile("https://www.example.com/", "John Doe", "1 Main Street"); CreateController(); CheckController(); @@ -94,9 +93,7 @@ } // Deleting the only profile results in item deletion and section deletion. -// TODO(crbug.com/919968): Reenable this test. -TEST_F(AutofillProfileTableViewControllerTest, - DISABLED_TestOneProfileItemDeleted) { +TEST_F(AutofillProfileTableViewControllerTest, TestOneProfileItemDeleted) { AddProfile("https://www.example.com/", "John Doe", "1 Main Street"); CreateController(); CheckController(); @@ -112,11 +109,6 @@ // Put the tableView in 'edit' mode. [view_controller editButtonPressed]; - autofill::PersonalDataManager* personal_data_manager = - autofill::PersonalDataManagerFactory::GetForBrowserState( - chrome_browser_state_.get()); - PersonalDataManagerDataChangedObserver observer(personal_data_manager); - AutofillProfileTableViewController* autofill_controller = static_cast<AutofillProfileTableViewController*>(controller()); [autofill_controller deleteItems:@[ [NSIndexPath indexPathForRow:0
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data_manager.mm b/ios/chrome/browser/ui/settings/clear_browsing_data_manager.mm index 61fb568..c9a793b 100644 --- a/ios/chrome/browser/ui/settings/clear_browsing_data_manager.mm +++ b/ios/chrome/browser/ui/settings/clear_browsing_data_manager.mm
@@ -8,7 +8,6 @@ #include "base/mac/foundation_util.h" #include "base/metrics/histogram_macros.h" #include "base/strings/sys_string_conversions.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/browsing_data/core/history_notice_utils.h" #include "components/browsing_data/core/pref_names.h" #include "components/feature_engagement/public/event_constants.h" @@ -17,6 +16,7 @@ #include "components/history/core/browser/web_history_service.h" #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" +#include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.h" @@ -274,7 +274,7 @@ toSectionWithIdentifier:SectionIdentifierGoogleAccount]; } - browser_sync::ProfileSyncService* syncService = + syncer::SyncService* syncService = ProfileSyncServiceFactory::GetForBrowserState(self.browserState); if (syncService && syncService->IsSyncFeatureActive()) { // TODO(crbug.com/650424): Footer items must currently go into a separate
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_mediator.h b/ios/chrome/browser/ui/settings/google_services_settings_mediator.h index 0cd8a98..052495e1 100644 --- a/ios/chrome/browser/ui/settings/google_services_settings_mediator.h +++ b/ios/chrome/browser/ui/settings/google_services_settings_mediator.h
@@ -18,9 +18,10 @@ class PrefService; class SyncSetupService; -namespace browser_sync { -class ProfileSyncService; -} // namespace browser_sync +namespace syncer { +class SyncService; +} // namespace syncer + namespace identity { class IdentityManager; } // namespace identity @@ -38,7 +39,7 @@ @property(nonatomic, weak) id<GoogleServicesSettingsCommandHandler> commandHandler; // Sync service. -@property(nonatomic, assign) browser_sync::ProfileSyncService* syncService; +@property(nonatomic, assign) syncer::SyncService* syncService; // Identity manager; @property(nonatomic, assign) identity::IdentityManager* identityManager;
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm b/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm index c9c0151..bdc9a79 100644 --- a/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm +++ b/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
@@ -6,9 +6,9 @@ #include "base/auto_reset.h" #include "base/mac/foundation_util.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/metrics/metrics_pref_names.h" #include "components/prefs/pref_service.h" +#include "components/sync/driver/sync_service.h" #include "components/unified_consent/pref_names.h" #include "ios/chrome/browser/pref_names.h" #import "ios/chrome/browser/signin/authentication_service.h"
diff --git a/ios/chrome/browser/ui/settings/manage_sync_settings_coordinator.h b/ios/chrome/browser/ui/settings/manage_sync_settings_coordinator.h new file mode 100644 index 0000000..3eba09a3 --- /dev/null +++ b/ios/chrome/browser/ui/settings/manage_sync_settings_coordinator.h
@@ -0,0 +1,28 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_MANAGE_SYNC_SETTINGS_COORDINATOR_H_ +#define IOS_CHROME_BROWSER_UI_SETTINGS_MANAGE_SYNC_SETTINGS_COORDINATOR_H_ + +#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" + +@class ManageSyncSettingsCoordinator; + +// Delegate for ManageSyncSettingsCoordinator. +@protocol ManageSyncSettingsCoordinatorDelegate <NSObject> + +// Called when the view controller is popped out from navigation controller. +- (void)manageSyncSettingsCoordinatorWasPopped: + (ManageSyncSettingsCoordinator*)coordinator; + +@end + +// Coordinator for the Manage Sync Settings TableView Controller. +@interface ManageSyncSettingsCoordinator : ChromeCoordinator + +@property(nonatomic, weak) id<ManageSyncSettingsCoordinatorDelegate> delegate; + +@end + +#endif // IOS_CHROME_BROWSER_UI_SETTINGS_MANAGE_SYNC_SETTINGS_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/settings/manage_sync_settings_coordinator.mm b/ios/chrome/browser/ui/settings/manage_sync_settings_coordinator.mm new file mode 100644 index 0000000..33770b97 --- /dev/null +++ b/ios/chrome/browser/ui/settings/manage_sync_settings_coordinator.mm
@@ -0,0 +1,43 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/settings/manage_sync_settings_coordinator.h" + +#include "base/logging.h" +#import "ios/chrome/browser/ui/settings/manage_sync_settings_table_view_controller.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface ManageSyncSettingsCoordinator () < + ManageSyncSettingsTableViewControllerPresentationDelegate> + +// View controller. +@property(nonatomic, strong) + ManageSyncSettingsTableViewController* viewController; + +@end + +@implementation ManageSyncSettingsCoordinator + +- (void)start { + self.viewController = [[ManageSyncSettingsTableViewController alloc] + initWithTableViewStyle:UITableViewStyleGrouped + appBarStyle:ChromeTableViewControllerStyleNoAppBar]; + self.viewController.presentationDelegate = self; + DCHECK(self.navigationController); + [self.navigationController pushViewController:self.viewController + animated:YES]; +} + +#pragma mark - ManageSyncSettingsTableViewControllerPresentationDelegate + +- (void)manageSyncSettingsViewControllerWasPopped: + (ManageSyncSettingsTableViewController*)controller { + DCHECK_EQ(self.viewController, controller); + [self.delegate manageSyncSettingsCoordinatorWasPopped:self]; +} + +@end
diff --git a/ios/chrome/browser/ui/settings/manage_sync_settings_table_view_controller.h b/ios/chrome/browser/ui/settings/manage_sync_settings_table_view_controller.h new file mode 100644 index 0000000..d8021add --- /dev/null +++ b/ios/chrome/browser/ui/settings/manage_sync_settings_table_view_controller.h
@@ -0,0 +1,33 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_MANAGE_SYNC_SETTINGS_TABLE_VIEW_CONTROLLER_H_ +#define IOS_CHROME_BROWSER_UI_SETTINGS_MANAGE_SYNC_SETTINGS_TABLE_VIEW_CONTROLLER_H_ + +#import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h" + +@class ManageSyncSettingsTableViewController; + +// Delegate for presentation events related to +// ManageSyncSettingsTableViewController. +@protocol ManageSyncSettingsTableViewControllerPresentationDelegate <NSObject> + +// Called when the view controller is removed from its parent. +- (void)manageSyncSettingsViewControllerWasPopped: + (ManageSyncSettingsTableViewController*)controller; + +@end + +// View controller to related to Manage sync settings view. +@interface ManageSyncSettingsTableViewController + : SettingsRootTableViewController + +// Presentation delegate. +@property(nonatomic, weak) + id<ManageSyncSettingsTableViewControllerPresentationDelegate> + presentationDelegate; + +@end + +#endif // IOS_CHROME_BROWSER_UI_SETTINGS_MANAGE_SYNC_SETTINGS_TABLE_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/settings/manage_sync_settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/manage_sync_settings_table_view_controller.mm new file mode 100644 index 0000000..7ee19c8a --- /dev/null +++ b/ios/chrome/browser/ui/settings/manage_sync_settings_table_view_controller.mm
@@ -0,0 +1,31 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/settings/manage_sync_settings_table_view_controller.h" + +#include "ios/chrome/grit/ios_strings.h" +#include "ui/base/l10n/l10n_util_mac.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation ManageSyncSettingsTableViewController + +#pragma mark - UIViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.tableView.accessibilityIdentifier = + @"manage_sync_settings_view_controller"; + self.title = l10n_util::GetNSString(IDS_IOS_MANAGE_SYNC_SETTINGS_TITLE); +} + +#pragma mark - SettingsControllerProtocol + +- (void)viewControllerWasPopped { + [self.presentationDelegate manageSyncSettingsViewControllerWasPopped:self]; +} + +@end
diff --git a/ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.cc b/ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.cc deleted file mode 100644 index 05253e236..0000000 --- a/ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.cc +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.h" - -#include "components/autofill/core/browser/personal_data_manager.h" - -PersonalDataManagerDataChangedObserver::PersonalDataManagerDataChangedObserver( - autofill::PersonalDataManager* personal_data_manager) - : personal_data_manager_(personal_data_manager) { - personal_data_manager_->AddObserver(this); -} - -PersonalDataManagerDataChangedObserver:: - ~PersonalDataManagerDataChangedObserver() { - personal_data_manager_->RemoveObserver(this); -} - -void PersonalDataManagerDataChangedObserver::Wait() { - // If a test is blocked in that method, it means that OnPersonalDataChanged() - // was never called which indicates a bug in either the expectation of the - // test (no asynchronous operation is executed on the PersonalDataManager - // passed in the constructor) or in the utilisation of the - // PersonalDataManagerDataChangedObserver (there is a race-condition between - // sending the asynchronous operation and the creation of the observer, it can - // be fixed by creating the observer before sending the operation). - run_loop_.Run(); -} - -void PersonalDataManagerDataChangedObserver::OnPersonalDataChanged() { - run_loop_.QuitWhenIdle(); -}
diff --git a/ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.h b/ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.h deleted file mode 100644 index 5b4ae40..0000000 --- a/ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PERSONAL_DATA_MANAGER_DATA_CHANGED_OBSERVER_H_ -#define IOS_CHROME_BROWSER_UI_SETTINGS_PERSONAL_DATA_MANAGER_DATA_CHANGED_OBSERVER_H_ - -#include "base/macros.h" -#include "base/run_loop.h" -#include "components/autofill/core/browser/personal_data_manager_observer.h" - -namespace autofill { -class PersonalDataManager; -} - -// Helper class to allow waiting until the asynchronous operation on the -// autofill::PersonalDataManager completed. Need to be used like this: -// -// autofill::PersonalDataManager* personal_data_manager = ...; -// PersonalDataManagerDataChangedObserver observer(personal_data_manager); -// personal_data_manager->...(); // Starts some asynchronous operation. -// observer.Wait(); -// -class PersonalDataManagerDataChangedObserver - : public autofill::PersonalDataManagerObserver { - public: - PersonalDataManagerDataChangedObserver( - autofill::PersonalDataManager* personal_data_manager); - ~PersonalDataManagerDataChangedObserver() override; - - // Blocks until |OnPersonalDataChanged| is invoked at the end of the - // asynchronous modification on the PersonalDataManager. - void Wait(); - - // autofill::PersonalDataManagerObserver implementation. - void OnPersonalDataChanged() override; - - private: - autofill::PersonalDataManager* personal_data_manager_; - base::RunLoop run_loop_; - - DISALLOW_COPY_AND_ASSIGN(PersonalDataManagerDataChangedObserver); -}; - -#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PERSONAL_DATA_MANAGER_DATA_CHANGED_OBSERVER_H_
diff --git a/ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.cc b/ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.cc new file mode 100644 index 0000000..9d7e8a2 --- /dev/null +++ b/ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.cc
@@ -0,0 +1,38 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.h" + +#include "components/autofill/core/browser/personal_data_manager.h" + +PersonalDataManagerFinishedProfileTasksWaiter:: + PersonalDataManagerFinishedProfileTasksWaiter( + autofill::PersonalDataManager* personal_data_manager) + : personal_data_manager_(personal_data_manager) { + personal_data_manager_->AddObserver(this); +} + +PersonalDataManagerFinishedProfileTasksWaiter:: + ~PersonalDataManagerFinishedProfileTasksWaiter() { + personal_data_manager_->RemoveObserver(this); +} + +void PersonalDataManagerFinishedProfileTasksWaiter::Wait() { + // If a test is blocked in that method, it means that OnPersonalDataChanged() + // was never called which indicates a bug in either the expectation of the + // test (no asynchronous operation is executed on the PersonalDataManager + // passed in the constructor) or in the utilisation of the + // PersonalDataManagerFinishedProfileTasksWaiter (there is a race-condition + // between sending the asynchronous operation and the creation of the + // observer, it can be fixed by creating the observer before sending the + // operation). + run_loop_.Run(); +} + +void PersonalDataManagerFinishedProfileTasksWaiter::OnPersonalDataChanged() {} + +void PersonalDataManagerFinishedProfileTasksWaiter:: + OnPersonalDataFinishedProfileTasks() { + run_loop_.QuitWhenIdle(); +}
diff --git a/ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.h b/ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.h new file mode 100644 index 0000000..186348f --- /dev/null +++ b/ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.h
@@ -0,0 +1,46 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PERSONAL_DATA_MANAGER_FINISHED_PROFILE_TASKS_WAITER_H_ +#define IOS_CHROME_BROWSER_UI_SETTINGS_PERSONAL_DATA_MANAGER_FINISHED_PROFILE_TASKS_WAITER_H_ + +#include "base/macros.h" +#include "base/run_loop.h" +#include "components/autofill/core/browser/personal_data_manager_observer.h" + +namespace autofill { +class PersonalDataManager; +} + +// Helper class to allow waiting until the asynchronous operation on the +// autofill::PersonalDataManager completed. Need to be used like this: +// +// autofill::PersonalDataManager* personal_data_manager = ...; +// PersonalDataManagerFinishedProfileTasksWaiter +// observer(personal_data_manager); personal_data_manager->...(); // Starts +// some asynchronous operation. observer.Wait(); +// +class PersonalDataManagerFinishedProfileTasksWaiter + : public autofill::PersonalDataManagerObserver { + public: + PersonalDataManagerFinishedProfileTasksWaiter( + autofill::PersonalDataManager* personal_data_manager); + ~PersonalDataManagerFinishedProfileTasksWaiter() override; + + // Blocks until |OnPersonalDataFinishedProfileTasks| is invoked at the end of + // the asynchronous modification on the PersonalDataManager. + void Wait(); + + // autofill::PersonalDataManagerObserver implementation. + void OnPersonalDataChanged() override; + void OnPersonalDataFinishedProfileTasks() override; + + private: + autofill::PersonalDataManager* personal_data_manager_; + base::RunLoop run_loop_; + + DISALLOW_COPY_AND_ASSIGN(PersonalDataManagerFinishedProfileTasksWaiter); +}; + +#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PERSONAL_DATA_MANAGER_FINISHED_PROFILE_TASKS_WAITER_H_
diff --git a/ios/chrome/browser/ui/settings/reauthentication_module.mm b/ios/chrome/browser/ui/settings/reauthentication_module.mm index 07e34e8..a342f83 100644 --- a/ios/chrome/browser/ui/settings/reauthentication_module.mm +++ b/ios/chrome/browser/ui/settings/reauthentication_module.mm
@@ -5,7 +5,7 @@ #import <LocalAuthentication/LocalAuthentication.h> -#import "base/logging.h" +#include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "components/password_manager/core/browser/password_manager_metrics_util.h"
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.h b/ios/chrome/browser/ui/settings/settings_navigation_controller.h index 46923da..15a9994 100644 --- a/ios/chrome/browser/ui/settings/settings_navigation_controller.h +++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.h
@@ -24,6 +24,10 @@ // Notifies the controller that the settings screen is being dismissed. - (void)settingsWillBeDismissed; +// Notifies the controller that is popped out from the settings navigation +// controller. +- (void)viewControllerWasPopped; + @end @protocol SettingsNavigationControllerDelegate<NSObject>
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm index 47bd7b2..42fa8f96 100644 --- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -295,6 +295,16 @@ } } +- (UIViewController*)popViewControllerAnimated:(BOOL)animated { + UIViewController* poppedViewController = + [super popViewControllerAnimated:animated]; + if ([poppedViewController + respondsToSelector:@selector(viewControllerWasPopped)]) { + [poppedViewController performSelector:@selector(viewControllerWasPopped)]; + } + return poppedViewController; +} + #pragma mark - Private // Creates an autoreleased "X" button that closes the settings when tapped.
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm index 5d4a3718d..b5c435e 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -10,7 +10,6 @@ #import "base/mac/foundation_util.h" #include "base/strings/sys_string_conversions.h" #include "components/autofill/core/common/autofill_prefs.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/core/service_access_type.h" #include "components/password_manager/core/browser/password_store.h" #include "components/password_manager/core/common/password_manager_pref_names.h" @@ -19,6 +18,7 @@ #include "components/search_engines/util.h" #include "components/signin/core/browser/signin_metrics.h" #include "components/strings/grit/components_strings.h" +#include "components/sync/driver/sync_service.h" #include "components/unified_consent/feature.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
diff --git a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_table_view_controller.mm b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_table_view_controller.mm index 5de08d62..d0cc1d8c 100644 --- a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_table_view_controller.mm
@@ -9,9 +9,9 @@ #include "base/i18n/time_formatting.h" #include "base/mac/foundation_util.h" #include "base/strings/sys_string_conversions.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/google/core/common/google_util.h" #include "components/strings/grit/components_strings.h" +#include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_user_settings.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" @@ -80,7 +80,7 @@ AuthenticationServiceFactory::GetForBrowserState(browserState_) ->GetAuthenticatedUserEmail(); DCHECK(userEmail); - browser_sync::ProfileSyncService* service = + syncer::SyncService* service = ProfileSyncServiceFactory::GetForBrowserState(browserState_); if (service->IsEngineInitialized() && service->IsUsingSecondaryPassphrase()) { @@ -271,7 +271,7 @@ // Clear out the error message. self.syncErrorMessage = nil; - browser_sync::ProfileSyncService* service = + syncer::SyncService* service = ProfileSyncServiceFactory::GetForBrowserState(browserState_); DCHECK(service); // It is possible for a race condition to happen where a user is allowed @@ -451,7 +451,7 @@ #pragma mark - SyncObserverModelBridge - (void)onSyncStateChanged { - browser_sync::ProfileSyncService* service = + syncer::SyncService* service = ProfileSyncServiceFactory::GetForBrowserState(browserState_); if (!service->IsEngineInitialized()) {
diff --git a/ios/chrome/browser/ui/settings/sync_encryption_table_view_controller.mm b/ios/chrome/browser/ui/settings/sync_encryption_table_view_controller.mm index 76db309..3c57eb9 100644 --- a/ios/chrome/browser/ui/settings/sync_encryption_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/sync_encryption_table_view_controller.mm
@@ -12,6 +12,7 @@ #include "components/google/core/common/google_util.h" #include "components/strings/grit/components_strings.h" #include "components/sync/base/sync_prefs.h" +#include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/chrome_url_constants.h" @@ -63,7 +64,7 @@ if (self) { self.title = l10n_util::GetNSString(IDS_IOS_SYNC_ENCRYPTION_TITLE); _browserState = browserState; - browser_sync::ProfileSyncService* syncService = + syncer::SyncService* syncService = ProfileSyncServiceFactory::GetForBrowserState(_browserState); _isUsingSecondaryPassphrase = syncService->IsEngineInitialized() && syncService->IsUsingSecondaryPassphrase(); @@ -175,7 +176,7 @@ switch (item.type) { case ItemTypePassphrase: { DCHECK(browser_sync::ProfileSyncService::IsSyncAllowedByFlag()); - browser_sync::ProfileSyncService* service = + syncer::SyncService* service = ProfileSyncServiceFactory::GetForBrowserState(_browserState); if (service->IsEngineInitialized() && !service->IsUsingSecondaryPassphrase()) { @@ -202,7 +203,7 @@ #pragma mark SyncObserverModelBridge - (void)onSyncStateChanged { - browser_sync::ProfileSyncService* service = + syncer::SyncService* service = ProfileSyncServiceFactory::GetForBrowserState(_browserState); BOOL isNowUsingSecondaryPassphrase = service->IsEngineInitialized() && service->IsUsingSecondaryPassphrase();
diff --git a/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.mm index 3e31f767..24c92445 100644 --- a/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.mm
@@ -9,11 +9,11 @@ #include "base/auto_reset.h" #include "base/mac/foundation_util.h" #include "components/autofill/core/common/autofill_prefs.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/google/core/common/google_util.h" #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" #include "components/sync/base/model_type.h" +#include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/chrome_url_constants.h" @@ -219,7 +219,7 @@ _syncSetupService = SyncSetupServiceFactory::GetForBrowserState(_browserState); self.title = l10n_util::GetNSString(IDS_IOS_SYNC_SETTING_TITLE); - browser_sync::ProfileSyncService* syncService = + syncer::SyncService* syncService = ProfileSyncServiceFactory::GetForBrowserState(_browserState); _syncObserver.reset(new SyncObserverBridge(self, syncService)); _identityManagerObserver.reset(new identity::IdentityManagerObserverBridge( @@ -753,7 +753,7 @@ } - (void)showEncryption { - browser_sync::ProfileSyncService* syncService = + syncer::SyncService* syncService = ProfileSyncServiceFactory::GetForBrowserState(_browserState); if (!syncService->IsEngineInitialized() || !_syncSetupService->IsSyncEnabled() || @@ -978,7 +978,7 @@ } - (BOOL)shouldEncryptionItemBeEnabled { - browser_sync::ProfileSyncService* syncService = + syncer::SyncService* syncService = ProfileSyncServiceFactory::GetForBrowserState(_browserState); return (syncService->IsEngineInitialized() && _syncSetupService->IsSyncEnabled() &&
diff --git a/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller_unittest.mm index 5fae263..179ba70 100644 --- a/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller_unittest.mm
@@ -52,7 +52,7 @@ class SyncSetupServiceMockThatFails : public SyncSetupServiceMock { public: - SyncSetupServiceMockThatFails(browser_sync::ProfileSyncService* sync_service) + SyncSetupServiceMockThatFails(syncer::SyncService* sync_service) : SyncSetupServiceMock(sync_service) {} bool IsSyncEnabled() const override { return sync_enabled_; } void SetSyncEnabled(bool sync_enabled) override {} @@ -76,8 +76,7 @@ class SyncSetupServiceMockThatSucceeds : public SyncSetupServiceMockThatFails { public: - SyncSetupServiceMockThatSucceeds( - browser_sync::ProfileSyncService* sync_service) + SyncSetupServiceMockThatSucceeds(syncer::SyncService* sync_service) : SyncSetupServiceMockThatFails(sync_service) {} void SetSyncEnabled(bool sync_enabled) override { sync_enabled_ = sync_enabled; @@ -95,7 +94,7 @@ web::BrowserState* context) { ios::ChromeBrowserState* chrome_browser_state = ios::ChromeBrowserState::FromBrowserState(context); - browser_sync::ProfileSyncService* sync_service = + syncer::SyncService* sync_service = ProfileSyncServiceFactory::GetForBrowserState(chrome_browser_state); return std::make_unique<NiceMock<SyncSetupServiceMock>>(sync_service); } @@ -104,7 +103,7 @@ web::BrowserState* context) { ios::ChromeBrowserState* chrome_browser_state = ios::ChromeBrowserState::FromBrowserState(context); - browser_sync::ProfileSyncService* sync_service = + syncer::SyncService* sync_service = ProfileSyncServiceFactory::GetForBrowserState(chrome_browser_state); return std::make_unique<NiceMock<SyncSetupServiceMockThatSucceeds>>( sync_service); @@ -114,7 +113,7 @@ web::BrowserState* context) { ios::ChromeBrowserState* chrome_browser_state = ios::ChromeBrowserState::FromBrowserState(context); - browser_sync::ProfileSyncService* sync_service = + syncer::SyncService* sync_service = ProfileSyncServiceFactory::GetForBrowserState(chrome_browser_state); return std::make_unique<NiceMock<SyncSetupServiceMockThatFails>>( sync_service);
diff --git a/ios/chrome/browser/ui/settings/sync_utils/sync_error_infobar_delegate.mm b/ios/chrome/browser/ui/settings/sync_utils/sync_error_infobar_delegate.mm index cf983be6..c9f5dbb 100644 --- a/ios/chrome/browser/ui/settings/sync_utils/sync_error_infobar_delegate.mm +++ b/ios/chrome/browser/ui/settings/sync_utils/sync_error_infobar_delegate.mm
@@ -11,7 +11,6 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/strings/sys_string_conversions.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/infobars/core/infobar.h" #include "components/infobars/core/infobar_delegate.h" #include "components/infobars/core/infobar_manager.h"
diff --git a/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm b/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm index 757fb4c3..ca049ad8 100644 --- a/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm +++ b/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm
@@ -9,14 +9,12 @@ #import "base/test/ios/wait_util.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/bookmarks/browser/titled_url_match.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/strings/grit/components_strings.h" #include "components/sync/base/model_type.h" #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #include "ios/chrome/browser/bookmarks/bookmarks_utils.h" #include "ios/chrome/browser/signin/authentication_service.h" #include "ios/chrome/browser/signin/authentication_service_factory.h" -#include "ios/chrome/browser/sync/profile_sync_service_factory.h" #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view.h" #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h" #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm b/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm index f6a2a63..5c914f7 100644 --- a/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm +++ b/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/tab_grid/grid/grid_cell.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/chrome/browser/ui/tab_grid/grid/grid_constants.h" #import "ios/chrome/browser/ui/tab_grid/grid/top_aligned_image_view.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_item.mm b/ios/chrome/browser/ui/tab_grid/grid/grid_item.mm index 0e985216..57c89245 100644 --- a/ios/chrome/browser/ui/tab_grid/grid/grid_item.mm +++ b/ios/chrome/browser/ui/tab_grid/grid/grid_item.mm
@@ -8,7 +8,7 @@ #error "This file requires ARC support." #endif -#import "base/logging.h" +#include "base/logging.h" @implementation GridItem
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm index 13b8cdd..02c52dfd 100644 --- a/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm +++ b/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm
@@ -5,7 +5,7 @@ #import "ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.h" #include "base/ios/block_types.h" -#import "base/logging.h" +#include "base/logging.h" #import "base/mac/foundation_util.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h"
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm index c6eed640..49620d3 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/chrome/browser/tabs/tab_model.h" #import "ios/chrome/browser/ui/main/view_controller_swapping.h" #import "ios/chrome/browser/ui/tab_grid/tab_grid_paging.h"
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm index 9b3f207..fc5cdf0a 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm
@@ -31,7 +31,7 @@ #import "ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler.h" #import "ios/chrome/browser/web_state_list/web_usage_enabler/web_state_list_web_usage_enabler_factory.h" #import "ios/web/public/navigation_manager.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #import "ios/web/public/web_state/web_state_observer_bridge.h" #include "ui/gfx/image/image.h"
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_url_loader.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_url_loader.mm index aa65f91..49330f5 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_url_loader.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_url_loader.mm
@@ -10,7 +10,7 @@ #include "ios/chrome/browser/ui/commands/open_new_tab_command.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #include "ios/chrome/browser/web_state_list/web_state_opener.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm index ceb48ee..05ecfe2 100644 --- a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm +++ b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/chrome/browser/ui/tab_grid/transitions/grid_to_tab_transition_view.h" #import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h" #import "ios/chrome/browser/ui/util/property_animator_group.h"
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm index e39e1e0..6571c43 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_item.mm index 00a8b27..9ac5a8e0 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_item.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/table_view/cells/table_view_item.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_view_controller.mm index 9770b35..c641c68 100644 --- a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_view_controller.mm +++ b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_view_controller.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/toolbar/adaptive_toolbar_view_controller.h" -#import "base/logging.h" +#include "base/logging.h" #include "base/metrics/user_metrics.h" #import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/popup_menu/public/popup_menu_long_press_delegate.h"
diff --git a/ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.mm b/ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.mm index 3a96fe8..17b6a4a0 100644 --- a/ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.mm +++ b/ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h" #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h" #include "ios/chrome/browser/ui/util/ui_util.h"
diff --git a/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm index 40e150d9..87b6696 100644 --- a/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm +++ b/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/chrome/browser/ui/UIView+SizeClassSupport.h" #import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm b/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm index 6928c960..d8774e0 100644 --- a/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm +++ b/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm
@@ -20,7 +20,7 @@ #import "ios/public/provider/chrome/browser/voice/voice_search_provider.h" #import "ios/web/public/navigation_manager.h" #import "ios/web/public/web_client.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #import "ios/web/public/web_state/web_state_observer_bridge.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.mm b/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.mm index 91efa9d..c279308 100644 --- a/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.mm +++ b/ios/chrome/browser/ui/toolbar_container/toolbar_height_range.mm
@@ -6,7 +6,7 @@ #include <algorithm> -#import "base/logging.h" +#include "base/logging.h" #include "ios/chrome/browser/ui/util/ui_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/translate/language_selection_coordinator.mm b/ios/chrome/browser/ui/translate/language_selection_coordinator.mm index 64d7e88..8b413b0 100644 --- a/ios/chrome/browser/ui/translate/language_selection_coordinator.mm +++ b/ios/chrome/browser/ui/translate/language_selection_coordinator.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/translate/language_selection_coordinator.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/chrome/browser/translate/language_selection_delegate.h" #import "ios/chrome/browser/translate/language_selection_handler.h" #import "ios/chrome/browser/ui/presenters/contained_presenter.h"
diff --git a/ios/chrome/browser/ui/translate/language_selection_view_controller.mm b/ios/chrome/browser/ui/translate/language_selection_view_controller.mm index 601dd00..c8d8459 100644 --- a/ios/chrome/browser/ui/translate/language_selection_view_controller.mm +++ b/ios/chrome/browser/ui/translate/language_selection_view_controller.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/translate/language_selection_view_controller.h" -#import "base/logging.h" +#include "base/logging.h" #import "base/mac/foundation_util.h" #import "ios/chrome/browser/ui/translate/language_selection_provider.h"
diff --git a/ios/chrome/browser/ui/util/property_animator_group.mm b/ios/chrome/browser/ui/util/property_animator_group.mm index ad27476..640e9fd6 100644 --- a/ios/chrome/browser/ui/util/property_animator_group.mm +++ b/ios/chrome/browser/ui/util/property_animator_group.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/util/property_animator_group.h" -#import "base/logging.h" +#include "base/logging.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/util/transparent_link_button.mm b/ios/chrome/browser/ui/util/transparent_link_button.mm index dbca033..b4d2901 100644 --- a/ios/chrome/browser/ui/util/transparent_link_button.mm +++ b/ios/chrome/browser/ui/util/transparent_link_button.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/util/transparent_link_button.h" -#import "base/logging.h" +#include "base/logging.h" #import "base/strings/sys_string_conversions.h" #include "url/gurl.h"
diff --git a/ios/chrome/browser/ui/webui/inspect/inspect_ui.mm b/ios/chrome/browser/ui/webui/inspect/inspect_ui.mm index 466958f..0c585d6 100644 --- a/ios/chrome/browser/ui/webui/inspect/inspect_ui.mm +++ b/ios/chrome/browser/ui/webui/inspect/inspect_ui.mm
@@ -20,6 +20,7 @@ #include "ios/chrome/grit/ios_resources.h" #include "ios/chrome/grit/ios_strings.h" #include "ios/web/public/web_state/web_frame.h" +#include "ios/web/public/web_state/web_frame_util.h" #import "ios/web/public/web_state/web_frames_manager.h" #import "ios/web/public/web_state/web_state.h" #include "ios/web/public/web_ui_ios_data_source.h" @@ -97,6 +98,10 @@ web::WebState* web_state, int index, bool activating) override; + void WillCloseWebStateAt(WebStateList* web_state_list, + web::WebState* web_state, + int index, + bool user_action) override; private: // Handles the message from JavaScript to enable or disable console logging. @@ -181,19 +186,15 @@ web::WebFrame* sender_frame, const JavaScriptConsoleMessage& message) { std::vector<base::Value> params; - web::WebFrame* main_web_frame = - web::WebFramesManager::FromWebState(web_state)->GetMainWebFrame(); + web::WebFrame* main_web_frame = web::GetMainWebFrame(web_state); params.push_back(base::Value(main_web_frame->GetFrameId())); params.push_back(base::Value(sender_frame->GetFrameId())); params.push_back(base::Value(message.url.spec())); params.push_back(base::Value(message.level)); params.push_back(message.message->Clone()); - web::WebFrame* inspect_ui_web_frame = - web::WebFramesManager::FromWebState(web_ui()->GetWebState()) - ->GetMainWebFrame(); - inspect_ui_web_frame->CallJavaScriptFunction( - "inspectWebUI.logMessageReceived", params); + web::GetMainWebFrame(web_ui()->GetWebState()) + ->CallJavaScriptFunction("inspectWebUI.logMessageReceived", params); } void InspectDOMHandler::SetDelegateForWebStatesInTabModel( @@ -228,6 +229,17 @@ JavaScriptConsoleTabHelper::FromWebState(web_state)->SetDelegate(this); } +void InspectDOMHandler::WillCloseWebStateAt(WebStateList* web_state_list, + web::WebState* web_state, + int index, + bool user_action) { + std::vector<base::Value> params; + params.push_back(base::Value(web::GetMainWebFrameId(web_state))); + + web::GetMainWebFrame(web_ui()->GetWebState()) + ->CallJavaScriptFunction("inspectWebUI.tabClosed", params); +} + } // namespace InspectUI::InspectUI(web::WebUIIOS* web_ui) : web::WebUIIOSController(web_ui) {
diff --git a/ios/chrome/browser/ui/webui/inspect/inspect_ui_egtest.mm b/ios/chrome/browser/ui/webui/inspect/inspect_ui_egtest.mm index 5cc78f3..1f91b39 100644 --- a/ios/chrome/browser/ui/webui/inspect/inspect_ui_egtest.mm +++ b/ios/chrome/browser/ui/webui/inspect/inspect_ui_egtest.mm
@@ -8,6 +8,7 @@ #import "base/strings/sys_string_conversions.h" #include "ios/chrome/browser/chrome_url_constants.h" #import "ios/chrome/test/app/chrome_test_util.h" +#import "ios/chrome/test/app/tab_test_util.h" #import "ios/chrome/test/app/web_view_interaction_test_util.h" #import "ios/chrome/test/earl_grey/chrome_actions.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" @@ -150,7 +151,7 @@ [ChromeEarlGrey tapWebViewElementWithID:kLogMessageButtonId]; [ChromeEarlGrey tapWebViewElementWithID:kWarningMessageButtonId]; - [ChromeEarlGrey closeCurrentTab]; + chrome_test_util::SelectTabAtIndexInCurrentMode(0); // Validate messages and labels are displayed. [ChromeEarlGrey waitForWebViewContainingText:kDebugMessageLabel]; [ChromeEarlGrey waitForWebViewContainingText:kDebugMessageText]; @@ -202,7 +203,7 @@ GREYAssertTrue(TapWebViewElementWithIdInIframe(warnButtonID), @"Failed to tap warn button."); - [ChromeEarlGrey closeCurrentTab]; + chrome_test_util::SelectTabAtIndexInCurrentMode(0); // Validate messages and labels are displayed. [ChromeEarlGrey waitForWebViewContainingText:kDebugMessageLabel]; [ChromeEarlGrey waitForWebViewContainingText:kIFrameDebugMessageText]; @@ -235,7 +236,7 @@ // Log a message and verify it is displayed. [ChromeEarlGrey tapWebViewElementWithID:kDebugMessageButtonId]; - [ChromeEarlGrey closeCurrentTab]; + chrome_test_util::SelectTabAtIndexInCurrentMode(0); [ChromeEarlGrey waitForWebViewContainingText:kDebugMessageLabel]; [ChromeEarlGrey waitForWebViewContainingText:kDebugMessageText]; @@ -248,7 +249,7 @@ // Log another message and verify it is displayed. [ChromeEarlGrey tapWebViewElementWithID:kLogMessageButtonId]; - [ChromeEarlGrey closeCurrentTab]; + chrome_test_util::SelectTabAtIndexInCurrentMode(0); [ChromeEarlGrey waitForWebViewContainingText:kLogMessageLabel]; [ChromeEarlGrey waitForWebViewContainingText:kLogMessageText]; @@ -276,7 +277,7 @@ // Log a message and verify it is displayed. [ChromeEarlGrey tapWebViewElementWithID:kDebugMessageButtonId]; - [ChromeEarlGrey closeCurrentTab]; + chrome_test_util::SelectTabAtIndexInCurrentMode(0); [ChromeEarlGrey waitForWebViewContainingText:kDebugMessageLabel]; [ChromeEarlGrey waitForWebViewContainingText:kDebugMessageText]; @@ -306,7 +307,7 @@ // Log a message and verify it is displayed. [ChromeEarlGrey tapWebViewElementWithID:kDebugMessageButtonId]; - [ChromeEarlGrey closeCurrentTab]; + chrome_test_util::SelectTabAtIndexInCurrentMode(0); [ChromeEarlGrey waitForWebViewContainingText:kDebugMessageLabel]; [ChromeEarlGrey waitForWebViewContainingText:kDebugMessageText]; @@ -317,4 +318,29 @@ [ChromeEarlGrey waitForWebViewNotContainingText:kDebugMessageText]; } +// Tests that messages are cleared for a tab which is closed. +- (void)testMessagesClearedOnTabClosure { + [ChromeEarlGrey loadURL:GURL(kChromeUIInspectURL)]; + + // Start logging. + [ChromeEarlGrey waitForWebViewContainingElement:StartLoggingButton()]; + [ChromeEarlGrey tapWebViewElementWithID:kStartLoggingButtonId]; + + // Open console test page. + [ChromeEarlGrey openNewTab]; + const GURL consoleTestsURL = self.testServer->GetURL(kConsolePage); + [ChromeEarlGrey loadURL:consoleTestsURL]; + std::string debugButtonID = base::SysNSStringToUTF8(kDebugMessageButtonId); + [ChromeEarlGrey + waitForWebViewContainingElement:ElementSelector::ElementSelectorId( + debugButtonID)]; + + [ChromeEarlGrey tapWebViewElementWithID:kDebugMessageButtonId]; + [ChromeEarlGrey closeCurrentTab]; + + // Validate message and label are not displayed. + [ChromeEarlGrey waitForWebViewNotContainingText:kDebugMessageLabel]; + [ChromeEarlGrey waitForWebViewNotContainingText:kDebugMessageText]; +} + @end
diff --git a/ios/chrome/browser/ui/webui/password_manager_internals_ui_ios.mm b/ios/chrome/browser/ui/webui/password_manager_internals_ui_ios.mm index e1e4d82..ab9e25f 100644 --- a/ios/chrome/browser/ui/webui/password_manager_internals_ui_ios.mm +++ b/ios/chrome/browser/ui/webui/password_manager_internals_ui_ios.mm
@@ -10,7 +10,7 @@ #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/chrome_url_constants.h" #include "ios/chrome/browser/passwords/password_manager_internals_service_factory.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ios/web/public/web_ui_ios_data_source.h" #include "ios/web/public/webui/web_ui_ios.h" #include "net/base/escape.h"
diff --git a/ios/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.cc b/ios/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.cc index f38cc68..3dd91de 100644 --- a/ios/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.cc +++ b/ios/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.cc
@@ -10,11 +10,11 @@ #include "base/command_line.h" #include "base/logging.h" #include "base/values.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/sync/base/weak_handle.h" #include "components/sync/driver/about_sync_util.h" #include "components/sync/driver/sync_driver_switches.h" #include "components/sync/driver/sync_service.h" +#include "components/sync/driver/sync_user_settings.h" #include "components/sync/engine/cycle/commit_counters.h" #include "components/sync/engine/cycle/status_counters.h" #include "components/sync/engine/cycle/update_counters.h"
diff --git a/ios/chrome/browser/unified_consent/unified_consent_service_factory.cc b/ios/chrome/browser/unified_consent/unified_consent_service_factory.cc index 94b70ed..26aa859 100644 --- a/ios/chrome/browser/unified_consent/unified_consent_service_factory.cc +++ b/ios/chrome/browser/unified_consent/unified_consent_service_factory.cc
@@ -4,7 +4,6 @@ #include "ios/chrome/browser/unified_consent/unified_consent_service_factory.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" #include "components/sync/driver/sync_service.h" #include "components/unified_consent/feature.h"
diff --git a/ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.cc b/ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.cc index 45616c3..22f88c4 100644 --- a/ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.cc +++ b/ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.cc
@@ -4,19 +4,12 @@ #include "ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.h" -#include "base/lazy_instance.h" +#include "base/no_destructor.h" #include "base/strings/stringprintf.h" #include "components/version_info/version_info.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/common/channel_info.h" -namespace { - -base::LazyInstance<IOSChromeUpdateQueryParamsDelegate>::DestructorAtExit - g_delegate = LAZY_INSTANCE_INITIALIZER; - -} // namespace - IOSChromeUpdateQueryParamsDelegate::IOSChromeUpdateQueryParamsDelegate() {} IOSChromeUpdateQueryParamsDelegate::~IOSChromeUpdateQueryParamsDelegate() {} @@ -24,7 +17,8 @@ // static IOSChromeUpdateQueryParamsDelegate* IOSChromeUpdateQueryParamsDelegate::GetInstance() { - return g_delegate.Pointer(); + static base::NoDestructor<IOSChromeUpdateQueryParamsDelegate> instance; + return instance.get(); } std::string IOSChromeUpdateQueryParamsDelegate::GetExtraParams() {
diff --git a/ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.h b/ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.h index 00a9e06..592e738 100644 --- a/ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.h +++ b/ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.h
@@ -16,7 +16,7 @@ IOSChromeUpdateQueryParamsDelegate(); ~IOSChromeUpdateQueryParamsDelegate() override; - // Gets the LazyInstance for IOSChromeUpdateQueryParamsDelegate. + // Gets the instance for IOSChromeUpdateQueryParamsDelegate. static IOSChromeUpdateQueryParamsDelegate* GetInstance(); // update_client::UpdateQueryParamsDelegate:
diff --git a/ios/chrome/browser/voice/text_to_speech_listener.mm b/ios/chrome/browser/voice/text_to_speech_listener.mm index 73a6050..00f64e1 100644 --- a/ios/chrome/browser/voice/text_to_speech_listener.mm +++ b/ios/chrome/browser/voice/text_to_speech_listener.mm
@@ -10,7 +10,7 @@ #import "ios/chrome/browser/voice/text_to_speech_parser.h" #import "ios/chrome/browser/voice/voice_search_url_rewriter.h" #include "ios/web/public/navigation_manager.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ios/web/public/web_state/web_state_observer.h" #import "ios/web/public/web_state/web_state_observer_bridge.h" #include "url/gurl.h"
diff --git a/ios/chrome/browser/voice/text_to_speech_parser.mm b/ios/chrome/browser/voice/text_to_speech_parser.mm index 280a4c5c..c61c4263 100644 --- a/ios/chrome/browser/voice/text_to_speech_parser.mm +++ b/ios/chrome/browser/voice/text_to_speech_parser.mm
@@ -6,7 +6,7 @@ #include "base/logging.h" #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #import "third_party/google_toolbox_for_mac/src/Foundation/GTMStringEncoding.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/web/sad_tab_tab_helper.mm b/ios/chrome/browser/web/sad_tab_tab_helper.mm index f35c0b1c..aefbb21c 100644 --- a/ios/chrome/browser/web/sad_tab_tab_helper.mm +++ b/ios/chrome/browser/web/sad_tab_tab_helper.mm
@@ -20,7 +20,7 @@ #import "ios/chrome/browser/web/sad_tab_tab_helper_delegate.h" #import "ios/web/public/navigation_manager.h" #include "ios/web/public/web_state/navigation_context.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/web_state_list/active_web_state_observation_forwarder.mm b/ios/chrome/browser/web_state_list/active_web_state_observation_forwarder.mm index 9d5e922c..1593301 100644 --- a/ios/chrome/browser/web_state_list/active_web_state_observation_forwarder.mm +++ b/ios/chrome/browser/web_state_list/active_web_state_observation_forwarder.mm
@@ -6,7 +6,7 @@ #include "base/logging.h" #include "ios/chrome/browser/web_state_list/web_state_list.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/web_state_list/active_web_state_observation_forwarder_unittest.mm b/ios/chrome/browser/web_state_list/active_web_state_observation_forwarder_unittest.mm index e13b918..cce3f67 100644 --- a/ios/chrome/browser/web_state_list/active_web_state_observation_forwarder_unittest.mm +++ b/ios/chrome/browser/web_state_list/active_web_state_observation_forwarder_unittest.mm
@@ -12,7 +12,7 @@ #include "ios/chrome/browser/web_state_list/web_state_list_delegate.h" #include "ios/chrome/browser/web_state_list/web_state_opener.h" #include "ios/web/public/test/fakes/test_web_state.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ios/web/public/web_state/web_state_observer.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest_mac.h"
diff --git a/ios/chrome/browser/web_state_list/all_web_state_observation_forwarder.mm b/ios/chrome/browser/web_state_list/all_web_state_observation_forwarder.mm index 4ef8662..bcfb7301 100644 --- a/ios/chrome/browser/web_state_list/all_web_state_observation_forwarder.mm +++ b/ios/chrome/browser/web_state_list/all_web_state_observation_forwarder.mm
@@ -6,7 +6,7 @@ #include "base/logging.h" #include "ios/chrome/browser/web_state_list/web_state_list.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/web_state_list/all_web_state_observation_forwarder_unittest.mm b/ios/chrome/browser/web_state_list/all_web_state_observation_forwarder_unittest.mm index 77ff4bb..50c5f18 100644 --- a/ios/chrome/browser/web_state_list/all_web_state_observation_forwarder_unittest.mm +++ b/ios/chrome/browser/web_state_list/all_web_state_observation_forwarder_unittest.mm
@@ -12,7 +12,7 @@ #include "ios/chrome/browser/web_state_list/web_state_list_delegate.h" #include "ios/chrome/browser/web_state_list/web_state_opener.h" #include "ios/web/public/test/fakes/test_web_state.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ios/web/public/web_state/web_state_observer.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest_mac.h"
diff --git a/ios/chrome/test/app/sync_test_util.mm b/ios/chrome/test/app/sync_test_util.mm index 0d1a424..1a62477 100644 --- a/ios/chrome/test/app/sync_test_util.mm +++ b/ios/chrome/test/app/sync_test_util.mm
@@ -18,6 +18,7 @@ #include "components/history/core/browser/history_service.h" #include "components/keyed_service/core/service_access_type.h" #include "components/sync/device_info/local_device_info_provider.h" +#include "components/sync/driver/sync_service.h" #include "components/sync/engine/net/http_bridge_network_resources.h" #include "components/sync/test/fake_server/entity_builder_factory.h" #include "components/sync/test/fake_server/fake_server.h" @@ -51,7 +52,8 @@ chrome_test_util::GetOriginalBrowserState(); DCHECK(browser_state); browser_sync::ProfileSyncService* service = - ProfileSyncServiceFactory::GetForBrowserState(browser_state); + ProfileSyncServiceFactory::GetAsProfileSyncServiceForBrowserState( + browser_state); service->OverrideNetworkResourcesForTest(std::move(resources)); } @@ -96,9 +98,9 @@ void TriggerSyncCycle(syncer::ModelType type) { ios::ChromeBrowserState* browser_state = chrome_test_util::GetOriginalBrowserState(); - browser_sync::ProfileSyncService* profile_sync_service = + syncer::SyncService* sync_service = ProfileSyncServiceFactory::GetForBrowserState(browser_state); - profile_sync_service->TriggerRefresh({type}); + sync_service->TriggerRefresh({type}); } void ClearSyncServerData() { @@ -160,10 +162,11 @@ DCHECK(IsSyncInitialized()); ios::ChromeBrowserState* browser_state = chrome_test_util::GetOriginalBrowserState(); - browser_sync::ProfileSyncService* profile_sync_service = - ProfileSyncServiceFactory::GetForBrowserState(browser_state); + browser_sync::ProfileSyncService* sync_service = + ProfileSyncServiceFactory::GetAsProfileSyncServiceForBrowserState( + browser_state); const syncer::LocalDeviceInfoProvider* info_provider = - profile_sync_service->GetLocalDeviceInfoProvider(); + sync_service->GetLocalDeviceInfoProvider(); return info_provider->GetLocalSyncCacheGUID(); }
diff --git a/ios/showcase/common/protocol_alerter.mm b/ios/showcase/common/protocol_alerter.mm index bb61e43..7ce8e49 100644 --- a/ios/showcase/common/protocol_alerter.mm +++ b/ios/showcase/common/protocol_alerter.mm
@@ -6,7 +6,7 @@ #import <objc/runtime.h> -#import "base/logging.h" +#include "base/logging.h" #import "base/strings/sys_string_conversions.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/showcase/core/showcase_view_controller.mm b/ios/showcase/core/showcase_view_controller.mm index 14cce0022..0c657d7 100644 --- a/ios/showcase/core/showcase_view_controller.mm +++ b/ios/showcase/core/showcase_view_controller.mm
@@ -4,7 +4,7 @@ #import "ios/showcase/core/showcase_view_controller.h" -#import "base/logging.h" +#include "base/logging.h" #import "ios/showcase/common/coordinator.h" #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/showcase/test/showcase_test_case.mm b/ios/showcase/test/showcase_test_case.mm index ca4bfa9..f82edfe 100644 --- a/ios/showcase/test/showcase_test_case.mm +++ b/ios/showcase/test/showcase_test_case.mm
@@ -6,7 +6,7 @@ #import <EarlGrey/EarlGrey.h> -#import "base/logging.h" +#include "base/logging.h" #import "base/mac/foundation_util.h" #import "ios/showcase/core/app_delegate.h" #include "testing/coverage_util_ios.h"
diff --git a/ios/web/navigation/legacy_navigation_manager_impl.h b/ios/web/navigation/legacy_navigation_manager_impl.h index 79d28f64..66c4ba2 100644 --- a/ios/web/navigation/legacy_navigation_manager_impl.h +++ b/ios/web/navigation/legacy_navigation_manager_impl.h
@@ -36,6 +36,7 @@ void SetSessionController(CRWSessionController* session_controller) override; void InitializeSession() override; void OnNavigationItemsPruned(size_t pruned_item_count) override; + void OnRendererInitiatedNavigationStarted(const GURL& url) override; void OnNavigationItemCommitted() override; CRWSessionController* GetSessionController() const override; void AddTransientItem(const GURL& url) override;
diff --git a/ios/web/navigation/legacy_navigation_manager_impl.mm b/ios/web/navigation/legacy_navigation_manager_impl.mm index 58b350a..42b3bcf8 100644 --- a/ios/web/navigation/legacy_navigation_manager_impl.mm +++ b/ios/web/navigation/legacy_navigation_manager_impl.mm
@@ -59,6 +59,9 @@ delegate_->OnNavigationItemCommitted(item); } +void LegacyNavigationManagerImpl::OnRendererInitiatedNavigationStarted( + const GURL& url) {} + CRWSessionController* LegacyNavigationManagerImpl::GetSessionController() const { return session_controller_;
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h index 09125cb..d39b230 100644 --- a/ios/web/navigation/navigation_manager_impl.h +++ b/ios/web/navigation/navigation_manager_impl.h
@@ -94,6 +94,9 @@ virtual void OnNavigationItemsPruned(size_t pruned_item_count) = 0; virtual void OnNavigationItemCommitted() = 0; + // Called when renderer-initiated navigation has started. + virtual void OnRendererInitiatedNavigationStarted(const GURL& url) = 0; + // Prepares for the deletion of WKWebView such as caching necessary data. virtual void DetachFromWebView();
diff --git a/ios/web/navigation/navigation_manager_impl.mm b/ios/web/navigation/navigation_manager_impl.mm index 1cab2002..84b091f63 100644 --- a/ios/web/navigation/navigation_manager_impl.mm +++ b/ios/web/navigation/navigation_manager_impl.mm
@@ -227,37 +227,44 @@ // GetLastCommittedItem() should return null while session restoration is in // progress and real item after the first post-restore navigation is // finished. IsRestoreSessionInProgress(), will return true until the first - // post-restore is finished. + // post-restore is started. if (IsRestoreSessionInProgress()) return nullptr; - return GetLastCommittedItemInCurrentOrRestoredSession(); + NavigationItem* result = GetLastCommittedItemInCurrentOrRestoredSession(); + if (!result || wk_navigation_util::IsRestoreSessionUrl(result->GetURL())) { + // Session restoration has completed, but the first post-restore navigation + // has not finished yet, so there is no committed URLs in the navigation + // stack. + return nullptr; + } + + return result; } int NavigationManagerImpl::GetLastCommittedItemIndex() const { // GetLastCommittedItemIndex() should return -1 while session restoration is // in progress and real item after the first post-restore navigation is // finished. IsRestoreSessionInProgress(), will return true until the first - // post-restore is finished. + // post-restore is started. if (IsRestoreSessionInProgress()) return -1; + NavigationItem* item = GetLastCommittedItemInCurrentOrRestoredSession(); + if (!item || wk_navigation_util::IsRestoreSessionUrl(item->GetURL())) { + // Session restoration has completed, but the first post-restore + // navigation has not finished yet, so there is no committed URLs in the + // navigation stack. + return -1; + } + return GetLastCommittedItemIndexInCurrentOrRestoredSession(); } NavigationItem* NavigationManagerImpl::GetPendingItem() const { - NavigationItem* item = GetPendingItemInCurrentOrRestoredSession(); - - // GetPendingItem() should return null while session restoration is in - // progress and real item when the first post-restore navigation has started. - // It's not possible to rely on IsRestoreSessionInProgress(), because this - // method may return true until the first post-restore is finished, hence - // this code relies on actual navigation URL to determine if restoration is - // complete. - if (item && wk_navigation_util::IsRestoreSessionUrl(item->GetURL())) + if (IsRestoreSessionInProgress()) return nullptr; - - return item; + return GetPendingItemInCurrentOrRestoredSession(); } NavigationItem* NavigationManagerImpl::GetTransientItem() const {
diff --git a/ios/web/navigation/navigation_manager_impl_unittest.mm b/ios/web/navigation/navigation_manager_impl_unittest.mm index b930ac5..b7984060 100644 --- a/ios/web/navigation/navigation_manager_impl_unittest.mm +++ b/ios/web/navigation/navigation_manager_impl_unittest.mm
@@ -1796,7 +1796,8 @@ ->GetPendingItemInCurrentOrRestoredSession() ->SetVirtualURL(virtual_url); [mock_wk_list_ setCurrentURL:base::SysUTF8ToNSString(url.spec())]; - navigation_manager()->CommitPendingItem(); + navigation_manager()->OnRendererInitiatedNavigationStarted( + GURL("http://www.1.com/virtual")); navigation_manager()->ReloadWithUserAgentType(UserAgentType::DESKTOP); @@ -2009,7 +2010,8 @@ [mock_wk_list_ setCurrentURL:@"http://www.url.com/1" backListURLs:@[ @"http://www.url.com/0" ] forwardListURLs:@[ @"http://www.url.com/2" ]]; - navigation_manager()->CommitPendingItem(); + navigation_manager()->OnRendererInitiatedNavigationStarted( + GURL("http://www.url.com/2")); } ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.h b/ios/web/navigation/wk_based_navigation_manager_impl.h index e5cce840..57cbc22 100644 --- a/ios/web/navigation/wk_based_navigation_manager_impl.h +++ b/ios/web/navigation/wk_based_navigation_manager_impl.h
@@ -94,6 +94,7 @@ void InitializeSession() override; void OnNavigationItemsPruned(size_t pruned_item_count) override; void OnNavigationItemCommitted() override; + void OnRendererInitiatedNavigationStarted(const GURL& url) override; void DetachFromWebView() override; CRWSessionController* GetSessionController() const override; void AddTransientItem(const GURL& url) override; @@ -274,7 +275,8 @@ std::unique_ptr<base::ElapsedTimer> restoration_timer_; // The active navigation entry in the restored session. GetVisibleItem() - // returns this item when |is_restore_session_in_progress_| is true so that + // returns this item in the window between |is_restore_session_in_progress_| + // becomes true until the first post-restore navigation is finished, so that // clients of this navigation manager gets sane values for visible title and // URL. std::unique_ptr<NavigationItem> restored_visible_item_;
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.mm b/ios/web/navigation/wk_based_navigation_manager_impl.mm index fa129de..09544eee 100644 --- a/ios/web/navigation/wk_based_navigation_manager_impl.mm +++ b/ios/web/navigation/wk_based_navigation_manager_impl.mm
@@ -85,10 +85,21 @@ void WKBasedNavigationManagerImpl::OnNavigationItemCommitted() { NavigationItem* item = GetLastCommittedItemInCurrentOrRestoredSession(); - if (!wk_navigation_util::IsRestoreSessionUrl(item->GetURL()) && - is_restore_session_in_progress_) { - is_restore_session_in_progress_ = false; + DCHECK(item); + delegate_->OnNavigationItemCommitted(item); + + if (!wk_navigation_util::IsRestoreSessionUrl(item->GetURL())) { restored_visible_item_.reset(); + } +} + +void WKBasedNavigationManagerImpl::OnRendererInitiatedNavigationStarted( + const GURL& url) { + if (!wk_navigation_util::IsRestoreSessionUrl(url) && + is_restore_session_in_progress_) { + // Session restoration navigations are rendered-initiated. + + is_restore_session_in_progress_ = false; UMA_HISTOGRAM_TIMES(kRestoreNavigationTime, restoration_timer_->Elapsed()); restoration_timer_.reset(); @@ -100,8 +111,6 @@ LoadIfNecessary(); } - - delegate_->OnNavigationItemCommitted(item); } CRWSessionController* WKBasedNavigationManagerImpl::GetSessionController() @@ -299,7 +308,7 @@ } NavigationItem* WKBasedNavigationManagerImpl::GetVisibleItem() const { - if (is_restore_session_in_progress_) + if (is_restore_session_in_progress_ || restored_visible_item_) return restored_visible_item_.get(); NavigationItem* transient_item = GetTransientItem();
diff --git a/ios/web/public/navigation_manager.h b/ios/web/public/navigation_manager.h index 09c1398c..2bd607f6 100644 --- a/ios/web/public/navigation_manager.h +++ b/ios/web/public/navigation_manager.h
@@ -197,9 +197,7 @@ std::vector<std::unique_ptr<NavigationItem>> items) = 0; // Returns true after session restoration has started, until the first - // post-restore navigation is finished. Returns true when first post-restore - // navigation is started, even though technically session restoration is - // complete. + // post-restore navigation is started. virtual bool IsRestoreSessionInProgress() const = 0; // Registers a callback to be run when session restoration is completed.
diff --git a/ios/web/public/test/fakes/test_web_state_observer.mm b/ios/web/public/test/fakes/test_web_state_observer.mm index 750861f..7fe436a 100644 --- a/ios/web/public/test/fakes/test_web_state_observer.mm +++ b/ios/web/public/test/fakes/test_web_state_observer.mm
@@ -7,7 +7,7 @@ #include <memory> #import "ios/web/public/web_state/navigation_context.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ios/web/web_state/navigation_context_impl.h" #include "net/http/http_response_headers.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ios/web/shell/shell_web_client.mm b/ios/web/shell/shell_web_client.mm index 7082746..13fb1f4 100644 --- a/ios/web/shell/shell_web_client.mm +++ b/ios/web/shell/shell_web_client.mm
@@ -8,7 +8,7 @@ #include "ios/web/public/service_names.mojom.h" #include "ios/web/public/user_agent.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #include "ios/web/shell/shell_web_main_parts.h" #import "ios/web/shell/web_usage_controller.mojom.h" #include "mojo/public/cpp/bindings/strong_binding.h"
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index e9fdac62..dd259c5d 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -4765,6 +4765,9 @@ return; } + _webStateImpl->GetNavigationManagerImpl() + .OnRendererInitiatedNavigationStarted(webViewURL); + std::unique_ptr<web::NavigationContextImpl> navigationContext = [self registerLoadRequestForURL:webViewURL sameDocumentNavigation:NO
diff --git a/ios/web/web_state/web_frame_util.mm b/ios/web/web_state/web_frame_util.mm index 8821a52f..101ce10 100644 --- a/ios/web/web_state/web_frame_util.mm +++ b/ios/web/web_state/web_frame_util.mm
@@ -7,7 +7,7 @@ #include "base/logging.h" #include "ios/web/public/web_state/web_frame.h" #include "ios/web/public/web_state/web_frames_manager.h" -#include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/web/web_state/web_state_unittest.mm b/ios/web/web_state/web_state_unittest.mm index 1997999..d5c1a60 100644 --- a/ios/web/web_state/web_state_unittest.mm +++ b/ios/web/web_state/web_state_unittest.mm
@@ -345,18 +345,6 @@ // LoadIfNecessary call. Fix the bug and remove extra call. navigation_manager->LoadIfNecessary(); - if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { - // After restoration is started GetPendingItemIndex() will return -1 and - // GetPendingItem() will return null. Pending item will be returned after - // the first post-restore navigation is started, but before session - // restoration is complete. Session restoration will be completed when the - // fist post-restore navigation is finished. This is why it is not possible - // to assert that pending item does not exist during the session - // restoration. - EXPECT_EQ(-1, navigation_manager->GetPendingItemIndex()); - EXPECT_FALSE(navigation_manager->GetPendingItem()); - } - // Verify that session was fully restored. int kExpectedItemCount = web::GetWebClient()->IsSlimNavigationManagerEnabled() ? wk_navigation_util::kMaxSessionSize @@ -364,6 +352,7 @@ EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ bool restored = navigation_manager->GetItemCount() == kExpectedItemCount && navigation_manager->CanGoForward(); + EXPECT_EQ(restored, !navigation_manager->IsRestoreSessionInProgress()); if (!restored) { EXPECT_FALSE(navigation_manager->GetLastCommittedItem()); EXPECT_EQ(-1, navigation_manager->GetLastCommittedItemIndex()); @@ -373,30 +362,27 @@ EXPECT_TRUE(navigation_manager->GetForwardItems().empty()); EXPECT_EQ("Test0", base::UTF16ToASCII(web_state_ptr->GetTitle())); EXPECT_EQ(0.0, web_state_ptr->GetLoadingProgress()); - NavigationItem* pendig_item = navigation_manager->GetPendingItem(); - if (pendig_item) { - // Pending item is non-null after the first post-restore navigation is - // started (when happens before session restoration is complete). But - // pending item should never be an internal placeholder or session - // restoration URL. - EXPECT_FALSE(IsWKInternalUrl(pendig_item->GetURL())); - } + EXPECT_EQ(-1, navigation_manager->GetPendingItemIndex()); + EXPECT_FALSE(navigation_manager->GetPendingItem()); } else { - if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { - EXPECT_EQ("www.0.com", base::UTF16ToASCII(web_state_ptr->GetTitle())); - } else { - // This page never loads and does not actually have a title, so - // returning cached title is a bug. However there is not much value in - // fixing this bug for legacy navigation manager. - EXPECT_EQ("Test0", base::UTF16ToASCII(web_state_ptr->GetTitle())); - } - EXPECT_EQ("http://www.0.com/", web_state_ptr->GetLastCommittedURL()); + EXPECT_EQ("Test0", base::UTF16ToASCII(web_state_ptr->GetTitle())); NavigationItem* last_committed_item = navigation_manager->GetLastCommittedItem(); - EXPECT_TRUE(last_committed_item); - EXPECT_TRUE(last_committed_item && - last_committed_item->GetURL() == "http://www.0.com/"); - EXPECT_EQ(0, navigation_manager->GetLastCommittedItemIndex()); + // After restoration is complete GetLastCommittedItem() will return null + // until fist post-restore navigation is finished. + if (last_committed_item) { + EXPECT_EQ("http://www.0.com/", last_committed_item->GetURL()); + EXPECT_EQ("http://www.0.com/", web_state_ptr->GetLastCommittedURL()); + EXPECT_EQ(0, navigation_manager->GetLastCommittedItemIndex()); + } else { + EXPECT_EQ("", web_state_ptr->GetLastCommittedURL()); + EXPECT_EQ(-1, navigation_manager->GetLastCommittedItemIndex()); + NavigationItem* pending_item = navigation_manager->GetPendingItem(); + EXPECT_TRUE(pending_item); + if (pending_item) { + EXPECT_EQ("http://www.0.com/", pending_item->GetURL()); + } + } EXPECT_TRUE(navigation_manager->GetBackwardItems().empty()); EXPECT_EQ(std::max(navigation_manager->GetItemCount() - 1, 0), static_cast<int>(navigation_manager->GetForwardItems().size()));
diff --git a/ios/web_view/internal/autofill/cwv_autofill_controller.mm b/ios/web_view/internal/autofill/cwv_autofill_controller.mm index 9f02a5a..60c0b9bf7 100644 --- a/ios/web_view/internal/autofill/cwv_autofill_controller.mm +++ b/ios/web_view/internal/autofill/cwv_autofill_controller.mm
@@ -23,8 +23,8 @@ #import "components/autofill/ios/browser/js_suggestion_manager.h" #import "components/autofill/ios/form_util/form_activity_observer_bridge.h" #include "components/autofill/ios/form_util/form_activity_params.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/core/service_access_type.h" +#include "components/sync/driver/sync_service.h" #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" #include "ios/web/public/web_state/web_frame.h" #include "ios/web/public/web_state/web_frame_util.h"
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h index 88fbc23..3af74138 100644 --- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h +++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
@@ -64,6 +64,7 @@ base::OnceClosure show_migration_dialog_closure) override; void ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) override; void ShowLocalCardMigrationResults(
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm index 867df73..e38ec8f 100644 --- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm +++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
@@ -145,6 +145,7 @@ void WebViewAutofillClientIOS::ConfirmMigrateLocalCardToCloud( std::unique_ptr<base::DictionaryValue> legal_message, + const std::string& user_email, const std::vector<MigratableCreditCard>& migratable_credit_cards, LocalCardMigrationCallback start_migrating_cards_callback) { NOTIMPLEMENTED();
diff --git a/ios/web_view/internal/cwv_scroll_view.mm b/ios/web_view/internal/cwv_scroll_view.mm index 2e4a541..aca80ec56 100644 --- a/ios/web_view/internal/cwv_scroll_view.mm +++ b/ios/web_view/internal/cwv_scroll_view.mm
@@ -73,6 +73,14 @@ _proxy.scrollsToTop = scrollsToTop; } +- (BOOL)bounces { + return _proxy.bounces; +} + +- (void)setBounces:(BOOL)bounces { + _proxy.bounces = bounces; +} + - (UIScrollViewContentInsetAdjustmentBehavior)contentInsetAdjustmentBehavior API_AVAILABLE(ios(11.0)) { return _proxy.contentInsetAdjustmentBehavior;
diff --git a/ios/web_view/internal/cwv_web_view_configuration.mm b/ios/web_view/internal/cwv_web_view_configuration.mm index 6f090b0b..3a6842a 100644 --- a/ios/web_view/internal/cwv_web_view_configuration.mm +++ b/ios/web_view/internal/cwv_web_view_configuration.mm
@@ -8,7 +8,7 @@ #include "base/logging.h" #include "base/threading/thread_restrictions.h" -#include "components/browser_sync/profile_sync_service.h" +#include "components/sync/driver/sync_service.h" #include "ios/web_view/cwv_web_view_buildflags.h" #include "ios/web_view/internal/app/application_context.h" #import "ios/web_view/internal/autofill/cwv_autofill_data_manager_internal.h" @@ -154,7 +154,7 @@ #pragma mark - Sync - (CWVSyncController*)syncController { if (!_syncController && self.persistent) { - browser_sync::ProfileSyncService* profileSyncService = + syncer::SyncService* syncService = ios_web_view::WebViewProfileSyncServiceFactory::GetForBrowserState( self.browserState); identity::IdentityManager* identityManager = @@ -167,11 +167,11 @@ ios_web_view::WebViewSigninErrorControllerFactory::GetForBrowserState( self.browserState); - _syncController = [[CWVSyncController alloc] - initWithProfileSyncService:profileSyncService - identityManager:identityManager - tokenService:tokenService - signinErrorController:signinErrorController]; + _syncController = + [[CWVSyncController alloc] initWithSyncService:syncService + identityManager:identityManager + tokenService:tokenService + signinErrorController:signinErrorController]; // Set the newly created CWVSyncController on IOSWebViewSigninClient to // so access tokens can be fetched.
diff --git a/ios/web_view/internal/passwords/web_view_password_store_factory.mm b/ios/web_view/internal/passwords/web_view_password_store_factory.mm index 5039dbf..c30070f 100644 --- a/ios/web_view/internal/passwords/web_view_password_store_factory.mm +++ b/ios/web_view/internal/passwords/web_view_password_store_factory.mm
@@ -13,7 +13,6 @@ #include "base/sequenced_task_runner.h" #include "base/task/post_task.h" #include "base/threading/sequenced_task_runner_handle.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/keyed_service/core/service_access_type.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h" @@ -22,6 +21,7 @@ #include "components/password_manager/core/browser/login_database.h" #include "components/password_manager/core/browser/password_store_default.h" #include "components/password_manager/core/browser/password_store_factory_util.h" +#include "components/sync/driver/sync_service.h" #include "ios/web_view/internal/app/application_context.h" #import "ios/web_view/internal/sync/web_view_profile_sync_service_factory.h" #include "ios/web_view/internal/web_view_browser_state.h"
diff --git a/ios/web_view/internal/sync/cwv_sync_controller.mm b/ios/web_view/internal/sync/cwv_sync_controller.mm index 0d72423..88bb0f4 100644 --- a/ios/web_view/internal/sync/cwv_sync_controller.mm +++ b/ios/web_view/internal/sync/cwv_sync_controller.mm
@@ -8,11 +8,11 @@ #include <memory> #include "base/strings/sys_string_conversions.h" -#include "components/browser_sync/profile_sync_service.h" #include "components/signin/core/browser/account_info.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_error_controller.h" #include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h" +#include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_user_settings.h" #include "ios/web/public/web_thread.h" #import "ios/web_view/public/cwv_identity.h" @@ -78,7 +78,7 @@ namespace ios_web_view { -// Bridge that observes browser_sync::ProfileSyncService and calls analagous +// Bridge that observes syncer::SyncService and calls analagous // methods on CWVSyncController. class WebViewSyncControllerObserverBridge : public syncer::SyncServiceObserver, @@ -107,7 +107,7 @@ } // namespace ios_web_view @implementation CWVSyncController { - browser_sync::ProfileSyncService* _profileSyncService; + syncer::SyncService* _syncService; identity::IdentityManager* _identityManager; ProfileOAuth2TokenService* _tokenService; SigninErrorController* _signinErrorController; @@ -119,22 +119,21 @@ @synthesize delegate = _delegate; -- (instancetype) - initWithProfileSyncService: - (browser_sync::ProfileSyncService*)profileSyncService - identityManager:(identity::IdentityManager*)identityManager - tokenService:(ProfileOAuth2TokenService*)tokenService - signinErrorController:(SigninErrorController*)signinErrorController { +- (instancetype)initWithSyncService:(syncer::SyncService*)syncService + identityManager:(identity::IdentityManager*)identityManager + tokenService:(ProfileOAuth2TokenService*)tokenService + signinErrorController: + (SigninErrorController*)signinErrorController { self = [super init]; if (self) { - _profileSyncService = profileSyncService; + _syncService = syncService; _identityManager = identityManager; _tokenService = tokenService; _signinErrorController = signinErrorController; _observer = std::make_unique<ios_web_view::WebViewSyncControllerObserverBridge>( self); - _profileSyncService->AddObserver(_observer.get()); + _syncService->AddObserver(_observer.get()); _signinErrorController->AddObserver(_observer.get()); // Refresh access tokens on foreground to extend expiration dates. @@ -148,7 +147,7 @@ } - (void)dealloc { - _profileSyncService->RemoveObserver(_observer.get()); + _syncService->RemoveObserver(_observer.get()); _signinErrorController->RemoveObserver(_observer.get()); } @@ -167,7 +166,7 @@ } - (BOOL)isPassphraseNeeded { - return _profileSyncService->IsPassphraseRequiredForDecryption(); + return _syncService->IsPassphraseRequiredForDecryption(); } - (void)startSyncWithIdentity:(CWVIdentity*)identity @@ -199,7 +198,7 @@ } - (BOOL)unlockWithPassphrase:(NSString*)passphrase { - return _profileSyncService->GetUserSettings()->SetDecryptionPassphrase( + return _syncService->GetUserSettings()->SetDecryptionPassphrase( base::SysNSStringToUTF8(passphrase)); } @@ -212,7 +211,7 @@ } - (void)didShutdownSync { - _profileSyncService->RemoveObserver(_observer.get()); + _syncService->RemoveObserver(_observer.get()); _signinErrorController->RemoveObserver(_observer.get()); }
diff --git a/ios/web_view/internal/sync/cwv_sync_controller_internal.h b/ios/web_view/internal/sync/cwv_sync_controller_internal.h index ff9e5b2..16fcf05a 100644 --- a/ios/web_view/internal/sync/cwv_sync_controller_internal.h +++ b/ios/web_view/internal/sync/cwv_sync_controller_internal.h
@@ -14,9 +14,9 @@ NS_ASSUME_NONNULL_BEGIN -namespace browser_sync { -class ProfileSyncService; -} // namespace browser_sync +namespace syncer { +class SyncService; +} // namespace syncer namespace identity { class IdentityManager; @@ -28,12 +28,11 @@ @interface CWVSyncController () // All dependencies must out live this class. -- (instancetype) - initWithProfileSyncService: - (browser_sync::ProfileSyncService*)profileSyncService - identityManager:(identity::IdentityManager*)identityManager - tokenService:(ProfileOAuth2TokenService*)tokenService - signinErrorController:(SigninErrorController*)SigninErrorController +- (instancetype)initWithSyncService:(syncer::SyncService*)syncService + identityManager:(identity::IdentityManager*)identityManager + tokenService:(ProfileOAuth2TokenService*)tokenService + signinErrorController: + (SigninErrorController*)SigninErrorController NS_DESIGNATED_INITIALIZER; // Called by WebViewProfileOAuth2TokenServiceIOSProviderImpl to obtain
diff --git a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm index cc8f86a..85544e1 100644 --- a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm +++ b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
@@ -127,10 +127,10 @@ .WillOnce(Invoke(this, &CWVSyncControllerTest::AddObserver)); sync_controller_ = [[CWVSyncController alloc] - initWithProfileSyncService:profile_sync_service_.get() - identityManager:identity_test_env_.identity_manager() - tokenService:&token_service_ - signinErrorController:&signin_error_controller_]; + initWithSyncService:profile_sync_service_.get() + identityManager:identity_test_env_.identity_manager() + tokenService:&token_service_ + signinErrorController:&signin_error_controller_]; }; ~CWVSyncControllerTest() override {
diff --git a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.h b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.h index aae4771..c25243c3 100644 --- a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.h +++ b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.h
@@ -11,9 +11,9 @@ #include "base/no_destructor.h" #include "components/keyed_service/ios/browser_state_keyed_service_factory.h" -namespace browser_sync { -class ProfileSyncService; -} // namespace browser_sync +namespace syncer { +class SyncService; +} // namespace syncer namespace ios_web_view { class WebViewBrowserState; @@ -23,7 +23,7 @@ class WebViewProfileSyncServiceFactory : public BrowserStateKeyedServiceFactory { public: - static browser_sync::ProfileSyncService* GetForBrowserState( + static syncer::SyncService* GetForBrowserState( WebViewBrowserState* browser_state); static WebViewProfileSyncServiceFactory* GetInstance();
diff --git a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm index 93df6df..507ef405 100644 --- a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm +++ b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
@@ -14,6 +14,7 @@ #include "components/sync/base/model_type.h" #include "components/sync/device_info/local_device_info_provider_impl.h" #include "components/sync/driver/startup_controller.h" +#include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_util.h" #include "ios/web/public/web_thread.h" #include "ios/web_view/internal/app/application_context.h" @@ -37,8 +38,6 @@ namespace ios_web_view { -using browser_sync::ProfileSyncService; - // static WebViewProfileSyncServiceFactory* WebViewProfileSyncServiceFactory::GetInstance() { @@ -47,9 +46,9 @@ } // static -ProfileSyncService* WebViewProfileSyncServiceFactory::GetForBrowserState( +syncer::SyncService* WebViewProfileSyncServiceFactory::GetForBrowserState( WebViewBrowserState* browser_state) { - return static_cast<ProfileSyncService*>( + return static_cast<syncer::SyncService*>( GetInstance()->GetServiceForBrowserState(browser_state, true)); } @@ -82,9 +81,9 @@ WebViewIdentityManagerFactory::GetForBrowserState(browser_state); WebViewGCMProfileServiceFactory::GetForBrowserState(browser_state); - ProfileSyncService::InitParams init_params; + browser_sync::ProfileSyncService::InitParams init_params; init_params.identity_manager = identity_manager; - init_params.start_behavior = ProfileSyncService::MANUAL_START; + init_params.start_behavior = browser_sync::ProfileSyncService::MANUAL_START; init_params.sync_client = std::make_unique<WebViewSyncClient>(browser_state); init_params.url_loader_factory = browser_state->GetSharedURLLoaderFactory(); // ios/web_view has no need to update network time. @@ -97,7 +96,8 @@ ->GetIdentityProvider()); auto profile_sync_service = - std::make_unique<ProfileSyncService>(std::move(init_params)); + std::make_unique<browser_sync::ProfileSyncService>( + std::move(init_params)); profile_sync_service->Initialize(); return profile_sync_service; }
diff --git a/ios/web_view/public/cwv_scroll_view.h b/ios/web_view/public/cwv_scroll_view.h index b79ab284..9935172 100644 --- a/ios/web_view/public/cwv_scroll_view.h +++ b/ios/web_view/public/cwv_scroll_view.h
@@ -32,6 +32,7 @@ @property(nonatomic, readonly, getter=isDragging) BOOL dragging; @property(nonatomic, readonly, getter=isTracking) BOOL tracking; @property(nonatomic) BOOL scrollsToTop; +@property(nonatomic) BOOL bounces; @property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior API_AVAILABLE(ios(11.0));
diff --git a/media/base/ipc/media_param_traits_macros.h b/media/base/ipc/media_param_traits_macros.h index 44e6602..e1a6a2bd 100644 --- a/media/base/ipc/media_param_traits_macros.h +++ b/media/base/ipc/media_param_traits_macros.h
@@ -24,6 +24,7 @@ #include "media/base/encryption_scheme.h" #include "media/base/hdr_metadata.h" #include "media/base/media_log_event.h" +#include "media/base/media_status.h" #include "media/base/output_device_info.h" #include "media/base/overlay_info.h" #include "media/base/pipeline_status.h" @@ -110,6 +111,9 @@ IPC_ENUM_TRAITS_MAX_VALUE(media::MediaLogEvent::Type, media::MediaLogEvent::TYPE_LAST) +IPC_ENUM_TRAITS_MAX_VALUE(media::MediaStatus::State, + media::MediaStatus::State::STATE_MAX) + IPC_ENUM_TRAITS_MAX_VALUE(media::OutputDeviceStatus, media::OUTPUT_DEVICE_STATUS_MAX)
diff --git a/media/base/media_status.h b/media/base/media_status.h index 8d913e3..5dc4ce9 100644 --- a/media/base/media_status.h +++ b/media/base/media_status.h
@@ -16,7 +16,14 @@ // TODO(https://crbug.com/820277): Deduplicate media_router::MediaStatus. struct MEDIA_EXPORT MediaStatus { public: - enum class State { UNKNOWN, PLAYING, PAUSED, BUFFERING, STOPPED }; + enum class State { + UNKNOWN, + PLAYING, + PAUSED, + BUFFERING, + STOPPED, + STATE_MAX = STOPPED, + }; MediaStatus(); MediaStatus(const MediaStatus& other);
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 32318703..13a1d1c 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -340,7 +340,13 @@ // Enables handling of hardware media keys for controlling media. const base::Feature kHardwareMediaKeyHandling{ - "HardwareMediaKeyHandling", base::FEATURE_DISABLED_BY_DEFAULT}; + "HardwareMediaKeyHandling", +#if defined(OS_CHROMEOS) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif +}; // Enables low-delay video rendering in media pipeline on "live" stream. const base::Feature kLowDelayVideoRenderingOnLiveStream{ @@ -479,7 +485,7 @@ #if defined(OS_ANDROID) base::FEATURE_ENABLED_BY_DEFAULT #else - base::FEATURE_ENABLED_BY_DEFAULT + base::FEATURE_DISABLED_BY_DEFAULT #endif };
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index 6afb8e7..432d3e44 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h
@@ -263,6 +263,7 @@ MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&)); MOCK_METHOD1(OnVideoOpacityChange, void(bool)); MOCK_METHOD1(OnDurationChange, void(base::TimeDelta)); + MOCK_METHOD1(OnRemotePlayStateChange, void(MediaStatus::State state)); }; class MockVideoRenderer : public VideoRenderer {
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc index 4a866067..15c0c23 100644 --- a/media/base/pipeline_impl.cc +++ b/media/base/pipeline_impl.cc
@@ -138,6 +138,7 @@ void OnVideoNaturalSizeChange(const gfx::Size& size) final; void OnVideoOpacityChange(bool opaque) final; void OnDurationChange(base::TimeDelta duration) final; + void OnRemotePlayStateChange(MediaStatus::State state) final; // Common handlers for notifications from renderers and demuxer. void OnPipelineError(PipelineStatus error); @@ -767,6 +768,13 @@ SetDuration(duration); } +void PipelineImpl::RendererWrapper::OnRemotePlayStateChange( + MediaStatus::State state) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + + // TODO(tguilbert): post change to Pipeline +} + void PipelineImpl::RendererWrapper::OnPipelineError(PipelineStatus error) { DCHECK(media_task_runner_->BelongsToCurrentThread()); DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
diff --git a/media/base/renderer_client.h b/media/base/renderer_client.h index d0b6c9d..703ecfe6 100644 --- a/media/base/renderer_client.h +++ b/media/base/renderer_client.h
@@ -7,6 +7,7 @@ #include "base/time/time.h" #include "media/base/audio_decoder_config.h" +#include "media/base/media_status.h" #include "media/base/pipeline_status.h" #include "media/base/video_decoder_config.h" #include "media/base/waiting.h" @@ -49,6 +50,12 @@ // Executed when video metadata is first read, and whenever it changes. // Only used when we are using a URL demuxer (e.g. for MediaPlayerRenderer). virtual void OnDurationChange(base::TimeDelta duration) = 0; + + // Executed when the status of a video playing remotely is changed, without + // the change originating from the media::Pipeline that owns |this|. + // Only used with the FlingingRenderer, when an external device play/pauses + // videos, and WMPI needs to be updated accordingly. + virtual void OnRemotePlayStateChange(media::MediaStatus::State state) = 0; }; } // namespace media
diff --git a/media/filters/fuchsia/fuchsia_video_decoder.cc b/media/filters/fuchsia/fuchsia_video_decoder.cc index b262bdb4..ef261f9 100644 --- a/media/filters/fuchsia/fuchsia_video_decoder.cc +++ b/media/filters/fuchsia/fuchsia_video_decoder.cc
@@ -268,7 +268,7 @@ class FuchsiaVideoDecoder : public VideoDecoder { public: - FuchsiaVideoDecoder(); + explicit FuchsiaVideoDecoder(bool enable_sw_decoding); ~FuchsiaVideoDecoder() override; // VideoDecoder implementation. @@ -318,6 +318,8 @@ uint64_t buffer_lifetime_ordinal, uint32_t packet_index); + const bool enable_sw_decoding_; + OutputCB output_cb_; // Aspect ratio specified in container, or 1.0 if it's not specified. This @@ -352,7 +354,8 @@ DISALLOW_COPY_AND_ASSIGN(FuchsiaVideoDecoder); }; -FuchsiaVideoDecoder::FuchsiaVideoDecoder() : weak_factory_(this) { +FuchsiaVideoDecoder::FuchsiaVideoDecoder(bool enable_sw_decoding) + : enable_sw_decoding_(enable_sw_decoding), weak_factory_(this) { weak_this_ = weak_factory_.GetWeakPtr(); } @@ -399,7 +402,7 @@ } codec_params.promise_separate_access_units_on_input = true; - codec_params.require_hw = true; + codec_params.require_hw = !enable_sw_decoding_; auto codec_factory = base::fuchsia::ComponentContext::GetDefault() @@ -576,6 +579,22 @@ DCHECK(layout); break; + case libyuv::FOURCC_YV12: + layout = VideoFrameLayout::CreateWithPlanes( + PIXEL_FORMAT_YV12, coded_size, + std::vector<VideoFrameLayout::Plane>{ + VideoFrameLayout::Plane(output_format_.primary_line_stride_bytes, + output_format_.primary_start_offset), + VideoFrameLayout::Plane( + output_format_.secondary_line_stride_bytes, + output_format_.secondary_start_offset), + VideoFrameLayout::Plane( + output_format_.secondary_line_stride_bytes, + output_format_.tertiary_start_offset), + }); + DCHECK(layout); + break; + default: LOG(ERROR) << "unknown fourcc: " << std::string(reinterpret_cast<char*>(&output_format_.fourcc), @@ -742,6 +761,7 @@ fuchsia::mediacodec::CodecPacket packet; packet.header.buffer_lifetime_ordinal = input_buffer_lifetime_ordinal_; packet.header.packet_index = input_buffer - input_buffers_.begin(); + packet.buffer_index = packet.header.packet_index; packet.has_timestamp_ish = true; packet.timestamp_ish = pending_decodes_.front().buffer().timestamp().InNanoseconds(); @@ -811,7 +831,12 @@ } std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoder() { - return std::make_unique<FuchsiaVideoDecoder>(); + return std::make_unique<FuchsiaVideoDecoder>(/*enable_sw_decoding=*/false); +} + +std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoderForTests( + bool enable_sw_decoding) { + return std::make_unique<FuchsiaVideoDecoder>(enable_sw_decoding); } } // namespace media
diff --git a/media/filters/fuchsia/fuchsia_video_decoder.h b/media/filters/fuchsia/fuchsia_video_decoder.h index d9c37d05..52f164ee 100644 --- a/media/filters/fuchsia/fuchsia_video_decoder.h +++ b/media/filters/fuchsia/fuchsia_video_decoder.h
@@ -13,9 +13,16 @@ class VideoDecoder; -// Creates VideoDecoder that uses fuchsia.mediacodec API. +// Creates VideoDecoder that uses fuchsia.mediacodec API. The returned +// VideoDecoder instance will only try to use hardware video codecs. MEDIA_EXPORT std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoder(); +// Same as above, but also allows to enable software codecs. This is useful for +// FuchsiaVideoDecoder tests that run on systems that don't have hardware +// decoder support. +MEDIA_EXPORT std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoderForTests( + bool enable_sw_decoding); + } // namespace media #endif // MEDIA_FILTERS_FUCHSIA_FUCHSIA_VIDEO_DECODER_H_
diff --git a/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc b/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc index 3041a74..4e6adad 100644 --- a/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc +++ b/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc
@@ -17,7 +17,9 @@ class FuchsiaVideoDecoderTest : public testing::Test { public: - FuchsiaVideoDecoderTest() { decoder_ = CreateFuchsiaVideoDecoder(); } + FuchsiaVideoDecoderTest() { + decoder_ = CreateFuchsiaVideoDecoderForTests(/*enable_sw_decoding=*/true); + } ~FuchsiaVideoDecoderTest() override = default; bool Initialize(VideoDecoderConfig config) WARN_UNUSED_RESULT { @@ -83,11 +85,9 @@ base::RepeatingClosure on_frame_; }; -// All tests are disabled because they currently depend on HW decoder that -// doesn't work on test bots. -TEST_F(FuchsiaVideoDecoderTest, DISABLED_CreateAndDestroy) {} +TEST_F(FuchsiaVideoDecoderTest, CreateAndDestroy) {} -TEST_F(FuchsiaVideoDecoderTest, DISABLED_CreateInitDestroy) { +TEST_F(FuchsiaVideoDecoderTest, CreateInitDestroy) { EXPECT_TRUE(Initialize(TestVideoConfig::NormalH264())); } @@ -101,7 +101,7 @@ EXPECT_EQ(num_output_frames_, 1); } -TEST_F(FuchsiaVideoDecoderTest, DISABLED_H264) { +TEST_F(FuchsiaVideoDecoderTest, H264) { ASSERT_TRUE(Initialize(TestVideoConfig::NormalH264())); ASSERT_TRUE(ReadAndDecodeFrame("h264-320x180-frame-0") == DecodeStatus::OK); @@ -114,4 +114,4 @@ EXPECT_EQ(num_output_frames_, 4); } -} // namespace media \ No newline at end of file +} // namespace media
diff --git a/media/gpu/test/generic_dmabuf_video_frame_mapper.cc b/media/gpu/test/generic_dmabuf_video_frame_mapper.cc index 0a9265b..b7db0ed 100644 --- a/media/gpu/test/generic_dmabuf_video_frame_mapper.cc +++ b/media/gpu/test/generic_dmabuf_video_frame_mapper.cc
@@ -31,7 +31,7 @@ } void MunmapBuffers(const std::vector<std::pair<uint8_t*, size_t>>& chunks, - scoped_refptr<VideoFrame> video_frame) { + scoped_refptr<const VideoFrame> video_frame) { for (const auto& chunk : chunks) { DLOG_IF(ERROR, !chunk.first) << "Pointer to be released is nullptr."; munmap(chunk.first, chunk.second); @@ -47,7 +47,7 @@ const gfx::Rect& visible_rect, uint8_t* plane_addrs[kNumOfYUVPlanes], const std::vector<std::pair<uint8_t*, size_t>>& chunks, - scoped_refptr<VideoFrame> src_video_frame) { + scoped_refptr<const VideoFrame> src_video_frame) { int32_t strides[kNumOfYUVPlanes] = {}; for (size_t i = 0; i < layout.num_planes(); i++) { strides[i] = layout.planes()[i].stride; @@ -69,7 +69,7 @@ } // namespace scoped_refptr<VideoFrame> GenericDmaBufVideoFrameMapper::Map( - scoped_refptr<VideoFrame> video_frame) const { + scoped_refptr<const VideoFrame> video_frame) const { if (video_frame->storage_type() != VideoFrame::StorageType::STORAGE_DMABUFS) { VLOGF(1) << "VideoFrame's storage type is not DMABUF: " << video_frame->storage_type();
diff --git a/media/gpu/test/generic_dmabuf_video_frame_mapper.h b/media/gpu/test/generic_dmabuf_video_frame_mapper.h index c7c4332..61755636 100644 --- a/media/gpu/test/generic_dmabuf_video_frame_mapper.h +++ b/media/gpu/test/generic_dmabuf_video_frame_mapper.h
@@ -18,7 +18,7 @@ // VideoFrameMapper implementation. scoped_refptr<VideoFrame> Map( - scoped_refptr<VideoFrame> video_frame) const override; + scoped_refptr<const VideoFrame> video_frame) const override; DISALLOW_COPY_AND_ASSIGN(GenericDmaBufVideoFrameMapper); };
diff --git a/media/gpu/test/vaapi_dmabuf_video_frame_mapper.cc b/media/gpu/test/vaapi_dmabuf_video_frame_mapper.cc index 5097dbc..c1c56044 100644 --- a/media/gpu/test/vaapi_dmabuf_video_frame_mapper.cc +++ b/media/gpu/test/vaapi_dmabuf_video_frame_mapper.cc
@@ -90,7 +90,7 @@ VaapiDmaBufVideoFrameMapper::~VaapiDmaBufVideoFrameMapper() {} scoped_refptr<VideoFrame> VaapiDmaBufVideoFrameMapper::Map( - scoped_refptr<VideoFrame> video_frame) const { + scoped_refptr<const VideoFrame> video_frame) const { DCHECK(vaapi_wrapper_); DCHECK(vaapi_picture_factory_); if (!video_frame->HasDmaBufs()) {
diff --git a/media/gpu/test/vaapi_dmabuf_video_frame_mapper.h b/media/gpu/test/vaapi_dmabuf_video_frame_mapper.h index 687a97f..3b10c51 100644 --- a/media/gpu/test/vaapi_dmabuf_video_frame_mapper.h +++ b/media/gpu/test/vaapi_dmabuf_video_frame_mapper.h
@@ -28,7 +28,7 @@ // VideoFrameMapper override. scoped_refptr<VideoFrame> Map( - scoped_refptr<VideoFrame> video_frame) const override; + scoped_refptr<const VideoFrame> video_frame) const override; private: VaapiDmaBufVideoFrameMapper();
diff --git a/media/gpu/test/video_frame_helpers.h b/media/gpu/test/video_frame_helpers.h index 6aa6930..809c39fd 100644 --- a/media/gpu/test/video_frame_helpers.h +++ b/media/gpu/test/video_frame_helpers.h
@@ -30,8 +30,10 @@ // Process the specified |video_frame|. This can e.g. validate the frame, // calculate the frame's checksum, write the frame to file,... The - // |frame_index| is the index of the video frame in display order. - virtual void ProcessVideoFrame(scoped_refptr<VideoFrame> video_frame, + // |frame_index| is the index of the video frame in display order. The caller + // should not modify the video frame while a reference is being held by the + // VideoFrameProcessor. + virtual void ProcessVideoFrame(scoped_refptr<const VideoFrame> video_frame, size_t frame_index) = 0; };
diff --git a/media/gpu/test/video_frame_mapper.h b/media/gpu/test/video_frame_mapper.h index 4e5a5be..079759f 100644 --- a/media/gpu/test/video_frame_mapper.h +++ b/media/gpu/test/video_frame_mapper.h
@@ -21,7 +21,7 @@ // Maps data referred by |video_frame| and creates a VideoFrame whose dtor // unmap the mapped memory. virtual scoped_refptr<VideoFrame> Map( - scoped_refptr<VideoFrame> video_frame) const = 0; + scoped_refptr<const VideoFrame> video_frame) const = 0; protected: VideoFrameMapper() = default;
diff --git a/media/gpu/test/video_frame_validator.cc b/media/gpu/test/video_frame_validator.cc index 10e3c2eb..e8c63f05 100644 --- a/media/gpu/test/video_frame_validator.cc +++ b/media/gpu/test/video_frame_validator.cc
@@ -29,9 +29,15 @@ return nullptr; } - return base::WrapUnique(new VideoFrameValidator( + auto video_frame_validator = base::WrapUnique(new VideoFrameValidator( VideoFrameValidator::CHECK, base::FilePath(), frame_checksums, base::File(), std::move(video_frame_mapper))); + if (!video_frame_validator->Initialize()) { + LOG(ERROR) << "Failed to initialize VideoFrameValidator."; + return nullptr; + } + + return video_frame_validator; } // static @@ -90,30 +96,74 @@ prefix_output_yuv_(prefix_output_yuv), md5_of_frames_(std::move(md5_of_frames)), md5_file_(std::move(md5_file)), - video_frame_mapper_(std::move(video_frame_mapper)) { - DETACH_FROM_THREAD(thread_checker_); + video_frame_mapper_(std::move(video_frame_mapper)), + num_frames_validating_(0), + frame_validator_thread_("FrameValidatorThread"), + frame_validator_cv_(&frame_validator_lock_) { + DETACH_FROM_SEQUENCE(validator_sequence_checker_); + DETACH_FROM_SEQUENCE(validator_thread_sequence_checker_); } -VideoFrameValidator::~VideoFrameValidator() {} +VideoFrameValidator::~VideoFrameValidator() { + Destroy(); +} + +bool VideoFrameValidator::Initialize() { + if (!frame_validator_thread_.Start()) { + LOG(ERROR) << "Failed to start frame validator thread"; + return false; + } + return true; +} + +void VideoFrameValidator::Destroy() { + frame_validator_thread_.Stop(); + base::AutoLock auto_lock(frame_validator_lock_); + DCHECK_EQ(0u, num_frames_validating_); +} std::vector<VideoFrameValidator::MismatchedFrameInfo> VideoFrameValidator::GetMismatchedFramesInfo() const { - base::AutoLock auto_lock(mismatched_frames_lock_); + base::AutoLock auto_lock(frame_validator_lock_); return mismatched_frames_; } size_t VideoFrameValidator::GetMismatchedFramesCount() const { - base::AutoLock auto_lock(mismatched_frames_lock_); + base::AutoLock auto_lock(frame_validator_lock_); return mismatched_frames_.size(); } +bool VideoFrameValidator::WaitUntilValidated() const { + base::AutoLock auto_lock(frame_validator_lock_); + while (num_frames_validating_ > 0) { + frame_validator_cv_.Wait(); + } + return mismatched_frames_.size() == 0u; +} + void VideoFrameValidator::ProcessVideoFrame( - scoped_refptr<VideoFrame> video_frame, + scoped_refptr<const VideoFrame> video_frame, size_t frame_index) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(validator_sequence_checker_); + + base::AutoLock auto_lock(frame_validator_lock_); + num_frames_validating_++; + + // Unretained is safe here, as we should not destroy the validator while there + // are still frames being validated. + frame_validator_thread_.task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&VideoFrameValidator::ProcessVideoFrameTask, + base::Unretained(this), video_frame, frame_index)); +} + +void VideoFrameValidator::ProcessVideoFrameTask( + const scoped_refptr<const VideoFrame> video_frame, + size_t frame_index) { + DCHECK_CALLED_ON_VALID_SEQUENCE(validator_thread_sequence_checker_); + auto standard_frame = CreateStandardizedFrame(video_frame); if (!standard_frame) { - LOG(ERROR) << "Failed to create standardized frame."; return; } std::string computed_md5 = ComputeMD5FromVideoFrame(standard_frame); @@ -127,7 +177,7 @@ << "Frame number is over than the number of read md5 values in file."; const auto& expected_md5 = md5_of_frames_[frame_index]; if (computed_md5 != expected_md5) { - base::AutoLock auto_lock(mismatched_frames_lock_); + base::AutoLock auto_lock(frame_validator_lock_); mismatched_frames_.push_back( MismatchedFrameInfo{frame_index, computed_md5, expected_md5}); } @@ -137,11 +187,15 @@ LOG_IF(WARNING, !WriteI420ToFile(frame_index, standard_frame.get())) << "Failed to write yuv into file."; } + + base::AutoLock auto_lock(frame_validator_lock_); + num_frames_validating_--; + frame_validator_cv_.Signal(); } scoped_refptr<VideoFrame> VideoFrameValidator::CreateStandardizedFrame( - scoped_refptr<VideoFrame> video_frame) const { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + scoped_refptr<const VideoFrame> video_frame) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(validator_thread_sequence_checker_); auto mapped_frame = video_frame_mapper_->Map(std::move(video_frame)); if (!mapped_frame) { LOG(FATAL) << "Failed to map decoded picture."; @@ -153,7 +207,7 @@ std::string VideoFrameValidator::ComputeMD5FromVideoFrame( scoped_refptr<VideoFrame> video_frame) const { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(validator_thread_sequence_checker_); base::MD5Context context; base::MD5Init(&context); VideoFrame::HashFrameForTesting(&context, video_frame); @@ -164,7 +218,7 @@ scoped_refptr<VideoFrame> VideoFrameValidator::CreateI420Frame( const VideoFrame* const src_frame) const { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(validator_thread_sequence_checker_); const auto& visible_rect = src_frame->visible_rect(); const int width = visible_rect.width(); const int height = visible_rect.height(); @@ -206,7 +260,7 @@ bool VideoFrameValidator::WriteI420ToFile( size_t frame_index, const VideoFrame* const video_frame) const { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(validator_thread_sequence_checker_); if (video_frame->format() != PIXEL_FORMAT_I420) { LOG(ERROR) << "No I420 format frame."; return false;
diff --git a/media/gpu/test/video_frame_validator.h b/media/gpu/test/video_frame_validator.h index 3b6e08d..f131488 100644 --- a/media/gpu/test/video_frame_validator.h +++ b/media/gpu/test/video_frame_validator.h
@@ -13,7 +13,9 @@ #include "base/files/file.h" #include "base/files/file_path.h" #include "base/memory/scoped_refptr.h" +#include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" +#include "base/threading/thread.h" #include "base/threading/thread_checker.h" #include "media/base/video_types.h" #include "media/gpu/test/video_frame_helpers.h" @@ -86,9 +88,13 @@ // function is thread-safe. size_t GetMismatchedFramesCount() const; + // Wait until all currently scheduled frame validations are done. Returns true + // if no corrupt frames were found. This function might take a long time to + // complete, depending on the platform. + bool WaitUntilValidated() const; + // Interface VideoFrameProcessor - // Validate the |video_frame|'s pixel content. - void ProcessVideoFrame(scoped_refptr<VideoFrame> video_frame, + void ProcessVideoFrame(scoped_refptr<const VideoFrame> video_frame, size_t frame_index) override; private: @@ -98,11 +104,21 @@ base::File md5_file, std::unique_ptr<VideoFrameMapper> video_frame_mapper); + // Start the frame validation thread. + bool Initialize(); + // Stop the frame validation thread. + void Destroy(); + + // Validate the |video_frame|'s content on the |frame_validator_thread_|. + void ProcessVideoFrameTask(const scoped_refptr<const VideoFrame> video_frame, + size_t frame_index); + // This maps |video_frame|, converts it to I420 format. // Returns the resulted I420 frame on success, and otherwise return nullptr. // |video_frame| is unchanged in this method. + // TODO(dstaessens@) Move frame helper functions to video_frame_helpers.h. scoped_refptr<VideoFrame> CreateStandardizedFrame( - scoped_refptr<VideoFrame> video_frame) const; + scoped_refptr<const VideoFrame> video_frame) const; // Returns md5 values of video frame represented by |video_frame|. std::string ComputeMD5FromVideoFrame( @@ -118,8 +134,7 @@ // The results of invalid frame data. std::vector<MismatchedFrameInfo> mismatched_frames_ - GUARDED_BY(mismatched_frames_lock_); - mutable base::Lock mismatched_frames_lock_; + GUARDED_BY(frame_validator_lock_); const uint32_t flags_; @@ -134,7 +149,17 @@ const std::unique_ptr<VideoFrameMapper> video_frame_mapper_; - THREAD_CHECKER(thread_checker_); + // The number of frames currently queued for validation. + size_t num_frames_validating_ GUARDED_BY(frame_validator_lock_); + + // Thread on which video frame validation is done. + base::Thread frame_validator_thread_; + mutable base::Lock frame_validator_lock_; + mutable base::ConditionVariable frame_validator_cv_; + + SEQUENCE_CHECKER(validator_sequence_checker_); + SEQUENCE_CHECKER(validator_thread_sequence_checker_); + DISALLOW_COPY_AND_ASSIGN(VideoFrameValidator); }; } // namespace test
diff --git a/media/gpu/test/video_player/video_decoder_client.cc b/media/gpu/test/video_player/video_decoder_client.cc index b07e3f65..8dd2c99 100644 --- a/media/gpu/test/video_player/video_decoder_client.cc +++ b/media/gpu/test/video_player/video_decoder_client.cc
@@ -169,7 +169,7 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_client_sequence_checker_); DVLOGF(4) << "Picture buffer ID: " << picture.picture_buffer_id(); - event_cb_.Run(VideoPlayerEvent::kFrameDecoded); + FireEvent(VideoPlayerEvent::kFrameDecoded); auto it = video_frames_.find(picture.picture_buffer_id()); LOG_ASSERT(it != video_frames_.end()); @@ -191,7 +191,8 @@ frame_renderer_->RenderFrame(wrapped_video_frame); for (VideoFrameProcessor* frame_processor : frame_processors_) - frame_processor->ProcessVideoFrame(video_frame, current_frame_index_); + frame_processor->ProcessVideoFrame(wrapped_video_frame, + current_frame_index_); current_frame_index_++; } @@ -214,7 +215,7 @@ DCHECK_EQ(0u, num_outstanding_decode_requests_); decoder_client_state_ = VideoDecoderClientState::kIdle; - event_cb_.Run(VideoPlayerEvent::kFlushDone); + FireEvent(VideoPlayerEvent::kFlushDone); } void VideoDecoderClient::NotifyResetDone() { @@ -227,7 +228,7 @@ current_frame_index_ = 0; decoder_client_state_ = VideoDecoderClientState::kIdle; - event_cb_.Run(VideoPlayerEvent::kResetDone); + FireEvent(VideoPlayerEvent::kResetDone); } void VideoDecoderClient::NotifyError(VideoDecodeAccelerator::Error error) { @@ -285,6 +286,7 @@ LOG_ASSERT(!decoder_) << "Can't create decoder: already created"; DVLOGF(4) << "Profile: " << config.profile; + decoder_config_ = config; encoded_data_helper_ = std::make_unique<EncodedDataHelper>(*stream, config.profile); @@ -359,6 +361,13 @@ DVLOGF(4) << "Bitstream buffer id: " << bitstream_buffer_id; decoder_->Decode(bitstream_buffer); num_outstanding_decode_requests_++; + + // Throw event when we encounter a config info in a H.264 stream. + if (media::test::EncodedDataHelper::HasConfigInfo( + reinterpret_cast<const uint8_t*>(fragment_bytes.data()), + fragment_size, decoder_config_.profile)) { + FireEvent(VideoPlayerEvent::kConfigInfo); + } } void VideoDecoderClient::PlayTask() { @@ -385,7 +394,7 @@ // Changing the state to flushing will abort any pending decodes. decoder_client_state_ = VideoDecoderClientState::kFlushing; decoder_->Flush(); - event_cb_.Run(VideoPlayerEvent::kFlushing); + FireEvent(VideoPlayerEvent::kFlushing); } void VideoDecoderClient::ResetTask() { @@ -397,7 +406,15 @@ // TODO(dstaessens@) Allow resetting to any point in the stream. encoded_data_helper_->Rewind(); decoder_->Reset(); - event_cb_.Run(VideoPlayerEvent::kResetting); + FireEvent(VideoPlayerEvent::kResetting); +} + +void VideoDecoderClient::FireEvent(VideoPlayerEvent event) { + bool continue_decoding = event_cb_.Run(event); + if (!continue_decoding) { + // Changing the state to idle will abort any pending decodes. + decoder_client_state_ = VideoDecoderClientState::kIdle; + } } void VideoDecoderClient::ReusePictureBufferTask(int32_t picture_buffer_id) {
diff --git a/media/gpu/test/video_player/video_decoder_client.h b/media/gpu/test/video_player/video_decoder_client.h index a694024..552e2b9 100644 --- a/media/gpu/test/video_player/video_decoder_client.h +++ b/media/gpu/test/video_player/video_decoder_client.h
@@ -123,6 +123,9 @@ // Instruct the decoder to perform a Reset. void ResetTask(); + // Fire the specified event. + void FireEvent(VideoPlayerEvent event); + // Called when a picture buffer is ready to be re-used. void ReusePictureBufferTask(int32_t picture_buffer_id); @@ -137,6 +140,7 @@ std::unique_ptr<GpuVideoDecodeAcceleratorFactory> decoder_factory_; std::unique_ptr<VideoDecodeAccelerator> decoder_; + VideoDecodeAccelerator::Config decoder_config_; base::Thread decoder_client_thread_; // Decoder client state, should only be accessed on the decoder client thread.
diff --git a/media/gpu/test/video_player/video_player.cc b/media/gpu/test/video_player/video_player.cc index 481d4e0..79dd642 100644 --- a/media/gpu/test/video_player/video_player.cc +++ b/media/gpu/test/video_player/video_player.cc
@@ -79,19 +79,24 @@ void VideoPlayer::Play() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DVLOGF(4); + + // Play until the end of the video. + PlayUntil(VideoPlayerEvent::kNumEvents, 0); +} + +void VideoPlayer::PlayUntil(VideoPlayerEvent event, size_t event_count) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(video_player_state_, VideoPlayerState::kIdle); DCHECK(video_); DVLOGF(4); // Start decoding the video. + play_until_ = std::make_pair(event, event_count); video_player_state_ = VideoPlayerState::kDecoding; decoder_client_->Play(); } -void VideoPlayer::Stop() { - NOTIMPLEMENTED(); -} - void VideoPlayer::Reset() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DVLOGF(4); @@ -187,15 +192,25 @@ return GetEventCount(VideoPlayerEvent::kFrameDecoded); } -void VideoPlayer::NotifyEvent(VideoPlayerEvent event) { +bool VideoPlayer::NotifyEvent(VideoPlayerEvent event) { base::AutoLock auto_lock(event_lock_); if (event == VideoPlayerEvent::kFlushDone || event == VideoPlayerEvent::kResetDone) { video_player_state_ = VideoPlayerState::kIdle; } + video_player_events_.push_back(event); video_player_event_counts_[static_cast<size_t>(event)]++; event_cv_.Signal(); + + // Check whether video playback should be paused after this event. + if (play_until_.first == event && + play_until_.second == + video_player_event_counts_[static_cast<size_t>(event)]) { + video_player_state_ = VideoPlayerState::kIdle; + return false; + } + return true; } } // namespace test
diff --git a/media/gpu/test/video_player/video_player.h b/media/gpu/test/video_player/video_player.h index 5c9df26e..9736bb1 100644 --- a/media/gpu/test/video_player/video_player.h +++ b/media/gpu/test/video_player/video_player.h
@@ -6,6 +6,7 @@ #define MEDIA_GPU_TEST_VIDEO_PLAYER_VIDEO_PLAYER_H_ #include <memory> +#include <utility> #include <vector> #include "base/callback.h" @@ -40,6 +41,7 @@ kFlushDone, kResetting, kResetDone, + kConfigInfo, // A config info was encountered in a H.264 video stream. kNumEvents, }; @@ -48,7 +50,7 @@ // events to occur. class VideoPlayer { public: - using EventCallback = base::RepeatingCallback<void(VideoPlayerEvent)>; + using EventCallback = base::RepeatingCallback<bool(VideoPlayerEvent)>; ~VideoPlayer(); @@ -61,9 +63,14 @@ const std::vector<VideoFrameProcessor*>& frame_processors, const VideoDecoderClientConfig& config); + // Play the video asynchronously. void Play(); - void Stop(); + // Play the video asynchronously. Automatically pause decoding when the + // specified |event| occurred |event_count| times. + void PlayUntil(VideoPlayerEvent event, size_t event_count = 1); + // Reset the decoder to the beginning of the video stream. void Reset(); + // Flush the decoder. void Flush(); // Get current media time. @@ -105,8 +112,9 @@ const VideoDecoderClientConfig& config); void Destroy(); - // Notify the client an event has occurred (e.g. frame decoded). - void NotifyEvent(VideoPlayerEvent event); + // Notify the video player an event has occurred (e.g. frame decoded). Returns + // whether the decoder client should continue decoding frames. + bool NotifyEvent(VideoPlayerEvent event); const Video* video_; VideoPlayerState video_player_state_; @@ -121,6 +129,10 @@ // The next event ID to start at, when waiting for events. size_t event_id_ GUARDED_BY(event_lock_); + // Automatically pause decoding once the video player has seen the specified + // number of events occur. + std::pair<VideoPlayerEvent, size_t> play_until_; + SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(VideoPlayer); };
diff --git a/media/gpu/video_decode_accelerator_tests.cc b/media/gpu/video_decode_accelerator_tests.cc index 398efdac..b5e3d2d 100644 --- a/media/gpu/video_decode_accelerator_tests.cc +++ b/media/gpu/video_decode_accelerator_tests.cc
@@ -101,7 +101,7 @@ EXPECT_EQ(tvp->GetFlushDoneCount(), 1u); EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames()); - EXPECT_EQ(0u, frame_validator_->GetMismatchedFramesCount()); + EXPECT_TRUE(frame_validator_->WaitUntilValidated()); } // Flush the decoder immediately after initialization. @@ -115,7 +115,7 @@ EXPECT_EQ(tvp->GetFlushDoneCount(), 2u); EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames()); - EXPECT_EQ(0u, frame_validator_->GetMismatchedFramesCount()); + EXPECT_TRUE(frame_validator_->WaitUntilValidated()); } // Flush the decoder immediately after doing a mid-stream reset, without waiting @@ -137,7 +137,7 @@ EXPECT_EQ(tvp->GetResetDoneCount(), 1u); EXPECT_EQ(tvp->GetFlushDoneCount(), 1u); EXPECT_LE(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames()); - EXPECT_EQ(0u, frame_validator_->GetMismatchedFramesCount()); + EXPECT_TRUE(frame_validator_->WaitUntilValidated()); } // Reset the decoder immediately after initialization. @@ -152,7 +152,7 @@ EXPECT_EQ(tvp->GetResetDoneCount(), 1u); EXPECT_EQ(tvp->GetFlushDoneCount(), 1u); EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames()); - EXPECT_EQ(0u, frame_validator_->GetMismatchedFramesCount()); + EXPECT_TRUE(frame_validator_->WaitUntilValidated()); } // Reset the decoder when the middle of the stream is reached. @@ -171,7 +171,7 @@ EXPECT_EQ(tvp->GetFlushDoneCount(), 1u); EXPECT_EQ(tvp->GetFrameDecodedCount(), numFramesDecoded + g_env->video_->NumFrames()); - EXPECT_EQ(0u, frame_validator_->GetMismatchedFramesCount()); + EXPECT_TRUE(frame_validator_->WaitUntilValidated()); } // Reset the decoder when the end of the stream is reached. @@ -189,7 +189,7 @@ EXPECT_EQ(tvp->GetResetDoneCount(), 1u); EXPECT_EQ(tvp->GetFlushDoneCount(), 2u); EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames() * 2); - EXPECT_EQ(0u, frame_validator_->GetMismatchedFramesCount()); + EXPECT_TRUE(frame_validator_->WaitUntilValidated()); } // Reset the decoder immediately when the end-of-stream flush starts, without @@ -211,7 +211,7 @@ EXPECT_LE(tvp->GetFlushDoneCount(), 1u); EXPECT_EQ(tvp->GetResetDoneCount(), 1u); EXPECT_LE(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames()); - EXPECT_EQ(0u, frame_validator_->GetMismatchedFramesCount()); + EXPECT_TRUE(frame_validator_->WaitUntilValidated()); } // Play video from start to end. Multiple buffer decodes will be queued in the @@ -226,6 +226,32 @@ EXPECT_EQ(tvp->GetFlushDoneCount(), 1u); EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames()); + EXPECT_TRUE(frame_validator_->WaitUntilValidated()); +} + +// Reset the decoder immediately when encountering the first config info in a +// H.264 video stream. After resetting the video is played until the end. +TEST_F(VideoDecoderTest, ResetAfterFirstConfigInfo) { + // This test is only relevant for H.264 video streams. + if (g_env->video_->Profile() < H264PROFILE_MIN || + g_env->video_->Profile() > H264PROFILE_MAX) + GTEST_SKIP(); + + auto tvp = CreateVideoPlayer(g_env->video_); + + tvp->PlayUntil(VideoPlayerEvent::kConfigInfo); + EXPECT_TRUE(tvp->WaitForEvent(VideoPlayerEvent::kConfigInfo)); + tvp->Reset(); + EXPECT_TRUE(tvp->WaitForResetDone()); + size_t numFramesDecoded = tvp->GetFrameDecodedCount(); + tvp->Play(); + EXPECT_TRUE(tvp->WaitForFlushDone()); + + EXPECT_EQ(tvp->GetResetDoneCount(), 1u); + EXPECT_EQ(tvp->GetFlushDoneCount(), 1u); + EXPECT_EQ(tvp->GetFrameDecodedCount(), + numFramesDecoded + g_env->video_->NumFrames()); + EXPECT_GE(tvp->GetEventCount(VideoPlayerEvent::kConfigInfo), 1u); EXPECT_EQ(0u, frame_validator_->GetMismatchedFramesCount()); }
diff --git a/media/gpu/video_decode_accelerator_unittest.cc b/media/gpu/video_decode_accelerator_unittest.cc index 4ee2c43..096c1d7 100644 --- a/media/gpu/video_decode_accelerator_unittest.cc +++ b/media/gpu/video_decode_accelerator_unittest.cc
@@ -607,6 +607,7 @@ ASSERT_NE(video_frame.get(), nullptr); video_frame_validator_->ProcessVideoFrame(std::move(video_frame), frame_index_); + video_frame_validator_->WaitUntilValidated(); frame_index_++; } rendering_helper_->ConsumeVideoFrame(config_.window_id,
diff --git a/media/mojo/clients/mojo_renderer.cc b/media/mojo/clients/mojo_renderer.cc index 360a2e6..717de96 100644 --- a/media/mojo/clients/mojo_renderer.cc +++ b/media/mojo/clients/mojo_renderer.cc
@@ -282,6 +282,11 @@ client_->OnDurationChange(duration); } +void MojoRenderer::OnRemotePlayStateChange(media::MediaStatus::State state) { + DVLOG(2) << __func__ << ": state" << (int)state; + client_->OnRemotePlayStateChange(state); +} + void MojoRenderer::OnVideoOpacityChange(bool opaque) { DVLOG(2) << __func__ << ": " << opaque; DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/mojo/clients/mojo_renderer.h b/media/mojo/clients/mojo_renderer.h index e27bf09..4232b22 100644 --- a/media/mojo/clients/mojo_renderer.h +++ b/media/mojo/clients/mojo_renderer.h
@@ -85,6 +85,7 @@ void OnWaiting(WaitingReason reason) override; void OnStatisticsUpdate(const PipelineStatistics& stats) override; void OnDurationChange(base::TimeDelta duration) override; + void OnRemotePlayStateChange(media::MediaStatus::State state) override; // Binds |remote_renderer_| to the mojo message pipe. Can be called multiple // times. If an error occurs during connection, OnConnectionError will be
diff --git a/media/mojo/interfaces/media_types.mojom b/media/mojo/interfaces/media_types.mojom index cbc4a75..a1fa1c64 100644 --- a/media/mojo/interfaces/media_types.mojom +++ b/media/mojo/interfaces/media_types.mojom
@@ -78,6 +78,10 @@ [Native] enum MediaContainerName; +// See media/base/media_status.h for description. +[Native] +enum MediaStatusState; + // This defines a mojo transport format for media::EncryptionPattern // See media/base/encryption_pattern.h for description. struct EncryptionPattern {
diff --git a/media/mojo/interfaces/media_types.typemap b/media/mojo/interfaces/media_types.typemap index bf0f9778..ec45153 100644 --- a/media/mojo/interfaces/media_types.typemap +++ b/media/mojo/interfaces/media_types.typemap
@@ -15,6 +15,7 @@ "//media/base/encryption_scheme.h", "//media/base/hdr_metadata.h", "//media/base/media_log_event.h", + "//media/base/media_status.h", "//media/base/output_device_info.h", "//media/base/pipeline_status.h", "//media/base/sample_format.h", @@ -57,4 +58,5 @@ "media.mojom.WaitingReason=media::WaitingReason", "media.mojom.WatchTimeKey=media::WatchTimeKey", "media.mojom.EncryptionPattern=media::EncryptionPattern", + "media.mojom.MediaStatusState=media::MediaStatus::State", ]
diff --git a/media/mojo/interfaces/renderer.mojom b/media/mojo/interfaces/renderer.mojom index 3eada65..3b601e1 100644 --- a/media/mojo/interfaces/renderer.mojom +++ b/media/mojo/interfaces/renderer.mojom
@@ -94,4 +94,10 @@ // Executed the first time the metadata is updated, and whenever the duration // changes. OnDurationChange(mojo_base.mojom.TimeDelta duration); + + // Executed whenever a renderer receives notification of a status change that + // was not originated by its owner. + // Only used with the FlingingRenderer (when external devices play/pause the + // video playing remotely). + OnRemotePlayStateChange(MediaStatusState state); };
diff --git a/media/mojo/services/media_service_unittest.cc b/media/mojo/services/media_service_unittest.cc index fa8bdf7..b48c9f8 100644 --- a/media/mojo/services/media_service_unittest.cc +++ b/media/mojo/services/media_service_unittest.cc
@@ -108,6 +108,7 @@ void(const media::PipelineStatistics& stats)); MOCK_METHOD1(OnWaiting, void(WaitingReason)); MOCK_METHOD1(OnDurationChange, void(base::TimeDelta duration)); + MOCK_METHOD1(OnRemotePlayStateChange, void(MediaStatus::State state)); private: DISALLOW_COPY_AND_ASSIGN(MockRendererClient);
diff --git a/media/mojo/services/mojo_renderer_service.cc b/media/mojo/services/mojo_renderer_service.cc index fff62c4..7afa721 100644 --- a/media/mojo/services/mojo_renderer_service.cc +++ b/media/mojo/services/mojo_renderer_service.cc
@@ -195,6 +195,10 @@ client_->OnDurationChange(duration); } +void MojoRendererService::OnRemotePlayStateChange(MediaStatus::State state) { + client_->OnRemotePlayStateChange(state); +} + void MojoRendererService::OnVideoOpacityChange(bool opaque) { DVLOG(2) << __func__ << "(" << opaque << ")"; client_->OnVideoOpacityChange(opaque);
diff --git a/media/mojo/services/mojo_renderer_service.h b/media/mojo/services/mojo_renderer_service.h index 781e01dd..e188127 100644 --- a/media/mojo/services/mojo_renderer_service.h +++ b/media/mojo/services/mojo_renderer_service.h
@@ -92,6 +92,7 @@ void OnVideoNaturalSizeChange(const gfx::Size& size) final; void OnVideoOpacityChange(bool opaque) final; void OnDurationChange(base::TimeDelta duration) final; + void OnRemotePlayStateChange(MediaStatus::State state) final; // Called when the MediaResourceShim is ready to go (has a config, // pipe handle, etc) and can be handed off to a renderer for use.
diff --git a/media/remoting/courier_renderer_unittest.cc b/media/remoting/courier_renderer_unittest.cc index c56e653..1577138d 100644 --- a/media/remoting/courier_renderer_unittest.cc +++ b/media/remoting/courier_renderer_unittest.cc
@@ -92,6 +92,7 @@ MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size& size)); MOCK_METHOD1(OnVideoOpacityChange, void(bool opaque)); MOCK_METHOD1(OnDurationChange, void(base::TimeDelta duration)); + MOCK_METHOD1(OnRemotePlayStateChange, void(MediaStatus::State state)); void DelegateOnStatisticsUpdate(const PipelineStatistics& stats) { stats_ = stats;
diff --git a/media/remoting/receiver.cc b/media/remoting/receiver.cc index 37161ff..6d6134e 100644 --- a/media/remoting/receiver.cc +++ b/media/remoting/receiver.cc
@@ -326,5 +326,10 @@ rpc_broker_->SendMessageToRemote(std::move(rpc)); } +void Receiver::OnRemotePlayStateChange(MediaStatus::State state) { + // Only used with the FlingingRenderer. + NOTREACHED(); +} + } // namespace remoting } // namespace media
diff --git a/media/remoting/receiver.h b/media/remoting/receiver.h index 39e950c0..ca44ab99 100644 --- a/media/remoting/receiver.h +++ b/media/remoting/receiver.h
@@ -41,6 +41,7 @@ void OnVideoNaturalSizeChange(const gfx::Size& size) override; void OnVideoOpacityChange(bool opaque) override; void OnDurationChange(base::TimeDelta duration) override; + void OnRemotePlayStateChange(MediaStatus::State state) override; void OnReceivedRpc(std::unique_ptr<pb::RpcMessage> message); void OnReceivedBuffer(DemuxerStream::Type type,
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc index 58407ce..e637a842 100644 --- a/media/renderers/audio_renderer_impl_unittest.cc +++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -194,6 +194,7 @@ MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&)); MOCK_METHOD1(OnVideoOpacityChange, void(bool)); MOCK_METHOD1(OnDurationChange, void(base::TimeDelta)); + MOCK_METHOD1(OnRemotePlayStateChange, void(MediaStatus::State state)); void InitializeRenderer(DemuxerStream* demuxer_stream, const PipelineStatusCB& pipeline_status_cb) {
diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc index 339268e4..4f49abb 100644 --- a/media/renderers/renderer_impl.cc +++ b/media/renderers/renderer_impl.cc
@@ -72,6 +72,10 @@ // the DemuxerHost interface. NOTREACHED(); } + void OnRemotePlayStateChange(MediaStatus::State state) override { + // Only used with FlingingRenderer. + NOTREACHED(); + } private: DemuxerStream::Type type_;
diff --git a/media/test/data/README.md b/media/test/data/README.md index bdab1c95..b2e84eb0 100644 --- a/media/test/data/README.md +++ b/media/test/data/README.md
@@ -233,6 +233,10 @@ Actual video frames are the same as four-colors.mp4, except it specifies a rotation of 270 degrees in mp4 meta data. +#### four-colors-vp9.web +A 960x540 vp9 video with 4 color blocks (Y,R,G,B) in every frame. This is +converted from four-colors.mp4 by ffmpeg. + #### bear-320x180-hi10p.mp4 #### bear-320x240-vp9_profile2.webm VP9 encoded video with profile 2 (10-bit, 4:2:0).
diff --git a/media/test/data/four-colors-vp9.webm b/media/test/data/four-colors-vp9.webm new file mode 100644 index 0000000..b91e92f6 --- /dev/null +++ b/media/test/data/four-colors-vp9.webm Binary files differ
diff --git a/mojo/core/broker_host.cc b/mojo/core/broker_host.cc index 286562c..5e6b225 100644 --- a/mojo/core/broker_host.cc +++ b/mojo/core/broker_host.cc
@@ -115,10 +115,10 @@ region.PassPlatformHandle(), &h[0], &h[1]); handles[0] = PlatformHandleInTransit(std::move(h[0])); handles[1] = PlatformHandleInTransit(std::move(h[1])); -#if !defined(OS_POSIX) || defined(OS_ANDROID) || defined(OS_FUCHSIA) || \ +#if !defined(OS_POSIX) || defined(OS_ANDROID) || \ (defined(OS_MACOSX) && !defined(OS_IOS)) - // Non-POSIX systems, as well as Android, Fuchsia, and non-iOS Mac, only use - // a single handle to represent a writable region. + // Non-POSIX systems, as well as Android, and non-iOS Mac, only use a single + // handle to represent a writable region. DCHECK(!handles[1].handle().is_valid()); handles.resize(1); #else
diff --git a/mojo/core/broker_posix.cc b/mojo/core/broker_posix.cc index a2501af..6ac4d95 100644 --- a/mojo/core/broker_posix.cc +++ b/mojo/core/broker_posix.cc
@@ -111,10 +111,10 @@ return base::WritableSharedMemoryRegion(); } -#if !defined(OS_POSIX) || defined(OS_ANDROID) || defined(OS_FUCHSIA) || \ +#if !defined(OS_POSIX) || defined(OS_ANDROID) || \ (defined(OS_MACOSX) && !defined(OS_IOS)) - // Non-POSIX systems, as well as Android, Fuchsia, and non-iOS Mac, only use - // a single handle to represent a writable region. + // Non-POSIX systems, as well as Android, and non-iOS Mac, only use a single + // handle to represent a writable region. constexpr size_t kNumExpectedHandles = 1; #else constexpr size_t kNumExpectedHandles = 2;
diff --git a/mojo/public/cpp/bindings/tests/test_helpers_unittest.cc b/mojo/public/cpp/bindings/tests/test_helpers_unittest.cc index 4e304b2..9a69f74 100644 --- a/mojo/public/cpp/bindings/tests/test_helpers_unittest.cc +++ b/mojo/public/cpp/bindings/tests/test_helpers_unittest.cc
@@ -7,6 +7,7 @@ #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/system/message_pipe.h" #include "mojo/public/cpp/system/wait.h" +#include "mojo/public/interfaces/bindings/tests/ping_service.mojom-test-utils.h" #include "mojo/public/interfaces/bindings/tests/ping_service.mojom.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/mojo/public/java/system/javatests/AndroidManifest.xml b/mojo/public/java/system/javatests/AndroidManifest.xml index 56aabd8..8fad0c7c 100644 --- a/mojo/public/java/system/javatests/AndroidManifest.xml +++ b/mojo/public/java/system/javatests/AndroidManifest.xml
@@ -8,7 +8,7 @@ xmlns:tools="http://schemas.android.com/tools" package="org.chromium.mojo.tests"> - <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.INJECT_EVENTS" tools:ignore="ProtectedPermissions"/>
diff --git a/mojo/public/tools/bindings/BUILD.gn b/mojo/public/tools/bindings/BUILD.gn index b0ea6a8..de558a617 100644 --- a/mojo/public/tools/bindings/BUILD.gn +++ b/mojo/public/tools/bindings/BUILD.gn
@@ -21,6 +21,8 @@ "$mojom_generator_root/generators/cpp_templates/module-shared-message-ids.h.tmpl", "$mojom_generator_root/generators/cpp_templates/module-shared.cc.tmpl", "$mojom_generator_root/generators/cpp_templates/module-shared.h.tmpl", + "$mojom_generator_root/generators/cpp_templates/module-test-utils.cc.tmpl", + "$mojom_generator_root/generators/cpp_templates/module-test-utils.h.tmpl", "$mojom_generator_root/generators/cpp_templates/module.cc.tmpl", "$mojom_generator_root/generators/cpp_templates/module.h.tmpl", "$mojom_generator_root/generators/cpp_templates/struct_data_view_declaration.tmpl",
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl index d2416ab..f783cab 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
@@ -2,7 +2,7 @@ Macro for enum definition, and the declaration of associated functions. ---#} -{%- macro enum_decl(enum) %} +{%- macro enum_decl(enum, export_attribute) %} {%- set enum_name = enum|get_name_for_kind(flatten_nested_kind=True) %} enum class {{enum_name}} : int32_t { {%- for field in enum.fields %} @@ -20,7 +20,19 @@ {%- endif %} }; -inline std::ostream& operator<<(std::ostream& os, {{enum_name}} value) { +{{export_attribute}} std::ostream& operator<<(std::ostream& os, {{enum_name}} value); + +{#- Returns true if the given enum value exists in this version of enum. #} +inline bool IsKnownEnumValue({{enum_name}} value) { + return {{enum|get_name_for_kind(internal=True, + flatten_nested_kind=True)}}::IsKnownValue( + static_cast<int32_t>(value)); +} +{%- endmacro %} + +{%- macro enum_stream(enum) %} +{%- set enum_name = enum|get_name_for_kind(flatten_nested_kind=True) %} +std::ostream& operator<<(std::ostream& os, {{enum_name}} value) { {%- if enum.fields %} switch(value) { {%- for _, values in enum.fields|groupby('numeric_value') %} @@ -42,13 +54,6 @@ return os << "Unknown {{enum_name}} value: " << static_cast<int32_t>(value); {%- endif %} } - -{#- Returns true if the given enum value exists in this version of enum. #} -inline bool IsKnownEnumValue({{enum_name}} value) { - return {{enum|get_name_for_kind(internal=True, - flatten_nested_kind=True)}}::IsKnownValue( - static_cast<int32_t>(value)); -} {%- endmacro %} {%- macro enum_data_decl(enum) %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl index 78918ba0..51c106e 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl
@@ -62,29 +62,3 @@ virtual void {{method.name}}({{interface_macros.declare_request_params("", method)}}) = 0; {%- endfor %} }; - -{#--- Testing interceptor #} -class {{export_attribute}} {{interface.name}}InterceptorForTesting : public {{interface.name}} { - virtual {{interface.name}}* GetForwardingInterface() = 0; - -{%- for method in interface.methods %} - void {{method.name}}({{interface_macros.declare_request_params("", method)}}) override; -{%- endfor %} -}; - -{#--- Async wait helper for testing #} -class {{export_attribute}} {{interface.name}}AsyncWaiter { - public: - explicit {{interface.name}}AsyncWaiter({{interface.name}}* proxy); - ~{{interface.name}}AsyncWaiter(); - -{%- for method in interface.methods if method.response_parameters != None %} - void {{method.name}}( - {{interface_macros.declare_sync_method_params("", method)}}); -{%- endfor %} - - private: - {{interface.name}}* const proxy_; - - DISALLOW_COPY_AND_ASSIGN({{interface.name}}AsyncWaiter); -};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl index ddacf7f..12e67cb 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -591,53 +591,3 @@ return false; } {%- endif -%} - -{#--- Testing interceptor #} -{%- for method in interface.methods %} -void {{interface.name}}InterceptorForTesting::{{method.name}}({{interface_macros.declare_request_params("", method)}}) { - GetForwardingInterface()->{{method.name}}( - {%- for param in method.parameters -%} - std::move({{param.name}}){%- if not loop.last %}, {% endif %} - {%- endfor %} - {%- if method.response_parameters != None -%} - {%- if method.parameters %}, {% endif -%} - std::move(callback) - {%- endif -%} - ); -} -{%- endfor %} - -{#--- Async wait helper for testing #} -{{interface.name}}AsyncWaiter::{{interface.name}}AsyncWaiter( - {{interface.name}}* proxy) : proxy_(proxy) {} - -{{interface.name}}AsyncWaiter::~{{interface.name}}AsyncWaiter() = default; - -{% for method in interface.methods if method.response_parameters != None -%} -void {{interface.name}}AsyncWaiter::{{method.name}}( - {{interface_macros.declare_sync_method_params("", method)}}) { - base::RunLoop loop; - proxy_->{{method.name}}( -{%- for param in method.parameters -%} - std::move({{param.name}}), -{%- endfor %} - base::BindOnce( - [](base::RunLoop* loop -{%- for param in method.response_parameters -%}, - {{param.kind|cpp_wrapper_call_type}}* out_{{param.name}} -{% endfor -%} -{%- for param in method.response_parameters -%}, - {{param.kind|cpp_wrapper_param_type}} {{param.name}} -{%- endfor %}) { -{%- for param in method.response_parameters -%} - *out_{{param.name}} = std::move({{param.name}}); -{%- endfor %} - loop->Quit(); - }, - &loop -{%- for param in method.response_parameters -%}, - out_{{param.name}} -{%- endfor %})); - loop.Run(); -} -{% endfor %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl index 357d850..c1a12f3 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
@@ -26,6 +26,14 @@ namespace {{namespace}} { {%- endfor %} +{#--- Enums #} +{%- from "enum_macros.tmpl" import enum_stream %} +{%- for enum in all_enums %} +{%- if not enum|is_native_only_kind %} +{{enum_stream(enum)}} +{%- endif %} +{%- endfor %} + namespace internal { {#--- Union definitions #} @@ -61,4 +69,3 @@ #if defined(_MSC_VER) #pragma warning(pop) #endif -
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl index 1ff771d24..017f06d0 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl
@@ -111,7 +111,7 @@ {%- if enum|is_native_only_kind %} using {{enum|get_name_for_kind(flatten_nested_kind=True)}} = mojo::NativeEnum; {%- else %} -{{enum_decl(enum)}} +{{enum_decl(enum, export_attribute)}} {%- endif %} {%- endfor %} @@ -221,4 +221,3 @@ {{namespace_end()}} #endif // {{header_guard}} -
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-test-utils.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-test-utils.cc.tmpl new file mode 100644 index 0000000..a7ea114a --- /dev/null +++ b/mojo/public/tools/bindings/generators/cpp_templates/module-test-utils.cc.tmpl
@@ -0,0 +1,127 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +{%- if variant -%} +{%- set variant_path = "%s-%s"|format(module.path, variant) -%} +{%- else -%} +{%- set variant_path = module.path -%} +{%- endif %} + +{%- set header_guard_for_jumbo = "%s_JUMBO_H_"|format( + variant_path|upper|replace("/","_")|replace(".","_")| + replace("-", "_")) %} + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-private-field" +#elif defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4056) +#pragma warning(disable:4065) +#pragma warning(disable:4756) +#endif + +{%- macro namespace_begin() %} +{%- for namespace in namespaces_as_array %} +namespace {{namespace}} { +{%- endfor %} +{%- if variant %} +namespace {{variant}} { +{%- endif %} +{%- endmacro %} + +{%- macro namespace_end() %} +{%- if variant %} +} // namespace {{variant}} +{%- endif %} +{%- for namespace in namespaces_as_array|reverse %} +} // namespace {{namespace}} +{%- endfor %} +{%- endmacro %} + + +#include "{{variant_path}}-test-utils.h" + +#include <utility> + +#include "base/bind.h" +#include "base/run_loop.h" + +{%- if for_blink %} +#include "mojo/public/cpp/bindings/lib/wtf_serialization.h" +{%- endif %} + +{# This is include guard for jumbo build. #} +#ifndef {{header_guard_for_jumbo}} +#define {{header_guard_for_jumbo}} +{%- for header in extra_traits_headers %} +#include "{{header}}" +{%- endfor %} +#endif + +{{namespace_begin()}} + +{%- import "interface_macros.tmpl" as interface_macros %} + +{% for interface in interfaces %} + +{#--- Testing interceptor #} +{%- for method in interface.methods %} +void {{interface.name}}InterceptorForTesting::{{method.name}}({{interface_macros.declare_request_params("", method)}}) { + GetForwardingInterface()->{{method.name}}( + {%- for param in method.parameters -%} + std::move({{param.name}}){%- if not loop.last %}, {% endif %} + {%- endfor %} + {%- if method.response_parameters != None -%} + {%- if method.parameters %}, {% endif -%} + std::move(callback) + {%- endif -%} + ); +} +{%- endfor %} + +{#--- Async wait helper for testing #} +{{interface.name}}AsyncWaiter::{{interface.name}}AsyncWaiter( + {{interface.name}}* proxy) : proxy_(proxy) {} + +{{interface.name}}AsyncWaiter::~{{interface.name}}AsyncWaiter() = default; + +{% for method in interface.methods if method.response_parameters != None -%} +void {{interface.name}}AsyncWaiter::{{method.name}}( + {{interface_macros.declare_sync_method_params("", method)}}) { + base::RunLoop loop; + proxy_->{{method.name}}( +{%- for param in method.parameters -%} + std::move({{param.name}}), +{%- endfor %} + base::BindOnce( + [](base::RunLoop* loop +{%- for param in method.response_parameters -%}, + {{param.kind|cpp_wrapper_call_type}}* out_{{param.name}} +{% endfor -%} +{%- for param in method.response_parameters -%}, + {{param.kind|cpp_wrapper_param_type}} {{param.name}} +{%- endfor %}) { +{%- for param in method.response_parameters -%} + *out_{{param.name}} = std::move({{param.name}}); +{%- endfor %} + loop->Quit(); + }, + &loop +{%- for param in method.response_parameters -%}, + out_{{param.name}} +{%- endfor %})); + loop.Run(); +} +{% endfor %} + +{% endfor %} + +{{namespace_end()}} + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(_MSC_VER) +#pragma warning(pop) +#endif \ No newline at end of file
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-test-utils.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-test-utils.h.tmpl new file mode 100644 index 0000000..89403243 --- /dev/null +++ b/mojo/public/tools/bindings/generators/cpp_templates/module-test-utils.h.tmpl
@@ -0,0 +1,79 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +{%- if variant -%} +{%- set variant_path = "%s-%s"|format(module.path, variant) -%} +{%- else -%} +{%- set variant_path = module.path -%} +{%- endif -%} + +{%- set header_guard = "%s_TEST_UTILS_H_"|format( + variant_path|upper|replace("/","_")|replace(".","_")| + replace("-", "_")) %} + + +{%- macro namespace_begin() %} +{%- for namespace in namespaces_as_array %} +namespace {{namespace}} { +{%- endfor %} +{%- if variant %} +namespace {{variant}} { +{%- endif %} +{%- endmacro %} + +{%- macro namespace_end() %} +{%- if variant %} +} // namespace {{variant}} +{%- endif %} +{%- for namespace in namespaces_as_array|reverse %} +} // namespace {{namespace}} +{%- endfor %} +{%- endmacro %} + +#ifndef {{header_guard}} +#define {{header_guard}} + +#include "{{variant_path}}.h" + +{%- if export_header %} +#include "{{export_header}}" +{%- endif %} + +{{namespace_begin()}} + +{%- import "interface_macros.tmpl" as interface_macros %} + +{% for interface in interfaces %} + +{#--- Testing interceptor #} +class {{export_attribute}} {{interface.name}}InterceptorForTesting : public {{interface.name}} { + virtual {{interface.name}}* GetForwardingInterface() = 0; + +{%- for method in interface.methods %} + void {{method.name}}({{interface_macros.declare_request_params("", method)}}) override; +{%- endfor %} +}; + +{#--- Async wait helper for testing #} +class {{export_attribute}} {{interface.name}}AsyncWaiter { + public: + explicit {{interface.name}}AsyncWaiter({{interface.name}}* proxy); + ~{{interface.name}}AsyncWaiter(); + +{%- for method in interface.methods if method.response_parameters != None %} + void {{method.name}}( + {{interface_macros.declare_sync_method_params("", method)}}); +{%- endfor %} + + private: + {{interface.name}}* const proxy_; + + DISALLOW_COPY_AND_ASSIGN({{interface.name}}AsyncWaiter); +}; + +{% endfor %} + +{{namespace_end()}} + +#endif // {{header_guard}}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl index 16f3baf..467f2b8 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
@@ -8,6 +8,10 @@ {%- set variant_path = module.path -%} {%- endif %} +{%- set header_guard_for_jumbo = "%s_JUMBO_H_"|format( + variant_path|upper|replace("/","_")|replace(".","_")| + replace("-", "_")) %} + #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" @@ -40,9 +44,13 @@ #include "mojo/public/cpp/bindings/lib/wtf_serialization.h" {%- endif %} +{# This is include guard for jumbo build. #} +#ifndef {{header_guard_for_jumbo}} +#define {{header_guard_for_jumbo}} {%- for header in extra_traits_headers %} #include "{{header}}" {%- endfor %} +#endif {%- for namespace in namespaces_as_array %} namespace {{namespace}} {
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py index 3b8f0fa..8c5dd88 100644 --- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -396,6 +396,14 @@ def _GenerateModuleSharedSource(self): return self._GetJinjaExports() + @UseJinja("module-test-utils.h.tmpl") + def _GenerateModuleTestUtilsHeader(self): + return self._GetJinjaExports() + + @UseJinja("module-test-utils.cc.tmpl") + def _GenerateModuleTestUtilsSource(self): + return self._GetJinjaExports() + def GenerateFiles(self, args): self.module.Stylize(generator.Stylizer()) @@ -416,6 +424,10 @@ "%s%s.h" % (self.module.path, suffix)) self.Write(self._GenerateModuleSource(), "%s%s.cc" % (self.module.path, suffix)) + self.Write(self._GenerateModuleTestUtilsHeader(), + "%s%s-test-utils.h" % (self.module.path, suffix)) + self.Write(self._GenerateModuleTestUtilsSource(), + "%s%s-test-utils.cc" % (self.module.path, suffix)) def _ConstantValue(self, constant): return self._ExpressionToText(constant.value, kind=constant.kind)
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni index 85eba84..4fe4e4b 100644 --- a/mojo/public/tools/bindings/mojom.gni +++ b/mojo/public/tools/bindings/mojom.gni
@@ -754,6 +754,8 @@ generator_cpp_outputs += [ "{{source_gen_dir}}/{{source_file_part}}${variant_dash_suffix}.cc", "{{source_gen_dir}}/{{source_file_part}}${variant_dash_suffix}.h", + "{{source_gen_dir}}/{{source_file_part}}${variant_dash_suffix}-test-utils.cc", + "{{source_gen_dir}}/{{source_file_part}}${variant_dash_suffix}-test-utils.h", ] enabled_sources = [] if (defined(bindings_configuration.blacklist)) { @@ -828,6 +830,8 @@ outputs += [ "$target_gen_dir/${source}${variant_dash_suffix}.cc", "$target_gen_dir/${source}${variant_dash_suffix}.h", + "$target_gen_dir/${source}${variant_dash_suffix}-test-utils.cc", + "$target_gen_dir/${source}${variant_dash_suffix}-test-utils.h", ] }
diff --git a/net/BUILD.gn b/net/BUILD.gn index 5983df95..35012c3 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -788,6 +788,7 @@ "http/http_chunked_decoder.h", "http/http_content_disposition.cc", "http/http_content_disposition.h", + "http/http_negotiate_auth_system.h", "http/http_network_layer.cc", "http/http_network_layer.h", "http/http_network_session.cc", @@ -1095,6 +1096,25 @@ "spdy/multiplexed_http_stream.h", "spdy/multiplexed_session.cc", "spdy/multiplexed_session.h", + "spdy/platform/impl/spdy_arraysize_impl.h", + "spdy/platform/impl/spdy_bug_tracker_impl.h", + "spdy/platform/impl/spdy_containers_impl.h", + "spdy/platform/impl/spdy_endianness_util_impl.h", + "spdy/platform/impl/spdy_estimate_memory_usage_impl.h", + "spdy/platform/impl/spdy_export_impl.h", + "spdy/platform/impl/spdy_flags_impl.cc", + "spdy/platform/impl/spdy_flags_impl.h", + "spdy/platform/impl/spdy_macros_impl.h", + "spdy/platform/impl/spdy_mem_slice_impl.cc", + "spdy/platform/impl/spdy_mem_slice_impl.h", + "spdy/platform/impl/spdy_ptr_util_impl.h", + "spdy/platform/impl/spdy_string_impl.h", + "spdy/platform/impl/spdy_string_piece_impl.h", + "spdy/platform/impl/spdy_string_utils_impl.cc", + "spdy/platform/impl/spdy_string_utils_impl.h", + "spdy/platform/impl/spdy_test_utils_prod_impl.h", + "spdy/platform/impl/spdy_unsafe_arena_impl.cc", + "spdy/platform/impl/spdy_unsafe_arena_impl.h", "spdy/server_push_delegate.h", "spdy/spdy_buffer.cc", "spdy/spdy_buffer.h", @@ -1454,6 +1474,7 @@ "third_party/quic/platform/api/quic_aligned.h", "third_party/quic/platform/api/quic_arraysize.h", "third_party/quic/platform/api/quic_bug_tracker.h", + "third_party/quic/platform/api/quic_cert_utils.h", "third_party/quic/platform/api/quic_client_stats.h", "third_party/quic/platform/api/quic_clock.cc", "third_party/quic/platform/api/quic_clock.h", @@ -1499,6 +1520,7 @@ "third_party/quic/platform/impl/quic_aligned_impl.h", "third_party/quic/platform/impl/quic_arraysize_impl.h", "third_party/quic/platform/impl/quic_bug_tracker_impl.h", + "third_party/quic/platform/impl/quic_cert_utils_impl.h", "third_party/quic/platform/impl/quic_chromium_clock.cc", "third_party/quic/platform/impl/quic_chromium_clock.h", "third_party/quic/platform/impl/quic_client_stats_impl.h", @@ -1646,79 +1668,60 @@ "third_party/quiche/src/http2/platform/api/http2_string.h", "third_party/quiche/src/http2/platform/api/http2_string_piece.h", "third_party/quiche/src/http2/platform/api/http2_string_utils.h", - "third_party/spdy/core/hpack/hpack_constants.cc", - "third_party/spdy/core/hpack/hpack_constants.h", - "third_party/spdy/core/hpack/hpack_decoder_adapter.cc", - "third_party/spdy/core/hpack/hpack_decoder_adapter.h", - "third_party/spdy/core/hpack/hpack_encoder.cc", - "third_party/spdy/core/hpack/hpack_encoder.h", - "third_party/spdy/core/hpack/hpack_entry.cc", - "third_party/spdy/core/hpack/hpack_entry.h", - "third_party/spdy/core/hpack/hpack_header_table.cc", - "third_party/spdy/core/hpack/hpack_header_table.h", - "third_party/spdy/core/hpack/hpack_huffman_table.cc", - "third_party/spdy/core/hpack/hpack_huffman_table.h", - "third_party/spdy/core/hpack/hpack_output_stream.cc", - "third_party/spdy/core/hpack/hpack_output_stream.h", - "third_party/spdy/core/hpack/hpack_static_table.cc", - "third_party/spdy/core/hpack/hpack_static_table.h", - "third_party/spdy/core/http2_frame_decoder_adapter.cc", - "third_party/spdy/core/http2_frame_decoder_adapter.h", - "third_party/spdy/core/priority_write_scheduler.h", - "third_party/spdy/core/spdy_alt_svc_wire_format.cc", - "third_party/spdy/core/spdy_alt_svc_wire_format.h", - "third_party/spdy/core/spdy_bitmasks.h", - "third_party/spdy/core/spdy_frame_builder.cc", - "third_party/spdy/core/spdy_frame_builder.h", - "third_party/spdy/core/spdy_frame_reader.cc", - "third_party/spdy/core/spdy_frame_reader.h", - "third_party/spdy/core/spdy_framer.cc", - "third_party/spdy/core/spdy_framer.h", - "third_party/spdy/core/spdy_header_block.cc", - "third_party/spdy/core/spdy_header_block.h", - "third_party/spdy/core/spdy_headers_handler_interface.h", - "third_party/spdy/core/spdy_pinnable_buffer_piece.cc", - "third_party/spdy/core/spdy_pinnable_buffer_piece.h", - "third_party/spdy/core/spdy_prefixed_buffer_reader.cc", - "third_party/spdy/core/spdy_prefixed_buffer_reader.h", - "third_party/spdy/core/spdy_protocol.cc", - "third_party/spdy/core/spdy_protocol.h", - "third_party/spdy/core/write_scheduler.h", - "third_party/spdy/core/zero_copy_output_buffer.h", - "third_party/spdy/platform/api/spdy_arraysize.h", - "third_party/spdy/platform/api/spdy_bug_tracker.h", - "third_party/spdy/platform/api/spdy_containers.h", - "third_party/spdy/platform/api/spdy_endianness_util.h", - "third_party/spdy/platform/api/spdy_estimate_memory_usage.h", - "third_party/spdy/platform/api/spdy_export.h", - "third_party/spdy/platform/api/spdy_flags.h", - "third_party/spdy/platform/api/spdy_macros.h", - "third_party/spdy/platform/api/spdy_mem_slice.h", - "third_party/spdy/platform/api/spdy_ptr_util.h", - "third_party/spdy/platform/api/spdy_string.h", - "third_party/spdy/platform/api/spdy_string_piece.h", - "third_party/spdy/platform/api/spdy_string_utils.h", - "third_party/spdy/platform/api/spdy_test_utils_prod.h", - "third_party/spdy/platform/api/spdy_unsafe_arena.h", - "third_party/spdy/platform/impl/spdy_arraysize_impl.h", - "third_party/spdy/platform/impl/spdy_bug_tracker_impl.h", - "third_party/spdy/platform/impl/spdy_containers_impl.h", - "third_party/spdy/platform/impl/spdy_endianness_util_impl.h", - "third_party/spdy/platform/impl/spdy_estimate_memory_usage_impl.h", - "third_party/spdy/platform/impl/spdy_export_impl.h", - "third_party/spdy/platform/impl/spdy_flags_impl.cc", - "third_party/spdy/platform/impl/spdy_flags_impl.h", - "third_party/spdy/platform/impl/spdy_macros_impl.h", - "third_party/spdy/platform/impl/spdy_mem_slice_impl.cc", - "third_party/spdy/platform/impl/spdy_mem_slice_impl.h", - "third_party/spdy/platform/impl/spdy_ptr_util_impl.h", - "third_party/spdy/platform/impl/spdy_string_impl.h", - "third_party/spdy/platform/impl/spdy_string_piece_impl.h", - "third_party/spdy/platform/impl/spdy_string_utils_impl.cc", - "third_party/spdy/platform/impl/spdy_string_utils_impl.h", - "third_party/spdy/platform/impl/spdy_test_utils_prod_impl.h", - "third_party/spdy/platform/impl/spdy_unsafe_arena_impl.cc", - "third_party/spdy/platform/impl/spdy_unsafe_arena_impl.h", + "third_party/quiche/src/spdy/core/hpack/hpack_constants.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_constants.h", + "third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h", + "third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_encoder.h", + "third_party/quiche/src/spdy/core/hpack/hpack_entry.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_entry.h", + "third_party/quiche/src/spdy/core/hpack/hpack_header_table.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_header_table.h", + "third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h", + "third_party/quiche/src/spdy/core/hpack/hpack_output_stream.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h", + "third_party/quiche/src/spdy/core/hpack/hpack_static_table.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_static_table.h", + "third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.cc", + "third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h", + "third_party/quiche/src/spdy/core/priority_write_scheduler.h", + "third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.cc", + "third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h", + "third_party/quiche/src/spdy/core/spdy_bitmasks.h", + "third_party/quiche/src/spdy/core/spdy_frame_builder.cc", + "third_party/quiche/src/spdy/core/spdy_frame_builder.h", + "third_party/quiche/src/spdy/core/spdy_frame_reader.cc", + "third_party/quiche/src/spdy/core/spdy_frame_reader.h", + "third_party/quiche/src/spdy/core/spdy_framer.cc", + "third_party/quiche/src/spdy/core/spdy_framer.h", + "third_party/quiche/src/spdy/core/spdy_header_block.cc", + "third_party/quiche/src/spdy/core/spdy_header_block.h", + "third_party/quiche/src/spdy/core/spdy_headers_handler_interface.h", + "third_party/quiche/src/spdy/core/spdy_pinnable_buffer_piece.cc", + "third_party/quiche/src/spdy/core/spdy_pinnable_buffer_piece.h", + "third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader.cc", + "third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader.h", + "third_party/quiche/src/spdy/core/spdy_protocol.cc", + "third_party/quiche/src/spdy/core/spdy_protocol.h", + "third_party/quiche/src/spdy/core/write_scheduler.h", + "third_party/quiche/src/spdy/core/zero_copy_output_buffer.h", + "third_party/quiche/src/spdy/platform/api/spdy_arraysize.h", + "third_party/quiche/src/spdy/platform/api/spdy_bug_tracker.h", + "third_party/quiche/src/spdy/platform/api/spdy_containers.h", + "third_party/quiche/src/spdy/platform/api/spdy_endianness_util.h", + "third_party/quiche/src/spdy/platform/api/spdy_estimate_memory_usage.h", + "third_party/quiche/src/spdy/platform/api/spdy_export.h", + "third_party/quiche/src/spdy/platform/api/spdy_flags.h", + "third_party/quiche/src/spdy/platform/api/spdy_macros.h", + "third_party/quiche/src/spdy/platform/api/spdy_mem_slice.h", + "third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h", + "third_party/quiche/src/spdy/platform/api/spdy_string.h", + "third_party/quiche/src/spdy/platform/api/spdy_string_piece.h", + "third_party/quiche/src/spdy/platform/api/spdy_string_utils.h", + "third_party/quiche/src/spdy/platform/api/spdy_test_utils_prod.h", + "third_party/quiche/src/spdy/platform/api/spdy_unsafe_arena.h", "url_request/data_protocol_handler.cc", "url_request/data_protocol_handler.h", "url_request/http_user_agent_settings.h", @@ -2011,6 +2014,7 @@ "base/network_change_notifier_fuchsia.cc", "base/network_change_notifier_fuchsia.h", "base/network_interfaces_fuchsia.cc", + "base/network_interfaces_fuchsia.h", "base/platform_mime_util_fuchsia.cc", "cert/test_root_certs_fuchsia.cc", ] @@ -5048,6 +5052,8 @@ "spdy/header_coalescer_test.cc", "spdy/http2_priority_dependencies_unittest.cc", "spdy/http2_push_promise_index_test.cc", + "spdy/platform/impl/spdy_test_helpers_impl.h", + "spdy/platform/impl/spdy_unsafe_arena_impl_test.cc", "spdy/spdy_buffer_unittest.cc", "spdy/spdy_http_stream_unittest.cc", "spdy/spdy_http_utils_unittest.cc", @@ -5159,6 +5165,7 @@ "third_party/quic/core/quic_connection_id_test.cc", "third_party/quic/core/quic_connection_test.cc", "third_party/quic/core/quic_control_frame_manager_test.cc", + "third_party/quic/core/quic_crypto_client_handshaker_test.cc", "third_party/quic/core/quic_crypto_client_stream_test.cc", "third_party/quic/core/quic_crypto_server_stream_test.cc", "third_party/quic/core/quic_crypto_stream_test.cc", @@ -5296,42 +5303,40 @@ "third_party/quiche/src/http2/tools/random_decoder_test.h", "third_party/quiche/src/http2/tools/random_util.cc", "third_party/quiche/src/http2/tools/random_util.h", - "third_party/spdy/core/array_output_buffer.cc", - "third_party/spdy/core/array_output_buffer.h", - "third_party/spdy/core/array_output_buffer_test.cc", - "third_party/spdy/core/hpack/hpack_decoder_adapter_test.cc", - "third_party/spdy/core/hpack/hpack_encoder_test.cc", - "third_party/spdy/core/hpack/hpack_entry_test.cc", - "third_party/spdy/core/hpack/hpack_header_table_test.cc", - "third_party/spdy/core/hpack/hpack_huffman_table_test.cc", - "third_party/spdy/core/hpack/hpack_output_stream_test.cc", - "third_party/spdy/core/hpack/hpack_round_trip_test.cc", - "third_party/spdy/core/hpack/hpack_static_table_test.cc", - "third_party/spdy/core/mock_spdy_framer_visitor.cc", - "third_party/spdy/core/mock_spdy_framer_visitor.h", - "third_party/spdy/core/priority_write_scheduler_test.cc", - "third_party/spdy/core/spdy_alt_svc_wire_format_test.cc", - "third_party/spdy/core/spdy_deframer_visitor.cc", - "third_party/spdy/core/spdy_deframer_visitor.h", - "third_party/spdy/core/spdy_deframer_visitor_test.cc", - "third_party/spdy/core/spdy_frame_builder_test.cc", - "third_party/spdy/core/spdy_frame_reader_test.cc", - "third_party/spdy/core/spdy_framer_test.cc", - "third_party/spdy/core/spdy_header_block_test.cc", - "third_party/spdy/core/spdy_no_op_visitor.cc", - "third_party/spdy/core/spdy_no_op_visitor.h", - "third_party/spdy/core/spdy_pinnable_buffer_piece_test.cc", - "third_party/spdy/core/spdy_prefixed_buffer_reader_test.cc", - "third_party/spdy/core/spdy_protocol_test.cc", - "third_party/spdy/core/spdy_protocol_test_utils.cc", - "third_party/spdy/core/spdy_protocol_test_utils.h", - "third_party/spdy/core/spdy_test_utils.cc", - "third_party/spdy/core/spdy_test_utils.h", - "third_party/spdy/platform/api/spdy_mem_slice_test.cc", - "third_party/spdy/platform/api/spdy_string_utils_test.cc", - "third_party/spdy/platform/api/spdy_test_helpers.h", - "third_party/spdy/platform/impl/spdy_test_helpers_impl.h", - "third_party/spdy/platform/impl/spdy_unsafe_arena_impl_test.cc", + "third_party/quiche/src/spdy/core/array_output_buffer.cc", + "third_party/quiche/src/spdy/core/array_output_buffer.h", + "third_party/quiche/src/spdy/core/array_output_buffer_test.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter_test.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_entry_test.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_header_table_test.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_test.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_output_stream_test.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_round_trip_test.cc", + "third_party/quiche/src/spdy/core/hpack/hpack_static_table_test.cc", + "third_party/quiche/src/spdy/core/mock_spdy_framer_visitor.cc", + "third_party/quiche/src/spdy/core/mock_spdy_framer_visitor.h", + "third_party/quiche/src/spdy/core/priority_write_scheduler_test.cc", + "third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format_test.cc", + "third_party/quiche/src/spdy/core/spdy_deframer_visitor.cc", + "third_party/quiche/src/spdy/core/spdy_deframer_visitor.h", + "third_party/quiche/src/spdy/core/spdy_deframer_visitor_test.cc", + "third_party/quiche/src/spdy/core/spdy_frame_builder_test.cc", + "third_party/quiche/src/spdy/core/spdy_frame_reader_test.cc", + "third_party/quiche/src/spdy/core/spdy_framer_test.cc", + "third_party/quiche/src/spdy/core/spdy_header_block_test.cc", + "third_party/quiche/src/spdy/core/spdy_no_op_visitor.cc", + "third_party/quiche/src/spdy/core/spdy_no_op_visitor.h", + "third_party/quiche/src/spdy/core/spdy_pinnable_buffer_piece_test.cc", + "third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader_test.cc", + "third_party/quiche/src/spdy/core/spdy_protocol_test.cc", + "third_party/quiche/src/spdy/core/spdy_protocol_test_utils.cc", + "third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h", + "third_party/quiche/src/spdy/core/spdy_test_utils.cc", + "third_party/quiche/src/spdy/core/spdy_test_utils.h", + "third_party/quiche/src/spdy/platform/api/spdy_mem_slice_test.cc", + "third_party/quiche/src/spdy/platform/api/spdy_string_utils_test.cc", + "third_party/quiche/src/spdy/platform/api/spdy_test_helpers.h", "third_party/uri_template/uri_template_test.cc", "tools/content_decoder_tool/content_decoder_tool.cc", "tools/content_decoder_tool/content_decoder_tool.h",
diff --git a/net/android/http_auth_negotiate_android.cc b/net/android/http_auth_negotiate_android.cc index 98bd29ce..836b0f4 100644 --- a/net/android/http_auth_negotiate_android.cc +++ b/net/android/http_auth_negotiate_android.cc
@@ -43,7 +43,9 @@ const JavaParamRef<jstring>& token) { // This will be called on the UI thread, so we have to post a task back to the // correct thread to actually save the result - std::string raw_token = ConvertJavaStringToUTF8(env, token); + std::string raw_token; + if (token.obj()) + raw_token = ConvertJavaStringToUTF8(env, token); // Always post, even if we are on the same thread. This guarantees that the // result will be delayed until after the request has completed, which // simplifies the logic. In practice the result will only ever come back on @@ -65,8 +67,7 @@ weak_factory_(this) { JNIEnv* env = AttachCurrentThread(); java_authenticator_.Reset(Java_HttpNegotiateAuthenticator_create( - env, - ConvertUTF8ToJavaString(env, prefs->AuthAndroidNegotiateAccountType()))); + env, ConvertUTF8ToJavaString(env, GetAuthAndroidNegotiateAccountType()))); } HttpAuthNegotiateAndroid::~HttpAuthNegotiateAndroid() { @@ -101,7 +102,7 @@ const std::string& channel_bindings, std::string* auth_token, net::CompletionOnceCallback callback) { - if (prefs_->AuthAndroidNegotiateAccountType().empty()) { + if (GetAuthAndroidNegotiateAccountType().empty()) { // This can happen if there is a policy change, removing the account type, // in the middle of a negotiation. return ERR_UNSUPPORTED_AUTH_SCHEME; @@ -121,8 +122,6 @@ ScopedJavaLocalRef<jstring> java_server_auth_token = ConvertUTF8ToJavaString(env, server_auth_token_); ScopedJavaLocalRef<jstring> java_spn = ConvertUTF8ToJavaString(env, spn); - ScopedJavaLocalRef<jstring> java_account_type = - ConvertUTF8ToJavaString(env, prefs_->AuthAndroidNegotiateAccountType()); // It is intentional that callback_wrapper is not owned or deleted by the // HttpAuthNegotiateAndroid object. The Java code will call the callback @@ -145,13 +144,18 @@ can_delegate_ = true; } +std::string HttpAuthNegotiateAndroid::GetAuthAndroidNegotiateAccountType() + const { + return prefs_->AuthAndroidNegotiateAccountType(); +} + void HttpAuthNegotiateAndroid::SetResultInternal(int result, const std::string& raw_token) { DCHECK(auth_token_); DCHECK(!completion_callback_.is_null()); if (result == OK) *auth_token_ = "Negotiate " + raw_token; - base::ResetAndReturn(&completion_callback_).Run(result); + std::move(completion_callback_).Run(result); } } // namespace android
diff --git a/net/android/http_auth_negotiate_android.h b/net/android/http_auth_negotiate_android.h index 6ede740f..1af5aba 100644 --- a/net/android/http_auth_negotiate_android.h +++ b/net/android/http_auth_negotiate_android.h
@@ -17,6 +17,7 @@ #include "net/base/completion_once_callback.h" #include "net/base/net_export.h" #include "net/http/http_auth.h" +#include "net/http/http_negotiate_auth_system.h" namespace base { class TaskRunner; @@ -63,61 +64,37 @@ // provides a bridge to the Java code, and hence to the service. See // https://drive.google.com/open?id=1G7WAaYEKMzj16PTHT_cIYuKXJG6bBcrQ7QQBQ6ihOcQ&authuser=1 // for the full details. -class NET_EXPORT_PRIVATE HttpAuthNegotiateAndroid { +class NET_EXPORT_PRIVATE HttpAuthNegotiateAndroid + : public HttpNegotiateAuthSystem { public: // Creates an object for one negotiation session. |prefs| are the // authentication preferences. In particular they include the Android account // type, which is used to connect to the correct Android Authenticator. explicit HttpAuthNegotiateAndroid(const HttpAuthPreferences* prefs); - ~HttpAuthNegotiateAndroid(); + ~HttpAuthNegotiateAndroid() override; - // Does nothing, but needed for compatibility with the Negotiate - // authenticators for other O.S.. Always returns true. - bool Init(); - - // True if authentication needs the identity of the user from Chrome. - bool NeedsIdentity() const; - - // True authentication can use explicit credentials included in the URL. - bool AllowsExplicitCredentials() const; - - // Parse a received Negotiate challenge. + // HttpNegotiateAuthSystem implementation: + bool Init() override; + bool NeedsIdentity() const override; + bool AllowsExplicitCredentials() const override; HttpAuth::AuthorizationResult ParseChallenge( - net::HttpAuthChallengeTokenizer* tok); - - // Generates an authentication token. - // - // The return value is an error code. The authentication token will be - // returned in |*auth_token|. If the result code is not |OK|, the value of - // |*auth_token| is unspecified. - // - // If the operation cannot be completed synchronously, |ERR_IO_PENDING| will - // be returned and the real result code will be passed to the completion - // callback. Otherwise the result code is returned immediately from this - // call. - // - // If the AndroidAuthNegotiate object is deleted before completion then the - // callback will not be called. - // - // If no immediate result is returned then |auth_token| must remain valid - // until the callback has been called. - // - // |spn| is the Service Principal Name of the server that the token is - // being generated for. - // - // If this is the first round of a multiple round scheme, credentials are - // obtained using |*credentials|. If |credentials| is NULL, the default - // credentials are used instead. + HttpAuthChallengeTokenizer* tok) override; int GenerateAuthToken(const AuthCredentials* credentials, const std::string& spn, const std::string& channel_bindings, std::string* auth_token, - net::CompletionOnceCallback callback); + CompletionOnceCallback callback) override; + void Delegate() override; - // Delegation is allowed on the Kerberos ticket. This allows certain servers - // to act as the user, such as an IIS server retrieving data from a - // Kerberized MSSQL server. - void Delegate(); + bool can_delegate() const { return can_delegate_; } + void set_can_delegate(bool can_delegate) { can_delegate_ = can_delegate; } + + const std::string& server_auth_token() const { return server_auth_token_; } + void set_server_auth_token(const std::string& server_auth_token) { + server_auth_token_ = server_auth_token; + } + + std::string GetAuthAndroidNegotiateAccountType() const; private: void SetResultInternal(int result, const std::string& token);
diff --git a/net/android/unittest_support/AndroidManifest.xml b/net/android/unittest_support/AndroidManifest.xml index 9293618..e9175e9f 100644 --- a/net/android/unittest_support/AndroidManifest.xml +++ b/net/android/unittest_support/AndroidManifest.xml
@@ -10,7 +10,7 @@ android:versionCode="1" android:versionName="1.0"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
diff --git a/net/base/network_change_notifier.cc b/net/base/network_change_notifier.cc index 10d9cdcd..a4c5486 100644 --- a/net/base/network_change_notifier.cc +++ b/net/base/network_change_notifier.cc
@@ -219,7 +219,7 @@ #elif defined(OS_MACOSX) return new NetworkChangeNotifierMac(); #elif defined(OS_FUCHSIA) - return new NetworkChangeNotifierFuchsia(); + return new NetworkChangeNotifierFuchsia(0 /* required_features */); #else NOTIMPLEMENTED(); return NULL;
diff --git a/net/base/network_change_notifier_fuchsia.cc b/net/base/network_change_notifier_fuchsia.cc index 1136e05..f3b0005a 100644 --- a/net/base/network_change_notifier_fuchsia.cc +++ b/net/base/network_change_notifier_fuchsia.cc
@@ -37,14 +37,17 @@ } // namespace -NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia() +NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia( + uint32_t required_features) : NetworkChangeNotifierFuchsia( base::fuchsia::ComponentContext::GetDefault() - ->ConnectToService<fuchsia::netstack::Netstack>()) {} + ->ConnectToService<fuchsia::netstack::Netstack>(), + required_features) {} NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia( - fuchsia::netstack::NetstackPtr netstack) - : netstack_(std::move(netstack)) { + fuchsia::netstack::NetstackPtr netstack, + uint32_t required_features) + : netstack_(std::move(netstack)), required_features_(required_features) { DCHECK(netstack_); netstack_.set_error_handler([](zx_status_t status) { @@ -90,39 +93,52 @@ base::OnceClosure on_initialized_cb, std::vector<fuchsia::netstack::NetInterface> interfaces, std::vector<fuchsia::netstack::RouteTableEntry> route_table) { - // Find the default interface in the routing table. - auto default_route_interface = std::find_if( - route_table.begin(), route_table.end(), - [](const fuchsia::netstack::RouteTableEntry& rt) { - return MaskPrefixLength( - internal::FuchsiaIpAddressToIPAddress(rt.netmask)) == 0; - }); - - // Find the default interface in the NetInterface list. - const fuchsia::netstack::NetInterface* default_interface = nullptr; - if (default_route_interface != route_table.end()) { - for (const auto& cur_interface : interfaces) { - if (cur_interface.id == default_route_interface->nicid) { - default_interface = &cur_interface; - } + // Create a set of NICs that have default routes (ie 0.0.0.0). + base::flat_set<uint32_t> default_route_ids; + for (const auto& route : route_table) { + if (MaskPrefixLength( + internal::FuchsiaIpAddressToIPAddress(route.netmask)) == 0) { + default_route_ids.insert(route.nicid); } } - base::flat_set<IPAddress> addresses; - std::string ssid; ConnectionType connection_type = CONNECTION_NONE; - if (default_interface) { + base::flat_set<IPAddress> addresses; + for (auto& interface : interfaces) { + // Filter out loopback and invalid connection types. + if ((internal::ConvertConnectionType(interface) == + NetworkChangeNotifier::CONNECTION_NONE) || + (interface.features & + fuchsia::hardware::ethernet::INFO_FEATURE_LOOPBACK)) { + continue; + } + + // Filter out interfaces that do not meet the |required_features_|. + if ((interface.features & required_features_) != required_features_) { + continue; + } + + // Filter out interfaces with non-default routes. + if (!default_route_ids.contains(interface.id)) { + continue; + } + std::vector<NetworkInterface> flattened_interfaces = - internal::NetInterfaceToNetworkInterfaces(*default_interface); + internal::NetInterfaceToNetworkInterfaces(interface); + if (flattened_interfaces.empty()) { + continue; + } + + // Add the addresses from this interface to the list of all addresses. std::transform( flattened_interfaces.begin(), flattened_interfaces.end(), std::inserter(addresses, addresses.begin()), [](const NetworkInterface& interface) { return interface.address; }); - if (!flattened_interfaces.empty()) { + + // Set the default connection to the first interface connection found. + if (connection_type == CONNECTION_NONE) { connection_type = flattened_interfaces.front().type; } - - // TODO(https://crbug.com/848355): Treat SSID changes as IP address changes. } bool connection_type_changed = false; @@ -131,6 +147,8 @@ connection_type_changed = true; } + // TODO(https://crbug.com/848355): Treat SSID changes as IP address changes. + if (addresses != cached_addresses_) { std::swap(cached_addresses_, addresses); if (on_initialized_cb.is_null()) {
diff --git a/net/base/network_change_notifier_fuchsia.h b/net/base/network_change_notifier_fuchsia.h index 72f9243..dfad123 100644 --- a/net/base/network_change_notifier_fuchsia.h +++ b/net/base/network_change_notifier_fuchsia.h
@@ -22,19 +22,26 @@ : public NetworkChangeNotifier { public: // Blocks execution until an initial interface list is received from - // |netstack_|. - NetworkChangeNotifierFuchsia(); + // |netstack_|. Interfaces can be filtered out by passing in + // |required_features|, which is defined in fuchsia::hardware::ethernet. + explicit NetworkChangeNotifierFuchsia(uint32_t required_features); ~NetworkChangeNotifierFuchsia() override; private: friend class NetworkChangeNotifierFuchsiaTest; + FRIEND_TEST_ALL_PREFIXES(NetworkChangeNotifierFuchsiaTest, + FindsInterfaceWithRequiredFeature); FRIEND_TEST_ALL_PREFIXES(NetworkChangeNotifierFuchsiaTest, FoundWiFi); FRIEND_TEST_ALL_PREFIXES(NetworkChangeNotifierFuchsiaTest, FoundWiFiNonDefault); + FRIEND_TEST_ALL_PREFIXES(NetworkChangeNotifierFuchsiaTest, + IgnoresInterfaceWithMissingFeature); - // For testing purposes. - explicit NetworkChangeNotifierFuchsia( - fuchsia::netstack::NetstackPtr netstack); + // For testing purposes. Receives a |netstack| pointer for easy mocking. + // Interfaces can be filtered out by passing in |required_features|, which is + // defined in fuchsia::hardware::ethernet. + NetworkChangeNotifierFuchsia(fuchsia::netstack::NetstackPtr netstack, + uint32_t required_features); // Forwards the network interface list along with the result of // GetRouteTable() to OnRouteTableReceived(). @@ -63,6 +70,10 @@ fuchsia::netstack::NetstackPtr netstack_; + // Bitmap of required features for an interface to be taken into account. The + // features are defined in fuchsia::hardware::ethernet. + const uint32_t required_features_; + // Set of addresses from the previous query/update for the default interface. base::flat_set<IPAddress> cached_addresses_;
diff --git a/net/base/network_change_notifier_fuchsia_unittest.cc b/net/base/network_change_notifier_fuchsia_unittest.cc index 4c38e07..596e07fb 100644 --- a/net/base/network_change_notifier_fuchsia_unittest.cc +++ b/net/base/network_change_notifier_fuchsia_unittest.cc
@@ -4,6 +4,7 @@ #include "net/base/network_change_notifier_fuchsia.h" +#include <fuchsia/hardware/ethernet/cpp/fidl.h> #include <fuchsia/netstack/cpp/fidl_test_base.h> #include <memory> #include <utility> @@ -128,7 +129,7 @@ void GetRouteTable(GetRouteTableCallback callback) override { std::vector<fuchsia::netstack::RouteTableEntry> table(2); table[0] = CreateRouteTableEntry(kDefaultNic, true); - table[1] = CreateRouteTableEntry(kSecondaryNic, true); + table[1] = CreateRouteTableEntry(kSecondaryNic, false); callback(std::move(table)); } @@ -160,8 +161,9 @@ // Creates a NetworkChangeNotifier, which will be seeded with the list of // interfaces which have already been added to |netstack_|. - void CreateNotifier() { - notifier_.reset(new NetworkChangeNotifierFuchsia(std::move(netstack_ptr_))); + void CreateNotifier(uint32_t required_features = 0) { + notifier_.reset(new NetworkChangeNotifierFuchsia(std::move(netstack_ptr_), + required_features)); NetworkChangeNotifier::AddNetworkChangeObserver(&observer_); } @@ -468,4 +470,25 @@ notifier_->GetCurrentConnectionType()); } +TEST_F(NetworkChangeNotifierFuchsiaTest, FindsInterfaceWithRequiredFeature) { + netstack_.PushInterface( + CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, + fuchsia::hardware::ethernet::INFO_FEATURE_WLAN, + CreateIPv4Address(169, 254, 0, 1), + CreateIPv4Address(255, 255, 255, 0), {})); + CreateNotifier(fuchsia::hardware::ethernet::INFO_FEATURE_WLAN); + EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, + notifier_->GetCurrentConnectionType()); +} + +TEST_F(NetworkChangeNotifierFuchsiaTest, IgnoresInterfaceWithMissingFeature) { + netstack_.PushInterface( + CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0, + CreateIPv4Address(169, 254, 0, 1), + CreateIPv4Address(255, 255, 255, 0), {})); + CreateNotifier(fuchsia::hardware::ethernet::INFO_FEATURE_WLAN); + EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_NONE, + notifier_->GetCurrentConnectionType()); +} + } // namespace net
diff --git a/net/base/network_interfaces_fuchsia.cc b/net/base/network_interfaces_fuchsia.cc index 04b0e2aa0..30dcc5d 100644 --- a/net/base/network_interfaces_fuchsia.cc +++ b/net/base/network_interfaces_fuchsia.cc
@@ -16,7 +16,6 @@ #include "base/fuchsia/fuchsia_logging.h" #include "base/strings/stringprintf.h" #include "net/base/ip_endpoint.h" -#include "net/base/network_change_notifier.h" #include "net/base/network_interfaces.h" namespace net { @@ -25,13 +24,6 @@ using ConnectionType = NetworkChangeNotifier::ConnectionType; -ConnectionType ConvertConnectionType( - const fuchsia::netstack::NetInterface& iface) { - return iface.features & fuchsia::hardware::ethernet::INFO_FEATURE_WLAN - ? NetworkChangeNotifier::CONNECTION_WIFI - : NetworkChangeNotifier::CONNECTION_UNKNOWN; -} - // Converts a Netstack NetInterface |interface| to a Chrome NetworkInterface. // NetInterfaces may be bound to multiple IPv6 addresses. |address_index| is // used to specify which address to use for the conversion. @@ -65,6 +57,16 @@ } // namespace +NetworkChangeNotifier::ConnectionType ConvertConnectionType( + const fuchsia::netstack::NetInterface& iface) { + if (!(iface.flags & fuchsia::netstack::NetInterfaceFlagUp)) { + return NetworkChangeNotifier::CONNECTION_NONE; + } else if (iface.features & fuchsia::hardware::ethernet::INFO_FEATURE_WLAN) { + return NetworkChangeNotifier::CONNECTION_WIFI; + } + return NetworkChangeNotifier::CONNECTION_UNKNOWN; +} + IPAddress FuchsiaIpAddressToIPAddress(const fuchsia::net::IpAddress& addr) { if (addr.is_ipv4()) { return IPAddress(addr.ipv4().addr.data(), addr.ipv4().addr.count()); @@ -79,13 +81,11 @@ const fuchsia::netstack::NetInterface& iface_in) { std::vector<NetworkInterface> output; - // Check if the interface is up. - if (!(iface_in.flags & fuchsia::netstack::NetInterfaceFlagUp)) + // If the interface is not currently up then there are no addresses to return. + if (internal::ConvertConnectionType(iface_in) == + NetworkChangeNotifier::CONNECTION_NONE) { return output; - - // Skip loopback. - if (iface_in.features & fuchsia::hardware::ethernet::INFO_FEATURE_LOOPBACK) - return output; + } output.push_back(NetworkInterfaceFromAddress(iface_in, 0)); @@ -115,6 +115,13 @@ } for (auto& interface : interfaces) { + if ((internal::ConvertConnectionType(interface) == + NetworkChangeNotifier::CONNECTION_NONE) || + (interface.features & + fuchsia::hardware::ethernet::INFO_FEATURE_LOOPBACK)) { + continue; + } + auto converted = internal::NetInterfaceToNetworkInterfaces(interface); std::move(converted.begin(), converted.end(), std::back_inserter(*networks));
diff --git a/net/base/network_interfaces_fuchsia.h b/net/base/network_interfaces_fuchsia.h index 06dbd95..b9dcf9c 100644 --- a/net/base/network_interfaces_fuchsia.h +++ b/net/base/network_interfaces_fuchsia.h
@@ -7,6 +7,8 @@ #include <vector> +#include "net/base/network_change_notifier.h" + namespace fuchsia { namespace net { class IpAddress; @@ -23,6 +25,12 @@ namespace internal { +// Returns the //net ConnectionType for the supplied netstack interface +// description. Returns ConnectionType::CONNECTION_NONE if the interface is not +// "up". +NetworkChangeNotifier::ConnectionType ConvertConnectionType( + const fuchsia::netstack::NetInterface& iface); + // Converts a Fuchsia Netstack NetInterface object to NetworkInterface objects. // Interfaces with more than one IPv6 address will yield multiple // NetworkInterface objects, with friendly names to distinguish the different
diff --git a/net/http/bidirectional_stream.cc b/net/http/bidirectional_stream.cc index e033260..404602b 100644 --- a/net/http/bidirectional_stream.cc +++ b/net/http/bidirectional_stream.cc
@@ -28,7 +28,7 @@ #include "net/spdy/spdy_log_util.h" #include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_config.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "url/gurl.h"
diff --git a/net/http/http_auth_gssapi_posix.h b/net/http/http_auth_gssapi_posix.h index 6d9fb68..df88f49 100644 --- a/net/http/http_auth_gssapi_posix.h +++ b/net/http/http_auth_gssapi_posix.h
@@ -13,6 +13,7 @@ #include "net/base/completion_once_callback.h" #include "net/base/net_export.h" #include "net/http/http_auth.h" +#include "net/http/http_negotiate_auth_system.h" #if defined(OS_MACOSX) #include <GSS/gssapi.h> @@ -222,55 +223,25 @@ // TODO(ahendrickson): Share code with HttpAuthSSPI. -class NET_EXPORT_PRIVATE HttpAuthGSSAPI { +class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpNegotiateAuthSystem { public: HttpAuthGSSAPI(GSSAPILibrary* library, const std::string& scheme, const gss_OID gss_oid); - ~HttpAuthGSSAPI(); + ~HttpAuthGSSAPI() override; - bool Init(); - - bool NeedsIdentity() const; - - bool AllowsExplicitCredentials() const; - + // HttpNegotiateAuthSystem implementation: + bool Init() override; + bool NeedsIdentity() const override; + bool AllowsExplicitCredentials() const override; HttpAuth::AuthorizationResult ParseChallenge( - HttpAuthChallengeTokenizer* tok); - - // Generates an authentication token. - // - // The return value is an error code. The authentication token will be - // returned in |*auth_token|. If the result code is not |OK|, the value of - // |*auth_token| is unspecified. - // - // If the operation cannot be completed synchronously, |ERR_IO_PENDING| will - // be returned and the real result code will be passed to the completion - // callback. Otherwise the result code is returned immediately from this - // call. - // - // If the HttpAuthGSSAPI object is deleted before completion then the callback - // will not be called. - // - // If no immediate result is returned then |auth_token| must remain valid - // until the callback has been called. - // - // |spn| is the Service Principal Name of the server that the token is - // being generated for. - // - // If this is the first round of a multiple round scheme, credentials are - // obtained using |*credentials|. If |credentials| is NULL, the default - // credentials are used instead. + HttpAuthChallengeTokenizer* tok) override; int GenerateAuthToken(const AuthCredentials* credentials, const std::string& spn, const std::string& channel_bindings, std::string* auth_token, - CompletionOnceCallback callback); - - // Delegation is allowed on the Kerberos ticket. This allows certain servers - // to act as the user, such as an IIS server retrieving data from a - // Kerberized MSSQL server. - void Delegate(); + CompletionOnceCallback callback) override; + void Delegate() override; private: int GetNextSecurityToken(const std::string& spn,
diff --git a/net/http/http_auth_handler_factory.cc b/net/http/http_auth_handler_factory.cc index dd3a643e..6b3dd0e 100644 --- a/net/http/http_auth_handler_factory.cc +++ b/net/http/http_auth_handler_factory.cc
@@ -96,16 +96,21 @@ // static std::unique_ptr<HttpAuthHandlerRegistryFactory> -HttpAuthHandlerFactory::CreateDefault(HostResolver* host_resolver, - const HttpAuthPreferences* prefs +HttpAuthHandlerFactory::CreateDefault( + HostResolver* host_resolver, + const HttpAuthPreferences* prefs #if defined(OS_CHROMEOS) - , - bool allow_gssapi_library_load + , + bool allow_gssapi_library_load #elif (defined(OS_POSIX) && !defined(OS_ANDROID)) || defined(OS_FUCHSIA) - , - const std::string& gssapi_library_name + , + const std::string& gssapi_library_name #endif - ) { +#if BUILDFLAG(USE_KERBEROS) + , + NegotiateAuthSystemFactory negotiate_auth_system_factory +#endif +) { std::vector<std::string> auth_types(std::begin(kDefaultAuthSchemes), std::end(kDefaultAuthSchemes)); return HttpAuthHandlerRegistryFactory::Create(host_resolver, prefs, auth_types @@ -117,7 +122,11 @@ , allow_gssapi_library_load #endif - ); +#if BUILDFLAG(USE_KERBEROS) + , + negotiate_auth_system_factory +#endif + ); } // static @@ -133,7 +142,11 @@ , const std::string& gssapi_library_name #endif - ) { +#if BUILDFLAG(USE_KERBEROS) + , + NegotiateAuthSystemFactory negotiate_auth_system_factory +#endif +) { std::set<std::string> auth_schemes_set(auth_schemes.begin(), auth_schemes.end()); @@ -162,7 +175,7 @@ if (base::ContainsKey(auth_schemes_set, kNegotiateAuthScheme)) { DCHECK(host_resolver); HttpAuthHandlerNegotiate::Factory* negotiate_factory = - new HttpAuthHandlerNegotiate::Factory(); + new HttpAuthHandlerNegotiate::Factory(negotiate_auth_system_factory); #if defined(OS_WIN) negotiate_factory->set_library(std::make_unique<SSPILibraryDefault>()); #elif defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
diff --git a/net/http/http_auth_handler_factory.h b/net/http/http_auth_handler_factory.h index a40b55ba..0c51a98 100644 --- a/net/http/http_auth_handler_factory.h +++ b/net/http/http_auth_handler_factory.h
@@ -14,7 +14,9 @@ #include "build/build_config.h" #include "net/base/net_export.h" #include "net/http/http_auth.h" +#include "net/http/http_negotiate_auth_system.h" #include "net/http/url_security_manager.h" +#include "net/net_buildflags.h" class GURL; @@ -117,6 +119,12 @@ const NetLogWithSource& net_log, std::unique_ptr<HttpAuthHandler>* handler); + // Factory callback to create the auth system used for Negotiate + // authentication. + using NegotiateAuthSystemFactory = + base::RepeatingCallback<std::unique_ptr<net::HttpNegotiateAuthSystem>( + const net::HttpAuthPreferences*)>; + // Creates a standard HttpAuthHandlerRegistryFactory. The caller is // responsible for deleting the factory. // The default factory supports Basic, Digest, NTLM, and Negotiate schemes. @@ -126,6 +134,9 @@ // non-NULL. |resolver| must remain valid for the lifetime of the // HttpAuthHandlerRegistryFactory and any HttpAuthHandlers created by said // factory. + // + // |negotiate_auth_system_factory| is used to override the default auth system + // used by the Negotiate authentication handler. static std::unique_ptr<HttpAuthHandlerRegistryFactory> CreateDefault( HostResolver* resolver, const HttpAuthPreferences* prefs = nullptr @@ -136,7 +147,12 @@ , const std::string& gssapi_library_name = "" #endif - ); +#if BUILDFLAG(USE_KERBEROS) + , + NegotiateAuthSystemFactory negotiate_auth_system_factory = + NegotiateAuthSystemFactory() +#endif + ); private: // The preferences for HTTP authentication. @@ -188,6 +204,9 @@ // // |auth_schemes| is a list of authentication schemes to support. Unknown // schemes are ignored. + // + // |negotiate_auth_system_factory| is used to override the default auth system + // used by the Negotiate authentication handler. static std::unique_ptr<HttpAuthHandlerRegistryFactory> Create( HostResolver* host_resolver, const HttpAuthPreferences* prefs, @@ -199,7 +218,12 @@ , const std::string& gssapi_library_name = "" #endif - ); +#if BUILDFLAG(USE_KERBEROS) + , + NegotiateAuthSystemFactory negotiate_auth_system_factory = + NegotiateAuthSystemFactory() +#endif + ); // Creates an auth handler by dispatching out to the registered factories // based on the first token in |challenge|.
diff --git a/net/http/http_auth_handler_negotiate.cc b/net/http/http_auth_handler_negotiate.cc index 5eacf4c..1356fdb9 100644 --- a/net/http/http_auth_handler_negotiate.cc +++ b/net/http/http_auth_handler_negotiate.cc
@@ -41,9 +41,36 @@ return std::move(dict); } +// Uses |negotiate_auth_system_factory| to create the auth system, otherwise +// creates the default auth system for each platform. +std::unique_ptr<HttpNegotiateAuthSystem> CreateAuthSystem( +#if !defined(OS_ANDROID) + HttpAuthHandlerNegotiate::AuthLibrary* auth_library, +#endif +#if defined(OS_WIN) + ULONG max_token_length, +#endif + const HttpAuthPreferences* prefs, + HttpAuthHandlerFactory::NegotiateAuthSystemFactory + negotiate_auth_system_factory) { + if (negotiate_auth_system_factory) + return negotiate_auth_system_factory.Run(prefs); +#if defined(OS_ANDROID) + return std::make_unique<net::android::HttpAuthNegotiateAndroid>(prefs); +#elif defined(OS_WIN) + return std::make_unique<HttpAuthSSPI>(auth_library, "Negotiate", NEGOSSP_NAME, + max_token_length); +#elif defined(OS_POSIX) + return std::make_unique<HttpAuthGSSAPI>(auth_library, "Negotiate", + CHROME_GSS_SPNEGO_MECH_OID_DESC); +#endif +} + } // namespace -HttpAuthHandlerNegotiate::Factory::Factory() {} +HttpAuthHandlerNegotiate::Factory::Factory( + NegotiateAuthSystemFactory negotiate_auth_system_factory) + : negotiate_auth_system_factory_(negotiate_auth_system_factory) {} HttpAuthHandlerNegotiate::Factory::~Factory() = default; @@ -81,9 +108,10 @@ } // TODO(cbentzel): Move towards model of parsing in the factory // method and only constructing when valid. - std::unique_ptr<HttpAuthHandler> tmp_handler( - new HttpAuthHandlerNegotiate(auth_library_.get(), max_token_length_, - http_auth_preferences(), resolver_)); + std::unique_ptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerNegotiate( + CreateAuthSystem(auth_library_.get(), max_token_length_, + http_auth_preferences(), negotiate_auth_system_factory_), + http_auth_preferences(), resolver_)); #elif defined(OS_ANDROID) if (is_unsupported_ || !http_auth_preferences() || http_auth_preferences()->AuthAndroidNegotiateAccountType().empty() || @@ -91,8 +119,9 @@ return ERR_UNSUPPORTED_AUTH_SCHEME; // TODO(cbentzel): Move towards model of parsing in the factory // method and only constructing when valid. - std::unique_ptr<HttpAuthHandler> tmp_handler( - new HttpAuthHandlerNegotiate(http_auth_preferences(), resolver_)); + std::unique_ptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerNegotiate( + CreateAuthSystem(http_auth_preferences(), negotiate_auth_system_factory_), + http_auth_preferences(), resolver_)); #elif defined(OS_POSIX) if (is_unsupported_ || !allow_gssapi_library_load_) return ERR_UNSUPPORTED_AUTH_SCHEME; @@ -103,7 +132,9 @@ // TODO(ahendrickson): Move towards model of parsing in the factory // method and only constructing when valid. std::unique_ptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerNegotiate( - auth_library_.get(), http_auth_preferences(), resolver_)); + CreateAuthSystem(auth_library_.get(), http_auth_preferences(), + negotiate_auth_system_factory_), + http_auth_preferences(), resolver_)); #endif if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, origin, net_log)) @@ -113,39 +144,27 @@ } HttpAuthHandlerNegotiate::HttpAuthHandlerNegotiate( -#if !defined(OS_ANDROID) - AuthLibrary* auth_library, -#endif -#if defined(OS_WIN) - ULONG max_token_length, -#endif + std::unique_ptr<HttpNegotiateAuthSystem> auth_system, const HttpAuthPreferences* prefs, HostResolver* resolver) -#if defined(OS_ANDROID) - : auth_system_(prefs), -#elif defined(OS_WIN) - : auth_system_(auth_library, "Negotiate", NEGOSSP_NAME, max_token_length), -#elif defined(OS_POSIX) - : auth_system_(auth_library, "Negotiate", CHROME_GSS_SPNEGO_MECH_OID_DESC), -#endif + : auth_system_(std::move(auth_system)), resolver_(resolver), already_called_(false), has_credentials_(false), auth_token_(NULL), next_state_(STATE_NONE), - http_auth_preferences_(prefs) { -} + http_auth_preferences_(prefs) {} HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() = default; HttpAuth::AuthorizationResult HttpAuthHandlerNegotiate::HandleAnotherChallenge( HttpAuthChallengeTokenizer* challenge) { - return auth_system_.ParseChallenge(challenge); + return auth_system_->ParseChallenge(challenge); } // Require identity on first pass instead of second. bool HttpAuthHandlerNegotiate::NeedsIdentity() { - return auth_system_.NeedsIdentity(); + return auth_system_->NeedsIdentity(); } bool HttpAuthHandlerNegotiate::AllowsDefaultCredentials() { @@ -157,7 +176,7 @@ } bool HttpAuthHandlerNegotiate::AllowsExplicitCredentials() { - return auth_system_.AllowsExplicitCredentials(); + return auth_system_->AllowsExplicitCredentials(); } // The Negotiate challenge header looks like: @@ -165,7 +184,7 @@ bool HttpAuthHandlerNegotiate::Init(HttpAuthChallengeTokenizer* challenge, const SSLInfo& ssl_info) { #if defined(OS_POSIX) - if (!auth_system_.Init()) { + if (!auth_system_->Init()) { VLOG(1) << "can't initialize GSSAPI library"; return false; } @@ -177,13 +196,13 @@ return false; #endif if (CanDelegate()) - auth_system_.Delegate(); + auth_system_->Delegate(); auth_scheme_ = HttpAuth::AUTH_SCHEME_NEGOTIATE; score_ = 4; properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED; HttpAuth::AuthorizationResult auth_result = - auth_system_.ParseChallenge(challenge); + auth_system_->ParseChallenge(challenge); if (auth_result != HttpAuth::AUTHORIZATION_RESULT_ACCEPT) return false; @@ -359,7 +378,7 @@ int HttpAuthHandlerNegotiate::DoGenerateAuthToken() { next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE; AuthCredentials* credentials = has_credentials_ ? &credentials_ : NULL; - return auth_system_.GenerateAuthToken( + return auth_system_->GenerateAuthToken( credentials, spn_, channel_bindings_, auth_token_, base::BindOnce(&HttpAuthHandlerNegotiate::OnIOComplete, base::Unretained(this)));
diff --git a/net/http/http_auth_handler_negotiate.h b/net/http/http_auth_handler_negotiate.h index de65976..a1f7fa8 100644 --- a/net/http/http_auth_handler_negotiate.h +++ b/net/http/http_auth_handler_negotiate.h
@@ -15,6 +15,7 @@ #include "net/dns/host_resolver.h" #include "net/http/http_auth_handler.h" #include "net/http/http_auth_handler_factory.h" +#include "net/http/http_negotiate_auth_system.h" #if defined(OS_ANDROID) #include "net/android/http_auth_negotiate_android.h" @@ -35,19 +36,15 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerNegotiate : public HttpAuthHandler { public: -#if defined(OS_ANDROID) - typedef net::android::HttpAuthNegotiateAndroid AuthSystem; -#elif defined(OS_WIN) +#if defined(OS_WIN) typedef SSPILibrary AuthLibrary; - typedef HttpAuthSSPI AuthSystem; -#elif defined(OS_POSIX) +#elif defined(OS_POSIX) && !defined(OS_ANDROID) typedef GSSAPILibrary AuthLibrary; - typedef HttpAuthGSSAPI AuthSystem; #endif class NET_EXPORT_PRIVATE Factory : public HttpAuthHandlerFactory { public: - Factory(); + Factory(NegotiateAuthSystemFactory negotiate_auth_system_factory); ~Factory() override; void set_host_resolver(HostResolver* host_resolver); @@ -82,6 +79,7 @@ std::unique_ptr<HttpAuthHandler>* handler) override; private: + NegotiateAuthSystemFactory negotiate_auth_system_factory_; HostResolver* resolver_ = nullptr; #if defined(OS_WIN) ULONG max_token_length_ = 0; @@ -95,15 +93,9 @@ #endif // !defined(OS_ANDROID) }; - HttpAuthHandlerNegotiate( -#if !defined(OS_ANDROID) - AuthLibrary* auth_library, -#endif -#if defined(OS_WIN) - ULONG max_token_length, -#endif - const HttpAuthPreferences* prefs, - HostResolver* host_resolver); + HttpAuthHandlerNegotiate(std::unique_ptr<HttpNegotiateAuthSystem> auth_system, + const HttpAuthPreferences* prefs, + HostResolver* host_resolver); ~HttpAuthHandlerNegotiate() override; @@ -146,7 +138,7 @@ int DoGenerateAuthTokenComplete(int rv); bool CanDelegate() const; - AuthSystem auth_system_; + std::unique_ptr<HttpNegotiateAuthSystem> auth_system_; HostResolver* const resolver_; // Members which are needed for DNS lookup + SPN.
diff --git a/net/http/http_auth_handler_negotiate_unittest.cc b/net/http/http_auth_handler_negotiate_unittest.cc index d4a932ff..ca8aa08 100644 --- a/net/http/http_auth_handler_negotiate_unittest.cc +++ b/net/http/http_auth_handler_negotiate_unittest.cc
@@ -37,6 +37,8 @@ namespace net { +constexpr char kFakeToken[] = "FakeToken"; + #if defined(OS_ANDROID) typedef net::android::DummySpnegoAuthenticator MockAuthLibrary; #elif defined(OS_WIN) @@ -55,7 +57,8 @@ "alias", "10.0.0.2", "canonical.example.com"); http_auth_preferences_.reset(new MockAllowHttpAuthPreferences()); - factory_.reset(new HttpAuthHandlerNegotiate::Factory()); + factory_.reset(new HttpAuthHandlerNegotiate::Factory( + net::HttpAuthHandlerFactory::NegotiateAuthSystemFactory())); factory_->set_http_auth_preferences(http_auth_preferences_.get()); #if defined(OS_ANDROID) http_auth_preferences_->set_auth_android_negotiate_account_type( @@ -232,6 +235,10 @@ } MockAuthLibrary* AuthLibrary() { return auth_library_; } + MockHostResolver* resolver() { return resolver_.get(); } + MockAllowHttpAuthPreferences* http_auth_preferences() { + return http_auth_preferences_.get(); + } private: #if defined(OS_WIN) @@ -377,7 +384,8 @@ std::unique_ptr<HostResolver> host_resolver(new MockHostResolver()); MockAllowHttpAuthPreferences http_auth_preferences; std::unique_ptr<HttpAuthHandlerNegotiate::Factory> negotiate_factory( - new HttpAuthHandlerNegotiate::Factory()); + new HttpAuthHandlerNegotiate::Factory( + net::HttpAuthHandlerFactory::NegotiateAuthSystemFactory())); negotiate_factory->set_host_resolver(host_resolver); negotiate_factory->set_http_auth_preferences(&http_auth_preferences); negotiate_factory->set_library( @@ -395,4 +403,60 @@ #endif // defined(OS_POSIX) +class TestAuthSystem : public HttpNegotiateAuthSystem { + public: + TestAuthSystem() = default; + ~TestAuthSystem() override = default; + + // HttpNegotiateAuthSystem implementation: + bool Init() override { return true; } + bool NeedsIdentity() const override { return true; } + bool AllowsExplicitCredentials() const override { return true; } + + net::HttpAuth::AuthorizationResult ParseChallenge( + net::HttpAuthChallengeTokenizer* tok) override { + return net::HttpAuth::AUTHORIZATION_RESULT_ACCEPT; + } + + int GenerateAuthToken(const net::AuthCredentials* credentials, + const std::string& spn, + const std::string& channel_bindings, + std::string* auth_token, + net::CompletionOnceCallback callback) override { + *auth_token = kFakeToken; + return net::OK; + } + + void Delegate() override {} +}; + +TEST_F(HttpAuthHandlerNegotiateTest, OverrideAuthSystem) { + auto negotiate_factory = std::make_unique<HttpAuthHandlerNegotiate::Factory>( + base::BindRepeating([](const HttpAuthPreferences*) + -> std::unique_ptr<HttpNegotiateAuthSystem> { + return std::make_unique<TestAuthSystem>(); + })); + negotiate_factory->set_host_resolver(resolver()); + negotiate_factory->set_http_auth_preferences(http_auth_preferences()); +#if !defined(OS_ANDROID) + auto auth_library = std::make_unique<MockAuthLibrary>(); + SetupMocks(auth_library.get()); + negotiate_factory->set_library(std::move(auth_library)); +#endif + + GURL gurl("http://www.example.com"); + std::unique_ptr<HttpAuthHandler> handler; + EXPECT_EQ(OK, negotiate_factory->CreateAuthHandlerFromString( + "Negotiate", HttpAuth::AUTH_SERVER, SSLInfo(), gurl, + NetLogWithSource(), &handler)); + EXPECT_TRUE(handler); + + TestCompletionCallback callback; + std::string auth_token; + HttpRequestInfo request_info; + EXPECT_EQ(OK, callback.GetResult(handler->GenerateAuthToken( + nullptr, &request_info, callback.callback(), &auth_token))); + EXPECT_EQ(kFakeToken, auth_token); +} + } // namespace net
diff --git a/net/http/http_auth_sspi_win.cc b/net/http/http_auth_sspi_win.cc index c6e531a..cfd8a874 100644 --- a/net/http/http_auth_sspi_win.cc +++ b/net/http/http_auth_sspi_win.cc
@@ -261,6 +261,10 @@ } } +bool HttpAuthSSPI::Init() { + return true; +} + bool HttpAuthSSPI::NeedsIdentity() const { return decoded_server_auth_token_.empty(); }
diff --git a/net/http/http_auth_sspi_win.h b/net/http/http_auth_sspi_win.h index 84c47c4..0e393c6 100644 --- a/net/http/http_auth_sspi_win.h +++ b/net/http/http_auth_sspi_win.h
@@ -20,6 +20,7 @@ #include "net/base/completion_once_callback.h" #include "net/base/net_export.h" #include "net/http/http_auth.h" +#include "net/http/http_negotiate_auth_system.h" namespace net { @@ -106,54 +107,26 @@ SECURITY_STATUS FreeContextBuffer(PVOID pvContextBuffer) override; }; -class NET_EXPORT_PRIVATE HttpAuthSSPI { +class NET_EXPORT_PRIVATE HttpAuthSSPI : public HttpNegotiateAuthSystem { public: HttpAuthSSPI(SSPILibrary* sspi_library, const std::string& scheme, const SEC_WCHAR* security_package, ULONG max_token_length); - ~HttpAuthSSPI(); + ~HttpAuthSSPI() override; - bool NeedsIdentity() const; - - bool AllowsExplicitCredentials() const; - + // HttpNegotiateAuthSystem implementation: + bool Init() override; + bool NeedsIdentity() const override; + bool AllowsExplicitCredentials() const override; HttpAuth::AuthorizationResult ParseChallenge( - HttpAuthChallengeTokenizer* tok); - - // Generates an authentication token. - // - // The return value is an error code. The authentication token will be - // returned in |*auth_token|. If the result code is not |OK|, the value of - // |*auth_token| is unspecified. - // - // If the operation cannot be completed synchronously, |ERR_IO_PENDING| will - // be returned and the real result code will be passed to the completion - // callback. Otherwise the result code is returned immediately from this - // call. - // - // If the HttpAuthSPPI object is deleted before completion then the callback - // will not be called. - // - // If no immediate result is returned then |auth_token| must remain valid - // until the callback has been called. - // - // |spn| is the Service Principal Name of the server that the token is - // being generated for. - // - // If this is the first round of a multiple round scheme, credentials are - // obtained using |*credentials|. If |credentials| is NULL, the default - // credentials are used instead. + HttpAuthChallengeTokenizer* tok) override; int GenerateAuthToken(const AuthCredentials* credentials, const std::string& spn, const std::string& channel_bindings, std::string* auth_token, - CompletionOnceCallback callback); - - // Delegation is allowed on the Kerberos ticket. This allows certain servers - // to act as the user, such as an IIS server retrieving data from a - // Kerberized MSSQL server. - void Delegate(); + CompletionOnceCallback callback) override; + void Delegate() override; private: int OnFirstRound(const AuthCredentials* credentials);
diff --git a/net/http/http_negotiate_auth_system.h b/net/http/http_negotiate_auth_system.h new file mode 100644 index 0000000..9d3acb0a --- /dev/null +++ b/net/http/http_negotiate_auth_system.h
@@ -0,0 +1,70 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_HTTP_HTTP_NEGOTIATE_AUTH_SYSTEM_H_ +#define NET_HTTP_HTTP_NEGOTIATE_AUTH_SYSTEM_H_ + +#include "net/base/completion_once_callback.h" +#include "net/base/net_export.h" +#include "net/http/http_auth.h" + +namespace net { + +class AuthCredentials; +class HttpAuthChallengeTokenizer; + +class NET_EXPORT_PRIVATE HttpNegotiateAuthSystem { + public: + virtual ~HttpNegotiateAuthSystem() = default; + + virtual bool Init() = 0; + + // True if authentication needs the identity of the user from Chrome. + virtual bool NeedsIdentity() const = 0; + + // True authentication can use explicit credentials included in the URL. + virtual bool AllowsExplicitCredentials() const = 0; + + // Parse a received Negotiate challenge. + virtual HttpAuth::AuthorizationResult ParseChallenge( + HttpAuthChallengeTokenizer* tok) = 0; + + // Generates an authentication token. + // + // The return value is an error code. The authentication token will be + // returned in |*auth_token|. If the result code is not |OK|, the value of + // |*auth_token| is unspecified. + // + // If the operation cannot be completed synchronously, |ERR_IO_PENDING| will + // be returned and the real result code will be passed to the completion + // callback. Otherwise the result code is returned immediately from this + // call. + // + // If the AndroidAuthNegotiate object is deleted before completion then the + // callback will not be called. + // + // If no immediate result is returned then |auth_token| must remain valid + // until the callback has been called. + // + // |spn| is the Service Principal Name of the server that the token is + // being generated for. + // + // If this is the first round of a multiple round scheme, credentials are + // obtained using |*credentials|. If |credentials| is NULL, the default + // credentials are used instead. + virtual int GenerateAuthToken(const AuthCredentials* credentials, + const std::string& spn, + const std::string& channel_bindings, + std::string* auth_token, + CompletionOnceCallback callback) = 0; + + // Delegation is allowed on the Kerberos ticket. This allows certain servers + // to act as the user, such as an IIS server retrieving data from a + // Kerberized MSSQL server. + virtual void Delegate() = 0; +}; + +} // namespace net + +#endif // NET_HTTP_HTTP_NEGOTIATE_AUTH_SYSTEM_H_
diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc index 359b4d2..5a43fd3 100644 --- a/net/http/http_network_layer.cc +++ b/net/http/http_network_layer.cc
@@ -15,7 +15,7 @@ #include "net/http/http_stream_factory_job.h" #include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session_pool.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" namespace net {
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 6833a7b4..0c42c754 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h
@@ -35,7 +35,7 @@ #include "net/socket/websocket_endpoint_lock_manager.h" #include "net/spdy/spdy_session_pool.h" #include "net/ssl/ssl_client_auth_cache.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace base { class Value;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index c164b27..19631949 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -74,7 +74,7 @@ #include "net/network_error_logging/network_error_logging_service.h" #include "net/reporting/reporting_header_parser.h" #include "net/reporting/reporting_service.h" -#endif +#endif // BUILDFLAG(ENABLE_REPORTING) namespace { @@ -110,6 +110,10 @@ can_send_early_data_(false), server_ssl_client_cert_was_cached_(false), request_headers_(), +#if BUILDFLAG(ENABLE_REPORTING) + network_error_logging_report_generated_(false), + request_reporting_upload_depth_(0), +#endif // BUILDFLAG(ENABLE_REPORTING) read_buf_len_(0), total_received_bytes_(0), total_sent_bytes_(0), @@ -121,9 +125,20 @@ net_error_details_(), retry_attempts_(0), num_restarts_(0), - ssl_version_interference_error_(OK) {} + ssl_version_interference_error_(OK) { +} HttpNetworkTransaction::~HttpNetworkTransaction() { +#if BUILDFLAG(ENABLE_REPORTING) + // Report a success if we have not already done so. Errors would have been + // reported from DoCallback(), DoReadBodyComplete(), HandleIOError(), or + // DoReadHeadersComplete(). + // Note: This may incorrectly report an error as a success, e.g. if the + // request is cancelled after successfully receiving headers but would + // otherwise have encountered an error on reading the body. + if (headers_valid_ && next_state_ == STATE_NONE) + GenerateNetworkErrorLoggingReport(OK); +#endif // BUILDFLAG(ENABLE_REPORTING) if (stream_.get()) { // TODO(mbelshe): The stream_ should be able to compute whether or not the // stream should be kept alive. No reason to compute here @@ -151,13 +166,15 @@ request_ = request_info; url_ = request_->url; #if BUILDFLAG(ENABLE_REPORTING) + // Store values for later use in NEL report generation. request_method_ = request_->method; request_->extra_headers.GetHeader(HttpRequestHeaders::kReferer, &request_referrer_); request_->extra_headers.GetHeader(HttpRequestHeaders::kUserAgent, &request_user_agent_); request_reporting_upload_depth_ = request_->reporting_upload_depth; -#endif + start_timeticks_ = base::TimeTicks::Now(); +#endif // BUILDFLAG(ENABLE_REPORTING) // Now that we have an HttpRequestInfo object, update server_ssl_config_. session_->GetSSLConfig(*request_, &server_ssl_config_, &proxy_ssl_config_); @@ -178,6 +195,11 @@ int rv = DoLoop(OK); if (rv == ERR_IO_PENDING) callback_ = std::move(callback); + + // This always returns ERR_IO_PENDING because DoCreateStream() does, but + // GenerateNetworkErrorLoggingReportIfError() should be called here if any + // other net::Error can be returned. + DCHECK_EQ(rv, ERR_IO_PENDING); return rv; } @@ -195,6 +217,11 @@ int rv = DoLoop(OK); if (rv == ERR_IO_PENDING) callback_ = std::move(callback); + + // This always returns ERR_IO_PENDING because DoCreateStream() does, but + // GenerateNetworkErrorLoggingReportIfError() should be called here if any + // other net::Error can be returned. + DCHECK_EQ(rv, ERR_IO_PENDING); return rv; } @@ -226,6 +253,11 @@ int rv = DoLoop(OK); if (rv == ERR_IO_PENDING) callback_ = std::move(callback); + + // This always returns ERR_IO_PENDING because DoCreateStream() does, but + // GenerateNetworkErrorLoggingReportIfError() should be called here if any + // other net::Error can be returned. + DCHECK_EQ(rv, ERR_IO_PENDING); return rv; } @@ -260,6 +292,11 @@ DCHECK(stream_request_ == NULL); PrepareForAuthRestart(target); rv = DoLoop(OK); + // Note: If an error is encountered while draining the old response body, no + // Network Error Logging report will be generated, because the error was + // with the old request, which will already have had a NEL report generated + // for it due to the auth challenge (so we don't report a second error for + // that request). } if (rv == ERR_IO_PENDING) @@ -661,9 +698,9 @@ #if BUILDFLAG(ENABLE_REPORTING) // Just before invoking the caller's completion callback, generate a NEL - // report about this network request. - GenerateNetworkErrorLoggingReport(rv); -#endif + // report about this network request if the result was an error. + GenerateNetworkErrorLoggingReportIfError(rv); +#endif // BUILDFLAG(ENABLE_REPORTING) // Since Run may result in Read being called, clear user_callback_ up front. base::ResetAndReturn(&callback_).Run(rv); @@ -1133,6 +1170,9 @@ if (response_.headers.get() && response_.headers->response_code() == HTTP_REQUEST_TIMEOUT && stream_->IsConnectionReused()) { +#if BUILDFLAG(ENABLE_REPORTING) + GenerateNetworkErrorLoggingReport(OK); +#endif // BUILDFLAG(ENABLE_REPORTING) net_log_.AddEventWithNetErrorCode( NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, response_.headers->response_code()); @@ -1183,6 +1223,9 @@ if (response_.headers->response_code() == 421 && (enable_ip_based_pooling_ || enable_alternative_services_)) { +#if BUILDFLAG(ENABLE_REPORTING) + GenerateNetworkErrorLoggingReport(OK); +#endif // BUILDFLAG(ENABLE_REPORTING) // Retry the request with both IP based pooling and Alternative Services // disabled. enable_ip_based_pooling_ = false; @@ -1208,9 +1251,22 @@ return rv; #if BUILDFLAG(ENABLE_REPORTING) + // Note: Unless there is a pre-existing NEL policy for this origin, any NEL + // reports generated before the NEL header is processed here will just be + // dropped by the NetworkErrorLoggingService. ProcessReportToHeader(); ProcessNetworkErrorLoggingHeader(); -#endif + + // Generate NEL report here if we have to report an HTTP error (4xx or 5xx + // code), or if the response body will not be read. + int response_code = response_.headers->response_code(); + if ((response_code >= 400 && response_code < 600) || + response_code == HTTP_NO_CONTENT || response_code == HTTP_RESET_CONTENT || + response_code == HTTP_NOT_MODIFIED || request_->method == "HEAD" || + response_.headers->GetContentLength() == 0) { + GenerateNetworkErrorLoggingReport(OK); + } +#endif // BUILDFLAG(ENABLE_REPORTING) headers_valid_ = true; @@ -1275,6 +1331,10 @@ session_->http_server_properties()->MarkAlternativeServiceBroken( retried_alternative_service_); } + +#if BUILDFLAG(ENABLE_REPORTING) + GenerateNetworkErrorLoggingReport(result); +#endif // BUILDFLAG(ENABLE_REPORTING) } // Clear these to avoid leaving around old state. @@ -1302,6 +1362,9 @@ bool done = false, keep_alive = true; if (result < 0) { // Error or closed connection while reading the socket. + // Note: No Network Error Logging report is generated here because a report + // will have already been generated for the original request due to the auth + // challenge, so a second report is not generated for the same request here. done = true; keep_alive = false; } else if (stream_->IsResponseBodyComplete()) { @@ -1379,7 +1442,20 @@ value); } +void HttpNetworkTransaction::GenerateNetworkErrorLoggingReportIfError(int rv) { + if (rv < 0 && rv != ERR_IO_PENDING) + GenerateNetworkErrorLoggingReport(rv); +} + void HttpNetworkTransaction::GenerateNetworkErrorLoggingReport(int rv) { + // |rv| should be a valid net::Error + DCHECK_NE(rv, ERR_IO_PENDING); + DCHECK_LE(rv, 0); + + if (network_error_logging_report_generated_) + return; + network_error_logging_report_generated_ = true; + NetworkErrorLoggingService* service = session_->network_error_logging_service(); if (!service) { @@ -1400,33 +1476,33 @@ if (!request_referrer_.empty()) details.referrer = GURL(request_referrer_); details.user_agent = request_user_agent_; - IPEndPoint endpoint; - if (!remote_endpoint_.address().empty()) + if (!remote_endpoint_.address().empty()) { details.server_ip = remote_endpoint_.address(); + } else { + details.server_ip = IPAddress(); + } // HttpResponseHeaders::response_code() returns 0 if response code couldn't // be parsed, which is also how NEL represents the same. - if (response_.headers) + if (response_.headers) { details.status_code = response_.headers->response_code(); - else + } else { details.status_code = 0; + } // If we got response headers, assume that the connection used HTTP/1.1 // unless ALPN negotiation tells us otherwise (handled below). - if (response_.was_alpn_negotiated) + if (response_.was_alpn_negotiated) { details.protocol = response_.alpn_negotiated_protocol; - else + } else { details.protocol = "http/1.1"; - details.method = request_method_; - if (stream_) { - LoadTimingInfo timing; - stream_->GetLoadTimingInfo(&timing); - details.elapsed_time = base::TimeTicks::Now() - timing.request_start; } + details.method = request_method_; + details.elapsed_time = base::TimeTicks::Now() - start_timeticks_; details.type = static_cast<Error>(rv); details.reporting_upload_depth = request_reporting_upload_depth_; service->OnRequest(std::move(details)); } -#endif +#endif // BUILDFLAG(ENABLE_REPORTING) int HttpNetworkTransaction::HandleCertificateRequest(int error) { // There are two paths through which the server can request a certificate @@ -1548,6 +1624,10 @@ // any time, check and handle client authentication errors. error = HandleSSLClientAuthError(error); +#if BUILDFLAG(ENABLE_REPORTING) + GenerateNetworkErrorLoggingReportIfError(error); +#endif // BUILDFLAG(ENABLE_REPORTING) + switch (error) { // If we try to reuse a connection that the server is in the process of // closing, we may end up successfully writing out our request (or a @@ -1658,6 +1738,10 @@ remote_endpoint_ = IPEndPoint(); net_error_details_.quic_broken = false; net_error_details_.quic_connection_error = quic::QUIC_NO_ERROR; +#if BUILDFLAG(ENABLE_REPORTING) + network_error_logging_report_generated_ = false; + start_timeticks_ = base::TimeTicks::Now(); +#endif // BUILDFLAG(ENABLE_REPORTING) } void HttpNetworkTransaction::CacheNetErrorDetailsAndResetStream() { @@ -1702,6 +1786,12 @@ // the SSL tunnel. request_headers_.Clear(); next_state_ = STATE_CREATE_STREAM; // Resend the request. + +#if BUILDFLAG(ENABLE_REPORTING) + // Reset for new request. + network_error_logging_report_generated_ = false; + start_timeticks_ = base::TimeTicks::Now(); +#endif // BUILDFLAG(ENABLE_REPORTING) } bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index d01f72d0..7ccc5f9 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h
@@ -214,6 +214,10 @@ // Reporting API. void ProcessNetworkErrorLoggingHeader(); + // Calls GenerateNetworkErrorLoggingReport() if |rv| represents a NET_ERROR + // other than ERR_IO_PENDING. + void GenerateNetworkErrorLoggingReportIfError(int rv); + // Generates a NEL report about this request. The NetworkErrorLoggingService // will discard the report if there is no NEL policy registered for this // origin. @@ -356,6 +360,8 @@ HttpRequestHeaders request_headers_; #if BUILDFLAG(ENABLE_REPORTING) + // Whether a NEL report has already been generated. Reset when restarting. + bool network_error_logging_report_generated_; // Cache some fields from |request_| that we'll need to construct a NEL // report about the request. (NEL report construction happens after we've // cleared the |request_| pointer.) @@ -363,6 +369,7 @@ std::string request_referrer_; std::string request_user_agent_; int request_reporting_upload_depth_; + base::TimeTicks start_timeticks_; #endif // The size in bytes of the buffer we use to drain the response body that
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index f0403a9..ae5b2324 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc
@@ -96,7 +96,7 @@ #include "net/test/gtest_util.h" #include "net/test/test_data_directory.h" #include "net/test/test_with_scoped_task_environment.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/websockets/websocket_handshake_stream_base.h" #include "net/websockets/websocket_test_util.h" @@ -18142,7 +18142,13 @@ } // Makes an HTTPS request that should install a valid Reporting policy. - void RequestPolicy() { + void RequestPolicy(CertStatus cert_status = 0) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL(url_); + request.traffic_annotation = + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + MockRead data_reads[] = { MockRead("HTTP/1.0 200 OK\r\n"), MockRead("Report-To: {\"group\": \"nel\", \"max_age\": 86400, " @@ -18158,35 +18164,27 @@ "Connection: keep-alive\r\n\r\n"), }; - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL(url_); - request.traffic_annotation = - net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + StaticSocketDataProvider reads(data_reads, data_writes); + session_deps_.socket_factory->AddSocketDataProvider(&reads); SSLSocketDataProvider ssl(ASYNC, OK); if (request.url.SchemeIsCryptographic()) { ssl.ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"); ASSERT_TRUE(ssl.ssl_info.cert); - ssl.ssl_info.cert_status = cert_status_; + ssl.ssl_info.cert_status = cert_status; session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); } - StaticSocketDataProvider reads(data_reads, data_writes); - session_deps_.socket_factory->AddSocketDataProvider(&reads); - TestCompletionCallback callback; auto session = CreateSession(&session_deps_); HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get()); int rv = trans.Start(&request, callback.callback(), NetLogWithSource()); - EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); - EXPECT_THAT(callback.WaitForResult(), IsOk()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); } protected: std::string url_ = "https://www.example.org/"; - CertStatus cert_status_ = 0; private: TestReportingContext* test_reporting_context_; @@ -18226,8 +18224,8 @@ TEST_F(HttpNetworkTransactionReportingTest, DontProcessReportToHeaderInvalidHttps) { base::HistogramTester histograms; - cert_status_ = CERT_STATUS_COMMON_NAME_INVALID; - RequestPolicy(); + CertStatus cert_status = CERT_STATUS_COMMON_NAME_INVALID; + RequestPolicy(cert_status); histograms.ExpectBucketCount( ReportingHeaderParser::kHeaderOutcomeHistogram, ReportingHeaderParser::HeaderOutcome::DISCARDED_CERT_STATUS_ERROR, 1); @@ -18238,6 +18236,13 @@ // Network Error Logging tests #if BUILDFLAG(ENABLE_REPORTING) +namespace { + +const char kUserAgent[] = "Mozilla/1.0"; +const char kReferrer[] = "https://www.referrer.org/"; + +} // namespace + class HttpNetworkTransactionNetworkErrorLoggingTest : public HttpNetworkTransactionTest { protected: @@ -18248,6 +18253,16 @@ test_network_error_logging_service_ = network_error_logging_service.get(); session_deps_.network_error_logging_service = std::move(network_error_logging_service); + + extra_headers_.SetHeader("User-Agent", kUserAgent); + extra_headers_.SetHeader("Referer", kReferrer); + + request_.method = "GET"; + request_.url = GURL(url_); + request_.extra_headers = extra_headers_; + request_.reporting_upload_depth = reporting_upload_depth_; + request_.traffic_annotation = + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); } TestNetworkErrorLoggingService* network_error_logging_service() const { @@ -18260,7 +18275,7 @@ } // Makes an HTTPS request that should install a valid NEL policy. - void RequestPolicy() { + void RequestPolicy(CertStatus cert_status = 0) { std::string extra_header_string = extra_headers_.ToString(); MockRead data_reads[] = { MockRead("HTTP/1.0 200 OK\r\n"), @@ -18277,37 +18292,52 @@ extra_header_string.size()), }; - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL(url_); - request.extra_headers = extra_headers_; - request.reporting_upload_depth = reporting_upload_depth_; - request.traffic_annotation = - net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + StaticSocketDataProvider reads(data_reads, data_writes); + session_deps_.socket_factory->AddSocketDataProvider(&reads); SSLSocketDataProvider ssl(ASYNC, OK); - if (request.url.SchemeIsCryptographic()) { + if (request_.url.SchemeIsCryptographic()) { ssl.ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"); ASSERT_TRUE(ssl.ssl_info.cert); - ssl.ssl_info.cert_status = cert_status_; + ssl.ssl_info.cert_status = cert_status; session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); } - StaticSocketDataProvider reads(data_reads, data_writes); - session_deps_.socket_factory->AddSocketDataProvider(&reads); - TestCompletionCallback callback; auto session = CreateSession(&session_deps_); HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get()); - int rv = trans.Start(&request, callback.callback(), NetLogWithSource()); - EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); - EXPECT_THAT(callback.WaitForResult(), IsOk()); + int rv = trans.Start(&request_, callback.callback(), NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + + std::string response_data; + ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk()); + EXPECT_EQ("hello world", response_data); + } + + void CheckReport(size_t index, + int status_code, + int error_type, + IPAddress server_ip = IPAddress::IPv4Localhost()) { + ASSERT_LT(index, network_error_logging_service()->errors().size()); + + const NetworkErrorLoggingService::RequestDetails& error = + network_error_logging_service()->errors()[index]; + EXPECT_EQ(url_, error.uri); + EXPECT_EQ(kReferrer, error.referrer); + EXPECT_EQ(kUserAgent, error.user_agent); + EXPECT_EQ(server_ip, error.server_ip); + EXPECT_EQ("http/1.1", error.protocol); + EXPECT_EQ("GET", error.method); + EXPECT_EQ(status_code, error.status_code); + EXPECT_EQ(error_type, error.type); + EXPECT_EQ(0, error.reporting_upload_depth); } protected: std::string url_ = "https://www.example.org/"; CertStatus cert_status_ = 0; + HttpRequestInfo request_; HttpRequestHeaders extra_headers_; int reporting_upload_depth_ = 0; @@ -18331,6 +18361,7 @@ DontProcessNelHeaderHttp) { base::HistogramTester histograms; url_ = "http://www.example.org/"; + request_.url = GURL(url_); RequestPolicy(); histograms.ExpectBucketCount( NetworkErrorLoggingService::kHeaderOutcomeHistogram, @@ -18350,27 +18381,704 @@ TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, DontProcessNelHeaderInvalidHttps) { base::HistogramTester histograms; - cert_status_ = CERT_STATUS_COMMON_NAME_INVALID; - RequestPolicy(); + CertStatus cert_status = CERT_STATUS_COMMON_NAME_INVALID; + RequestPolicy(cert_status); histograms.ExpectBucketCount( NetworkErrorLoggingService::kHeaderOutcomeHistogram, NetworkErrorLoggingService::HeaderOutcome::DISCARDED_CERT_STATUS_ERROR, 1); } -TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, CreateReportHttps) { +TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, CreateReportSuccess) { RequestPolicy(); ASSERT_EQ(1u, network_error_logging_service()->errors().size()); - const auto& error = network_error_logging_service()->errors()[0]; - EXPECT_EQ(GURL("https://www.example.org/"), error.uri); - EXPECT_TRUE(error.referrer.is_empty()); - EXPECT_EQ("", error.user_agent); - EXPECT_EQ(IPAddress::IPv4Localhost(), error.server_ip); - EXPECT_EQ("http/1.1", error.protocol); - EXPECT_EQ("GET", error.method); - EXPECT_EQ(200, error.status_code); - EXPECT_EQ(OK, error.type); - EXPECT_EQ(0, error.reporting_upload_depth); + CheckReport(0 /* index */, 200 /* status_code */, OK); +} + +TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, + CreateReportErrorAfterStart) { + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + + MockConnect mock_connect(SYNCHRONOUS, ERR_NAME_NOT_RESOLVED); + StaticSocketDataProvider data; + data.set_connect_data(mock_connect); + session_deps_.socket_factory->AddSocketDataProvider(&data); + + TestCompletionCallback callback; + + int rv = trans->Start(&request_, callback.callback(), NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsError(ERR_NAME_NOT_RESOLVED)); + + trans.reset(); + + ASSERT_EQ(1u, network_error_logging_service()->errors().size()); + CheckReport(0 /* index */, 0 /* status_code */, ERR_NAME_NOT_RESOLVED, + IPAddress() /* server_ip */); +} + +// Same as above except the error is ASYNC +TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, + CreateReportErrorAfterStartAsync) { + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + + MockConnect mock_connect(ASYNC, ERR_NAME_NOT_RESOLVED); + StaticSocketDataProvider data; + data.set_connect_data(mock_connect); + session_deps_.socket_factory->AddSocketDataProvider(&data); + + TestCompletionCallback callback; + + int rv = trans->Start(&request_, callback.callback(), NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsError(ERR_NAME_NOT_RESOLVED)); + + trans.reset(); + + ASSERT_EQ(1u, network_error_logging_service()->errors().size()); + CheckReport(0 /* index */, 0 /* status_code */, ERR_NAME_NOT_RESOLVED, + IPAddress() /* server_ip */); +} + +TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, + CreateReportReadBodyError) { + std::string extra_header_string = extra_headers_.ToString(); + MockRead data_reads[] = { + MockRead("HTTP/1.0 200 OK\r\n"), + MockRead("Content-Length: 100\r\n\r\n"), // wrong content length + MockRead("hello world"), + MockRead(SYNCHRONOUS, OK), + }; + MockWrite data_writes[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n"), + MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()), + }; + + StaticSocketDataProvider reads(data_reads, data_writes); + session_deps_.socket_factory->AddSocketDataProvider(&reads); + + SSLSocketDataProvider ssl(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); + + // Log start time + base::TimeTicks start_time = base::TimeTicks::Now(); + + TestCompletionCallback callback; + auto session = CreateSession(&session_deps_); + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + int rv = trans->Start(&request_, callback.callback(), NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + + EXPECT_TRUE(response->headers); + EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); + + std::string response_data; + rv = ReadTransaction(trans.get(), &response_data); + EXPECT_THAT(rv, IsError(ERR_CONTENT_LENGTH_MISMATCH)); + + trans.reset(); + + ASSERT_EQ(1u, network_error_logging_service()->errors().size()); + + CheckReport(0 /* index */, 200 /* status_code */, + ERR_CONTENT_LENGTH_MISMATCH); + const NetworkErrorLoggingService::RequestDetails& error = + network_error_logging_service()->errors()[0]; + EXPECT_LE(error.elapsed_time, base::TimeTicks::Now() - start_time); +} + +// Same as above except the final read is ASYNC. +TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, + CreateReportReadBodyErrorAsync) { + std::string extra_header_string = extra_headers_.ToString(); + MockRead data_reads[] = { + MockRead("HTTP/1.0 200 OK\r\n"), + MockRead("Content-Length: 100\r\n\r\n"), // wrong content length + MockRead("hello world"), + MockRead(ASYNC, OK), + }; + MockWrite data_writes[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n"), + MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()), + }; + + StaticSocketDataProvider reads(data_reads, data_writes); + session_deps_.socket_factory->AddSocketDataProvider(&reads); + + SSLSocketDataProvider ssl(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); + + // Log start time + base::TimeTicks start_time = base::TimeTicks::Now(); + + TestCompletionCallback callback; + auto session = CreateSession(&session_deps_); + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + int rv = trans->Start(&request_, callback.callback(), NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + + EXPECT_TRUE(response->headers); + EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); + + std::string response_data; + rv = ReadTransaction(trans.get(), &response_data); + EXPECT_THAT(rv, IsError(ERR_CONTENT_LENGTH_MISMATCH)); + + trans.reset(); + + ASSERT_EQ(1u, network_error_logging_service()->errors().size()); + + CheckReport(0 /* index */, 200 /* status_code */, + ERR_CONTENT_LENGTH_MISMATCH); + const NetworkErrorLoggingService::RequestDetails& error = + network_error_logging_service()->errors()[0]; + EXPECT_LE(error.elapsed_time, base::TimeTicks::Now() - start_time); +} + +TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, + CreateReportRestartWithAuth) { + std::string extra_header_string = extra_headers_.ToString(); + static const base::TimeDelta kSleepDuration = + base::TimeDelta::FromMilliseconds(10); + + MockWrite data_writes1[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n"), + MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()), + }; + + MockRead data_reads1[] = { + MockRead("HTTP/1.0 401 Unauthorized\r\n"), + // Give a couple authenticate options (only the middle one is actually + // supported). + MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed. + MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), + MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), + // Large content-length -- won't matter, as connection will be reset. + MockRead("Content-Length: 10000\r\n\r\n"), + MockRead(SYNCHRONOUS, ERR_FAILED), + }; + + // After calling trans->RestartWithAuth(), this is the request we should + // be issuing -- the final header line contains the credentials. + MockWrite data_writes2[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n" + "Authorization: Basic Zm9vOmJhcg==\r\n"), + MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()), + }; + + // Lastly, the server responds with the actual content. + MockRead data_reads2[] = { + MockRead("HTTP/1.0 200 OK\r\n\r\n"), + MockRead("hello world"), + MockRead(SYNCHRONOUS, OK), + }; + + StaticSocketDataProvider data1(data_reads1, data_writes1); + StaticSocketDataProvider data2(data_reads2, data_writes2); + session_deps_.socket_factory->AddSocketDataProvider(&data1); + session_deps_.socket_factory->AddSocketDataProvider(&data2); + + SSLSocketDataProvider ssl1(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1); + SSLSocketDataProvider ssl2(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2); + + base::TimeTicks start_time = base::TimeTicks::Now(); + base::TimeTicks restart_time; + + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + + TestCompletionCallback callback1; + + int rv = trans->Start(&request_, callback1.callback(), NetLogWithSource()); + EXPECT_THAT(callback1.GetResult(rv), IsOk()); + + ASSERT_EQ(1u, network_error_logging_service()->errors().size()); + + TestCompletionCallback callback2; + + // Wait 10 ms then restart with auth + FastForwardBy(kSleepDuration); + restart_time = base::TimeTicks::Now(); + rv = + trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback()); + EXPECT_THAT(callback2.GetResult(rv), IsOk()); + + std::string response_data; + ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk()); + EXPECT_EQ("hello world", response_data); + + trans.reset(); + + // One 401 report for the auth challenge, then a 200 report for the successful + // retry. Note that we don't report the error draining the body, as the first + // request already generated a report for the auth challenge. + ASSERT_EQ(2u, network_error_logging_service()->errors().size()); + + // Check error report contents + CheckReport(0 /* index */, 401 /* status_code */, OK); + CheckReport(1 /* index */, 200 /* status_code */, OK); + + const NetworkErrorLoggingService::RequestDetails& error1 = + network_error_logging_service()->errors()[0]; + const NetworkErrorLoggingService::RequestDetails& error2 = + network_error_logging_service()->errors()[1]; + + // Sanity-check elapsed time values + EXPECT_EQ(error1.elapsed_time, restart_time - start_time - kSleepDuration); + // Check that the start time is refreshed when restarting with auth. + EXPECT_EQ(error2.elapsed_time, base::TimeTicks::Now() - restart_time); +} + +// Same as above, except draining the body before restarting fails +// asynchronously. +TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, + CreateReportRestartWithAuthAsync) { + std::string extra_header_string = extra_headers_.ToString(); + static const base::TimeDelta kSleepDuration = + base::TimeDelta::FromMilliseconds(10); + + MockWrite data_writes1[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n"), + MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()), + }; + + MockRead data_reads1[] = { + MockRead("HTTP/1.0 401 Unauthorized\r\n"), + // Give a couple authenticate options (only the middle one is actually + // supported). + MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed. + MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), + MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), + // Large content-length -- won't matter, as connection will be reset. + MockRead("Content-Length: 10000\r\n\r\n"), + MockRead(ASYNC, ERR_FAILED), + }; + + // After calling trans->RestartWithAuth(), this is the request we should + // be issuing -- the final header line contains the credentials. + MockWrite data_writes2[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n" + "Authorization: Basic Zm9vOmJhcg==\r\n"), + MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()), + }; + + // Lastly, the server responds with the actual content. + MockRead data_reads2[] = { + MockRead("HTTP/1.0 200 OK\r\n\r\n"), + MockRead("hello world"), + MockRead(SYNCHRONOUS, OK), + }; + + StaticSocketDataProvider data1(data_reads1, data_writes1); + StaticSocketDataProvider data2(data_reads2, data_writes2); + session_deps_.socket_factory->AddSocketDataProvider(&data1); + session_deps_.socket_factory->AddSocketDataProvider(&data2); + + SSLSocketDataProvider ssl1(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1); + SSLSocketDataProvider ssl2(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2); + + base::TimeTicks start_time = base::TimeTicks::Now(); + base::TimeTicks restart_time; + + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + + TestCompletionCallback callback1; + + int rv = trans->Start(&request_, callback1.callback(), NetLogWithSource()); + EXPECT_THAT(callback1.GetResult(rv), IsOk()); + + ASSERT_EQ(1u, network_error_logging_service()->errors().size()); + + TestCompletionCallback callback2; + + // Wait 10 ms then restart with auth + FastForwardBy(kSleepDuration); + restart_time = base::TimeTicks::Now(); + rv = + trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback()); + EXPECT_THAT(callback2.GetResult(rv), IsOk()); + + std::string response_data; + ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk()); + EXPECT_EQ("hello world", response_data); + + trans.reset(); + + // One 401 report for the auth challenge, then a 200 report for the successful + // retry. Note that we don't report the error draining the body, as the first + // request already generated a report for the auth challenge. + ASSERT_EQ(2u, network_error_logging_service()->errors().size()); + + // Check error report contents + CheckReport(0 /* index */, 401 /* status_code */, OK); + CheckReport(1 /* index */, 200 /* status_code */, OK); + + const NetworkErrorLoggingService::RequestDetails& error1 = + network_error_logging_service()->errors()[0]; + const NetworkErrorLoggingService::RequestDetails& error2 = + network_error_logging_service()->errors()[1]; + + // Sanity-check elapsed time values + EXPECT_EQ(error1.elapsed_time, restart_time - start_time - kSleepDuration); + // Check that the start time is refreshed when restarting with auth. + EXPECT_EQ(error2.elapsed_time, base::TimeTicks::Now() - restart_time); +} + +TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, + CreateReportRetryKeepAliveConnectionReset) { + std::string extra_header_string = extra_headers_.ToString(); + MockWrite data_writes1[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n"), + MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()), + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n"), + MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()), + }; + + MockRead data_reads1[] = { + MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), + MockRead("hello"), + // Connection is reset + MockRead(ASYNC, ERR_CONNECTION_RESET), + }; + + // Successful retry + MockRead data_reads2[] = { + MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), + MockRead("world"), + MockRead(ASYNC, OK), + }; + + StaticSocketDataProvider data1(data_reads1, data_writes1); + StaticSocketDataProvider data2(data_reads2, base::span<MockWrite>()); + session_deps_.socket_factory->AddSocketDataProvider(&data1); + session_deps_.socket_factory->AddSocketDataProvider(&data2); + + SSLSocketDataProvider ssl1(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1); + SSLSocketDataProvider ssl2(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2); + + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + auto trans1 = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + + TestCompletionCallback callback1; + + int rv = trans1->Start(&request_, callback1.callback(), NetLogWithSource()); + EXPECT_THAT(callback1.GetResult(rv), IsOk()); + + std::string response_data; + ASSERT_THAT(ReadTransaction(trans1.get(), &response_data), IsOk()); + EXPECT_EQ("hello", response_data); + + ASSERT_EQ(1u, network_error_logging_service()->errors().size()); + + auto trans2 = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + + TestCompletionCallback callback2; + + rv = trans2->Start(&request_, callback2.callback(), NetLogWithSource()); + EXPECT_THAT(callback2.GetResult(rv), IsOk()); + + ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk()); + EXPECT_EQ("world", response_data); + + trans1.reset(); + trans2.reset(); + + // One OK report from first request, then a ERR_CONNECTION_RESET report from + // the second request, then an OK report from the successful retry. + ASSERT_EQ(3u, network_error_logging_service()->errors().size()); + + // Check error report contents + CheckReport(0 /* index */, 200 /* status_code */, OK); + CheckReport(1 /* index */, 0 /* status_code */, ERR_CONNECTION_RESET); + CheckReport(2 /* index */, 200 /* status_code */, OK); +} + +TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, + CreateReportRetryKeepAlive408) { + std::string extra_header_string = extra_headers_.ToString(); + MockWrite data_writes1[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n"), + MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()), + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n"), + MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()), + }; + + MockRead data_reads1[] = { + MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), + MockRead("hello"), + // 408 Request Timeout + MockRead(SYNCHRONOUS, + "HTTP/1.1 408 Request Timeout\r\n" + "Connection: Keep-Alive\r\n" + "Content-Length: 6\r\n\r\n" + "Pickle"), + }; + + // Successful retry + MockRead data_reads2[] = { + MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), + MockRead("world"), + MockRead(ASYNC, OK), + }; + + StaticSocketDataProvider data1(data_reads1, data_writes1); + StaticSocketDataProvider data2(data_reads2, base::span<MockWrite>()); + session_deps_.socket_factory->AddSocketDataProvider(&data1); + session_deps_.socket_factory->AddSocketDataProvider(&data2); + + SSLSocketDataProvider ssl1(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1); + SSLSocketDataProvider ssl2(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2); + + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + auto trans1 = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + + TestCompletionCallback callback1; + + int rv = trans1->Start(&request_, callback1.callback(), NetLogWithSource()); + EXPECT_THAT(callback1.GetResult(rv), IsOk()); + + std::string response_data; + ASSERT_THAT(ReadTransaction(trans1.get(), &response_data), IsOk()); + EXPECT_EQ("hello", response_data); + + ASSERT_EQ(1u, network_error_logging_service()->errors().size()); + + auto trans2 = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + + TestCompletionCallback callback2; + + rv = trans2->Start(&request_, callback2.callback(), NetLogWithSource()); + EXPECT_THAT(callback2.GetResult(rv), IsOk()); + + ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk()); + EXPECT_EQ("world", response_data); + + trans1.reset(); + trans2.reset(); + + // One 200 report from first request, then a 408 report from + // the second request, then a 200 report from the successful retry. + ASSERT_EQ(3u, network_error_logging_service()->errors().size()); + + // Check error report contents + CheckReport(0 /* index */, 200 /* status_code */, OK); + CheckReport(1 /* index */, 408 /* status_code */, OK); + CheckReport(2 /* index */, 200 /* status_code */, OK); +} + +TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, + CreateReportRetry421WithoutConnectionPooling) { + // Two hosts resolve to the same IP address. + const std::string ip_addr = "1.2.3.4"; + IPAddress ip; + ASSERT_TRUE(ip.AssignFromIPLiteral(ip_addr)); + IPEndPoint peer_addr = IPEndPoint(ip, 443); + + session_deps_.host_resolver = std::make_unique<MockCachingHostResolver>(); + session_deps_.host_resolver->rules()->AddRule("www.example.org", ip_addr); + session_deps_.host_resolver->rules()->AddRule("mail.example.org", ip_addr); + + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + + // Two requests on the first connection. + spdy::SpdySerializedFrame req1( + spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST)); + spdy_util_.UpdateWithStreamDestruction(1); + spdy::SpdySerializedFrame req2( + spdy_util_.ConstructSpdyGet("https://mail.example.org", 3, LOWEST)); + spdy::SpdySerializedFrame rst( + spdy_util_.ConstructSpdyRstStream(3, spdy::ERROR_CODE_CANCEL)); + MockWrite writes1[] = { + CreateMockWrite(req1, 0), + CreateMockWrite(req2, 3), + CreateMockWrite(rst, 6), + }; + + // The first one succeeds, the second gets error 421 Misdirected Request. + spdy::SpdySerializedFrame resp1( + spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); + spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true)); + spdy::SpdyHeaderBlock response_headers; + response_headers[spdy::kHttp2StatusHeader] = "421"; + spdy::SpdySerializedFrame resp2( + spdy_util_.ConstructSpdyReply(3, std::move(response_headers))); + MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2), + CreateMockRead(resp2, 4), MockRead(ASYNC, 0, 5)}; + + MockConnect connect1(ASYNC, OK, peer_addr); + SequencedSocketData data1(connect1, reads1, writes1); + session_deps_.socket_factory->AddSocketDataProvider(&data1); + + AddSSLSocketData(); + + // Retry the second request on a second connection. + SpdyTestUtil spdy_util2; + spdy::SpdySerializedFrame req3( + spdy_util2.ConstructSpdyGet("https://mail.example.org", 1, LOWEST)); + MockWrite writes2[] = { + CreateMockWrite(req3, 0), + }; + + spdy::SpdySerializedFrame resp3( + spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1)); + spdy::SpdySerializedFrame body3(spdy_util2.ConstructSpdyDataFrame(1, true)); + MockRead reads2[] = {CreateMockRead(resp3, 1), CreateMockRead(body3, 2), + MockRead(ASYNC, 0, 3)}; + + MockConnect connect2(ASYNC, OK, peer_addr); + SequencedSocketData data2(connect2, reads2, writes2); + session_deps_.socket_factory->AddSocketDataProvider(&data2); + + AddSSLSocketData(); + + // Preload mail.example.org into HostCache. + HostPortPair host_port("mail.example.org", 443); + HostResolver::RequestInfo resolve_info(host_port); + AddressList ignored; + std::unique_ptr<HostResolver::Request> request; + TestCompletionCallback callback; + int rv = session_deps_.host_resolver->Resolve(resolve_info, DEFAULT_PRIORITY, + &ignored, callback.callback(), + &request, NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + + HttpRequestInfo request1; + request1.method = "GET"; + request1.url = GURL("https://www.example.org/"); + request1.load_flags = 0; + request1.traffic_annotation = + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + auto trans1 = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + + rv = trans1->Start(&request1, callback.callback(), NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + + const HttpResponseInfo* response = trans1->GetResponseInfo(); + ASSERT_TRUE(response); + ASSERT_TRUE(response->headers); + EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine()); + EXPECT_TRUE(response->was_fetched_via_spdy); + EXPECT_TRUE(response->was_alpn_negotiated); + std::string response_data; + ASSERT_THAT(ReadTransaction(trans1.get(), &response_data), IsOk()); + EXPECT_EQ("hello!", response_data); + + trans1.reset(); + + ASSERT_EQ(1u, network_error_logging_service()->errors().size()); + + HttpRequestInfo request2; + request2.method = "GET"; + request2.url = GURL("https://mail.example.org/"); + request2.load_flags = 0; + request2.traffic_annotation = + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + auto trans2 = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + + BoundTestNetLog log; + rv = trans2->Start(&request2, callback.callback(), log.bound()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + + response = trans2->GetResponseInfo(); + ASSERT_TRUE(response); + ASSERT_TRUE(response->headers); + EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine()); + EXPECT_TRUE(response->was_fetched_via_spdy); + EXPECT_TRUE(response->was_alpn_negotiated); + ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk()); + EXPECT_EQ("hello!", response_data); + + trans2.reset(); + + // One 200 report from the first request, then a 421 report from the + // second request, then a 200 report from the successful retry. + ASSERT_EQ(3u, network_error_logging_service()->errors().size()); + + // Check error report contents + const NetworkErrorLoggingService::RequestDetails& error1 = + network_error_logging_service()->errors()[0]; + EXPECT_EQ(GURL("https://www.example.org/"), error1.uri); + EXPECT_TRUE(error1.referrer.is_empty()); + EXPECT_EQ("", error1.user_agent); + EXPECT_EQ(ip, error1.server_ip); + EXPECT_EQ("h2", error1.protocol); + EXPECT_EQ("GET", error1.method); + EXPECT_EQ(200, error1.status_code); + EXPECT_EQ(OK, error1.type); + EXPECT_EQ(0, error1.reporting_upload_depth); + + const NetworkErrorLoggingService::RequestDetails& error2 = + network_error_logging_service()->errors()[1]; + EXPECT_EQ(GURL("https://mail.example.org/"), error2.uri); + EXPECT_TRUE(error2.referrer.is_empty()); + EXPECT_EQ("", error2.user_agent); + EXPECT_EQ(ip, error2.server_ip); + EXPECT_EQ("h2", error2.protocol); + EXPECT_EQ("GET", error2.method); + EXPECT_EQ(421, error2.status_code); + EXPECT_EQ(OK, error2.type); + EXPECT_EQ(0, error2.reporting_upload_depth); + + const NetworkErrorLoggingService::RequestDetails& error3 = + network_error_logging_service()->errors()[2]; + EXPECT_EQ(GURL("https://mail.example.org/"), error3.uri); + EXPECT_TRUE(error3.referrer.is_empty()); + EXPECT_EQ("", error3.user_agent); + EXPECT_EQ(ip, error3.server_ip); + EXPECT_EQ("h2", error3.protocol); + EXPECT_EQ("GET", error3.method); + EXPECT_EQ(200, error3.status_code); + EXPECT_EQ(OK, error3.type); + EXPECT_EQ(0, error3.reporting_upload_depth); } TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, DontCreateReportHttp) { @@ -18393,23 +19101,23 @@ MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()), }; - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.example.org/"); - request.extra_headers = extra_headers_; - request.reporting_upload_depth = reporting_upload_depth_; - request.traffic_annotation = - net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); - StaticSocketDataProvider reads(data_reads, data_writes); session_deps_.socket_factory->AddSocketDataProvider(&reads); + // Insecure url + url_ = "http://www.example.org/"; + request_.url = GURL(url_); + TestCompletionCallback callback; auto session = CreateSession(&session_deps_); - HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get()); - int rv = trans.Start(&request, callback.callback(), NetLogWithSource()); - EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); - EXPECT_THAT(callback.WaitForResult(), IsOk()); + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + int rv = trans->Start(&request_, callback.callback(), NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + + std::string response_data; + ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk()); + EXPECT_EQ("hello world", response_data); // Insecure request does not generate a report histograms.ExpectBucketCount( @@ -18435,19 +19143,15 @@ StaticSocketDataProvider data(data_reads, base::span<MockWrite>()); session_deps_.socket_factory->AddSocketDataProvider(&data); + url_ = "http://www.originwithoutpolicy.com:2000/"; + request_.url = GURL(url_); + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); - HttpRequestInfo request; auto trans = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); - - request.method = "GET"; - request.url = GURL("http://www.originwithoutpolicy.com:2000/"); - request.traffic_annotation = - net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); - TestCompletionCallback callback; - int rv = trans->Start(&request, callback.callback(), NetLogWithSource()); + int rv = trans->Start(&request_, callback.callback(), NetLogWithSource()); EXPECT_THAT(callback.GetResult(rv), IsError(ERR_INVALID_HTTP_RESPONSE)); // Insecure request does not generate a report, regardless of existence of a @@ -18459,32 +19163,79 @@ EXPECT_EQ(1u, network_error_logging_service()->errors().size()); } -TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, ReportContainsReferrer) { - constexpr char kReferrer[] = "https://www.example.org/login/"; - extra_headers_.SetHeader("Referer", kReferrer); - RequestPolicy(); - ASSERT_EQ(1u, network_error_logging_service()->errors().size()); - const auto& error = network_error_logging_service()->errors()[0]; - EXPECT_EQ(GURL(kReferrer), error.referrer); -} - TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, ReportContainsUploadDepth) { reporting_upload_depth_ = 7; + request_.reporting_upload_depth = reporting_upload_depth_; RequestPolicy(); ASSERT_EQ(1u, network_error_logging_service()->errors().size()); - const auto& error = network_error_logging_service()->errors()[0]; + const NetworkErrorLoggingService::RequestDetails& error = + network_error_logging_service()->errors()[0]; EXPECT_EQ(7, error.reporting_upload_depth); } -TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, ReportContainsUserAgent) { - constexpr char kUserAgent[] = "Mozilla/1.0"; - extra_headers_.SetHeader("User-Agent", kUserAgent); - RequestPolicy(); +TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, ReportElapsedTime) { + std::string extra_header_string = extra_headers_.ToString(); + static const base::TimeDelta kSleepDuration = + base::TimeDelta::FromMilliseconds(10); + + std::vector<MockWrite> data_writes = { + MockWrite(ASYNC, 0, + "GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n"), + MockWrite(ASYNC, 1, extra_header_string.data()), + }; + + std::vector<MockRead> data_reads = { + // Write one byte of the status line, followed by a pause. + MockRead(ASYNC, 2, "H"), + MockRead(ASYNC, ERR_IO_PENDING, 3), + MockRead(ASYNC, 4, "TTP/1.1 200 OK\r\n\r\n"), + MockRead(ASYNC, 5, "hello world"), + MockRead(SYNCHRONOUS, OK, 6), + }; + + SequencedSocketData data(data_reads, data_writes); + session_deps_.socket_factory->AddSocketDataProvider(&data); + + SSLSocketDataProvider ssl(ASYNC, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); + + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + + auto trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get()); + + TestCompletionCallback callback; + + int rv = trans->Start(&request_, callback.callback(), NetLogWithSource()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + data.RunUntilPaused(); + ASSERT_TRUE(data.IsPaused()); + FastForwardBy(kSleepDuration); + data.Resume(); + + EXPECT_THAT(callback.GetResult(rv), IsOk()); + + std::string response_data; + ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk()); + EXPECT_EQ("hello world", response_data); + + trans.reset(); + ASSERT_EQ(1u, network_error_logging_service()->errors().size()); - const auto& error = network_error_logging_service()->errors()[0]; - EXPECT_EQ(kUserAgent, error.user_agent); + + CheckReport(0 /* index */, 200 /* status_code */, OK); + + const NetworkErrorLoggingService::RequestDetails& error = + network_error_logging_service()->errors()[0]; + + // Sanity-check elapsed time in error report + EXPECT_EQ(kSleepDuration, error.elapsed_time); } + #endif // BUILDFLAG(ENABLE_REPORTING) } // namespace net
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index c333199..4397ae6 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -35,7 +35,7 @@ #include "net/spdy/spdy_test_util_common.h" #include "net/test/gtest_util.h" #include "net/test/test_with_scoped_task_environment.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/net/http/http_proxy_client_socket_wrapper_unittest.cc b/net/http/http_proxy_client_socket_wrapper_unittest.cc index 40f235c..d5d3d563 100644 --- a/net/http/http_proxy_client_socket_wrapper_unittest.cc +++ b/net/http/http_proxy_client_socket_wrapper_unittest.cc
@@ -89,18 +89,20 @@ quic::QuicUtils::GetHeadersStreamId(quic_version_) + quic::QuicUtils::StreamIdDelta(quic_version_)), client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), - client_maker_(quic_version_, - quic::EmptyQuicConnectionId(), - &clock_, - kProxyHost, - quic::Perspective::IS_CLIENT, - client_headers_include_h2_stream_dependency_), - server_maker_(quic_version_, - quic::EmptyQuicConnectionId(), - &clock_, - kProxyHost, - quic::Perspective::IS_SERVER, - false), + client_maker_( + quic_version_, + quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, + kProxyHost, + quic::Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), + server_maker_( + quic_version_, + quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, + kProxyHost, + quic::Perspective::IS_SERVER, + false), header_stream_offset_(0), response_offset_(0), store_server_configs_in_properties_(false),
diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h index 2dc2332..fef3509 100644 --- a/net/http/http_server_properties.h +++ b/net/http/http_server_properties.h
@@ -23,8 +23,8 @@ #include "net/third_party/quic/core/quic_bandwidth.h" #include "net/third_party/quic/core/quic_server_id.h" #include "net/third_party/quic/core/quic_versions.h" -#include "net/third_party/spdy/core/spdy_framer.h" // TODO(willchan): Reconsider this. -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" // TODO(willchan): Reconsider this. +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "url/scheme_host_port.h" namespace base {
diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc index aaa8f769..ce140ab 100644 --- a/net/http/http_stream_factory.cc +++ b/net/http/http_stream_factory.cc
@@ -33,7 +33,7 @@ #include "net/spdy/spdy_http_stream.h" #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/core/quic_server_id.h" -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" +#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h" #include "url/gurl.h" #include "url/scheme_host_port.h" #include "url/url_constants.h"
diff --git a/net/http/http_stream_factory_job.cc b/net/http/http_stream_factory_job.cc index 67b31b2b..5579cae9 100644 --- a/net/http/http_stream_factory_job.cc +++ b/net/http/http_stream_factory_job.cc
@@ -56,7 +56,7 @@ #include "net/spdy/spdy_session_pool.h" #include "net/ssl/channel_id_service.h" #include "net/ssl/ssl_cert_request_info.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "url/url_constants.h" namespace net {
diff --git a/net/http/http_stream_factory_job_controller_unittest.cc b/net/http/http_stream_factory_job_controller_unittest.cc index 0954530..26cb63ba 100644 --- a/net/http/http_stream_factory_job_controller_unittest.cc +++ b/net/http/http_stream_factory_job_controller_unittest.cc
@@ -43,6 +43,7 @@ #include "net/socket/socket_test_util.h" #include "net/spdy/spdy_test_util_common.h" #include "net/test/test_with_scoped_task_environment.h" +#include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/test_tools/mock_random.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" @@ -349,7 +350,7 @@ quic::test::MockRandom random_generator_{0}; QuicTestPacketMaker client_maker_{ HttpNetworkSession::Params().quic_supported_versions[0], - quic::EmptyQuicConnectionId(), + quic::QuicUtils::CreateRandomConnectionId(&random_generator_), &clock_, kServerHostname, quic::Perspective::IS_CLIENT,
diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc index 3d68939..adf774b9a 100644 --- a/net/http/http_stream_factory_unittest.cc +++ b/net/http/http_stream_factory_unittest.cc
@@ -62,6 +62,7 @@ #include "net/test/test_data_directory.h" #include "net/test/test_with_scoped_task_environment.h" #include "net/third_party/quic/core/quic_server_id.h" +#include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/test_tools/crypto_test_utils.h" #include "net/third_party/quic/test_tools/mock_random.h" #include "net/third_party/quic/test_tools/quic_test_utils.h" @@ -2360,19 +2361,21 @@ : default_url_(kDefaultUrl), version_(std::get<0>(GetParam())), client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), - client_packet_maker_(version_, - quic::EmptyQuicConnectionId(), - &clock_, - "www.example.org", - quic::Perspective::IS_CLIENT, - client_headers_include_h2_stream_dependency_), - server_packet_maker_(version_, - quic::EmptyQuicConnectionId(), - &clock_, - "www.example.org", - quic::Perspective::IS_SERVER, - false), random_generator_(0), + client_packet_maker_( + version_, + quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, + "www.example.org", + quic::Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), + server_packet_maker_( + version_, + quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, + "www.example.org", + quic::Perspective::IS_SERVER, + false), proxy_resolution_service_(ProxyResolutionService::CreateDirect()), ssl_config_service_(new SSLConfigServiceDefaults) { clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(20)); @@ -2451,11 +2454,11 @@ const quic::QuicTransportVersion version_; const bool client_headers_include_h2_stream_dependency_; quic::MockClock clock_; + quic::test::MockRandom random_generator_; test::QuicTestPacketMaker client_packet_maker_; test::QuicTestPacketMaker server_packet_maker_; MockTaggingClientSocketFactory socket_factory_; std::unique_ptr<HttpNetworkSession> session_; - quic::test::MockRandom random_generator_; MockCertVerifier cert_verifier_; ProofVerifyDetailsChromium verify_details_; MockCryptoClientStreamFactory crypto_client_stream_factory_;
diff --git a/net/quic/bidirectional_stream_quic_impl.cc b/net/quic/bidirectional_stream_quic_impl.cc index d20924f..68d2f64 100644 --- a/net/quic/bidirectional_stream_quic_impl.cc +++ b/net/quic/bidirectional_stream_quic_impl.cc
@@ -17,7 +17,7 @@ #include "net/spdy/spdy_http_utils.h" #include "net/third_party/quic/core/quic_connection.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "quic_http_stream.h" namespace net {
diff --git a/net/quic/bidirectional_stream_quic_impl.h b/net/quic/bidirectional_stream_quic_impl.h index 16c8a84..aa5f938 100644 --- a/net/quic/bidirectional_stream_quic_impl.h +++ b/net/quic/bidirectional_stream_quic_impl.h
@@ -17,7 +17,7 @@ #include "net/http/bidirectional_stream_impl.h" #include "net/quic/quic_chromium_client_session.h" #include "net/quic/quic_chromium_client_stream.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" namespace base { class OneShotTimer;
diff --git a/net/quic/bidirectional_stream_quic_impl_unittest.cc b/net/quic/bidirectional_stream_quic_impl_unittest.cc index fc5ccb4..90079c9b 100644 --- a/net/quic/bidirectional_stream_quic_impl_unittest.cc +++ b/net/quic/bidirectional_stream_quic_impl_unittest.cc
@@ -414,7 +414,7 @@ crypto_config_(quic::test::crypto_test_utils::ProofVerifierForTesting(), quic::TlsClientHandshaker::CreateSslCtx()), read_buffer_(base::MakeRefCounted<IOBufferWithSize>(4096)), - connection_id_(quic::QuicConnectionIdFromUInt64(2)), + connection_id_(quic::test::TestConnectionId(2)), stream_id_(GetNthClientInitiatedBidirectionalStreamId(0)), client_maker_(version_, connection_id_, @@ -870,7 +870,7 @@ &spdy_request_headers_frame_length, &header_stream_offset)); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructInitialSettingsPacket(2, &header_stream_offset)); - AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(3, 3, 1, 2)); Initialize(); @@ -891,7 +891,7 @@ ConfirmHandshake(); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -979,7 +979,7 @@ GetNthClientInitiatedBidirectionalStreamId(0), nullptr, &offset)); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructInitialSettingsPacket(3, &offset)); - AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(4, 3, 1, 2)); Initialize(); BidirectionalStreamRequestInfo request; @@ -1009,7 +1009,7 @@ ConfirmHandshake(); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. offset = 0; @@ -1062,7 +1062,7 @@ } // Ack server's data packet. - AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(4, 3, 1, 2)); const char kBody3[] = "hello there"; const char kBody4[] = "another piece of small data"; const char kBody5[] = "really small"; @@ -1114,7 +1114,7 @@ delegate->WaitUntilNextCallback(kOnDataSent); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -1199,7 +1199,7 @@ } // Ack server's data packet. - AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(3, 3, 1, 2)); const char kBody2[] = "really small"; quic::QuicString header2 = ConstructDataHeader(strlen(kBody2)); quic::QuicStreamOffset data_offset = strlen(kBody1) + header.length(); @@ -1237,7 +1237,7 @@ delegate->WaitUntilNextCallback(kOnDataSent); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -1318,7 +1318,7 @@ } // Ack server's data packet. - AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(3, 3, 1, 2)); const char kBody3[] = "hello there"; const char kBody4[] = "another piece of small data"; const char kBody5[] = "really small"; @@ -1365,7 +1365,7 @@ delegate->WaitUntilNextCallback(kOnDataSent); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -1522,7 +1522,7 @@ 0, {kUploadData})); } - AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(4, 3, 1, 2)); Initialize(); @@ -1549,7 +1549,7 @@ delegate->WaitUntilNextCallback(kOnDataSent); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -1615,7 +1615,7 @@ 0, {kUploadData})); } - AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(4, 3, 1, 2)); Initialize(); @@ -1643,7 +1643,7 @@ delegate->WaitUntilNextCallback(kOnDataSent); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -1703,7 +1703,7 @@ quic::QuicString header = ConstructDataHeader(strlen(kUploadData)); if (version_ != quic::QUIC_VERSION_99) { - AddWrite(ConstructAckAndDataPacket(3, !kIncludeVersion, 2, 1, 1, !kFin, 0, + AddWrite(ConstructAckAndDataPacket(3, !kIncludeVersion, 2, 1, 2, !kFin, 0, kUploadData, &client_maker_)); AddWrite(ConstructAckAndDataPacket(4, !kIncludeVersion, 3, 3, 3, kFin, strlen(kUploadData), kUploadData, @@ -1733,7 +1733,7 @@ delegate->WaitUntilNextCallback(kOnStreamReady); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -1856,7 +1856,7 @@ client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructInitialSettingsPacket(2, &header_stream_offset)); // Why does QUIC ack Rst? Is this expected? - AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(3, 3, 1, 2)); Initialize(); @@ -1876,7 +1876,7 @@ ConfirmHandshake(); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -1936,7 +1936,7 @@ delegate->WaitUntilNextCallback(kOnStreamReady); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -2088,7 +2088,7 @@ AddWrite(ConstructRequestHeadersPacketInner( 2, GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length, &header_stream_offset)); - AddWrite(ConstructClientAckAndRstStreamPacket(3, 2, 1, 1)); + AddWrite(ConstructClientAckAndRstStreamPacket(3, 2, 1, 2)); Initialize(); @@ -2108,7 +2108,7 @@ delegate->WaitUntilNextCallback(kOnStreamReady); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -2144,7 +2144,7 @@ AddWrite(ConstructRequestHeadersPacketInner( 2, GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length, &header_stream_offset)); - AddWrite(ConstructClientAckAndRstStreamPacket(3, 2, 1, 1)); + AddWrite(ConstructClientAckAndRstStreamPacket(3, 2, 1, 2)); Initialize(); @@ -2165,7 +2165,7 @@ delegate->WaitUntilNextCallback(kOnStreamReady); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -2192,7 +2192,7 @@ AddWrite(ConstructRequestHeadersPacketInner( 2, GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length, &header_stream_offset)); - AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(3, 3, 1, 2)); AddWrite(ConstructClientRstStreamPacket(4)); Initialize(); @@ -2213,7 +2213,7 @@ delegate->WaitUntilNextCallback(kOnStreamReady); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -2260,7 +2260,7 @@ AddWrite(ConstructClientMultipleDataFramesPacket(3, kIncludeVersion, kFin, 0, {kBody})); } - AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(4, 3, 1, 2)); Initialize(); @@ -2287,7 +2287,7 @@ delegate->WaitUntilNextCallback(kOnDataSent); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); @@ -2327,8 +2327,8 @@ client_maker_.SetLongHeaderType(quic::ZERO_RTT_PROTECTED); AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); - AddWrite(ConstructClientAckPacket(2, 3, 1, 1)); // Ack the data packet - AddWrite(ConstructClientAckAndRstStreamPacket(3, 4, 4, 1)); + AddWrite(ConstructClientAckPacket(2, 3, 1, 2)); // Ack the data packet + AddWrite(ConstructClientAckAndRstStreamPacket(3, 4, 4, 2)); Initialize(); @@ -2348,7 +2348,7 @@ delegate->WaitUntilNextCallback(kOnStreamReady); // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Server sends the response headers. spdy::SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc index 3c20ccf5..276e049 100644 --- a/net/quic/quic_chromium_client_session.cc +++ b/net/quic/quic_chromium_client_session.cc
@@ -117,9 +117,7 @@ std::string reason, NetLogCaptureMode capture_mode) { std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetString( - "connection_id", - base::NumberToString(quic::QuicConnectionIdToUInt64(connection_id))); + dict->SetString("connection_id", connection_id.ToString()); dict->SetString("reason", reason); return std::move(dict); } @@ -128,9 +126,7 @@ quic::QuicConnectionId connection_id, NetLogCaptureMode capture_mode) { std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetString( - "connection_id", - base::NumberToString(quic::QuicConnectionIdToUInt64(connection_id))); + dict->SetString("connection_id", connection_id.ToString()); return std::move(dict); } @@ -2707,9 +2703,7 @@ dict->SetInteger("total_streams", num_total_streams_); dict->SetString("peer_address", peer_address().ToString()); - dict->SetKey( - "connection_id", - NetLogNumberValue(quic::QuicConnectionIdToUInt64(connection_id()))); + dict->SetString("connection_id", connection_id().ToString()); dict->SetBoolean("connected", connection()->connected()); const quic::QuicConnectionStats& stats = connection()->GetStats(); dict->SetInteger("packets_sent", stats.packets_sent);
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc index e978c215e..fcb13dc 100644 --- a/net/quic/quic_chromium_client_session_test.cc +++ b/net/quic/quic_chromium_client_session_test.cc
@@ -44,6 +44,7 @@ #include "net/third_party/quic/core/http/quic_client_promised_info.h" #include "net/third_party/quic/core/quic_connection_id.h" #include "net/third_party/quic/core/quic_packet_writer.h" +#include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/core/tls_client_handshaker.h" #include "net/third_party/quic/platform/api/quic_flags.h" #include "net/third_party/quic/platform/api/quic_test.h" @@ -54,7 +55,7 @@ #include "net/third_party/quic/test_tools/quic_stream_peer.h" #include "net/third_party/quic/test_tools/quic_test_utils.h" #include "net/third_party/quic/test_tools/simple_quic_framer.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" +#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" @@ -113,13 +114,13 @@ SocketTag()), destination_(kServerHostname, kServerPort), client_maker_(version_, - quic::EmptyQuicConnectionId(), + quic::QuicUtils::CreateRandomConnectionId(&random_), &clock_, kServerHostname, quic::Perspective::IS_CLIENT, client_headers_include_h2_stream_dependency_), server_maker_(version_, - quic::EmptyQuicConnectionId(), + quic::QuicUtils::CreateRandomConnectionId(&random_), &clock_, kServerHostname, quic::Perspective::IS_SERVER, @@ -147,7 +148,7 @@ QuicChromiumPacketWriter* writer = new net::QuicChromiumPacketWriter( socket.get(), base::ThreadTaskRunnerHandle::Get().get()); quic::QuicConnection* connection = new quic::QuicConnection( - quic::EmptyQuicConnectionId(), + quic::QuicUtils::CreateRandomConnectionId(&random_), quic::QuicSocketAddress(quic::QuicSocketAddressImpl(kIpEndPoint)), &helper_, &alarm_factory_, writer, true, quic::Perspective::IS_CLIENT, quic::test::SupportedVersions( @@ -730,6 +731,9 @@ } TEST_P(QuicChromiumClientSessionTest, ConnectionCloseBeforeHandshakeConfirmed) { + // Force the connection close packet to use long headers with connection ID. + server_maker_.SetEncryptionLevel(quic::ENCRYPTION_INITIAL); + MockQuicData quic_data; quic_data.AddRead(ASYNC, ERR_IO_PENDING); quic_data.AddRead(
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc index 09a115c..c10dd4f9 100644 --- a/net/quic/quic_connection_logger.cc +++ b/net/quic/quic_connection_logger.cc
@@ -99,9 +99,8 @@ const quic::QuicPacketHeader* header, NetLogCaptureMode /* capture_mode */) { std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetKey("connection_id", - NetLogNumberValue(quic::QuicConnectionIdToUInt64( - header->destination_connection_id))); + dict->SetString("connection_id", + header->destination_connection_id.ToString()); dict->SetInteger("reset_flag", header->reset_flag); dict->SetInteger("version_flag", header->version_flag); dict->SetKey("packet_number", NetLogNumberValue(header->packet_number));
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h index 2255eed..052ab391 100644 --- a/net/quic/quic_flags_list.h +++ b/net/quic/quic_flags_list.h
@@ -156,9 +156,6 @@ // If true, disable QUIC version 35. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_35, true) -// If true, then QuicCryptoServerConfig::ProcessClientHelloAfterGetProof() will -// use the async interface to KeyExchange::CalculateSharedKeys. -QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_use_async_key_exchange, true) // If true, increase size of random bytes in IETF stateless reset packet. QUIC_FLAG(bool, @@ -301,19 +298,19 @@ // byte order. QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_connection_ids_network_byte_order, - false) + true) // Allows use of new QUIC connection ID constructor designed for // variable-length connection IDs when acting as client. QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_variable_length_connection_ids_client, - false) + true) // Allows use of new QUIC connection ID constructor designed for // variable-length connection IDs when acting as server QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_variable_length_connection_ids_server, - false) + true) // If true, QuicPacketCreator::SetTransmissionType will set the transmission // type of the next successfully added frame. QUIC_FLAG(bool, @@ -329,3 +326,12 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_keep_ack_decimation_reordering, false) + +// If true, close QUIC connection if peer acks packet number 0 because our +// implementation never sends packet number 0. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disallow_peer_ack_0, true) + +// If true, log leaf cert subject name into warning log. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_log_cert_name_for_empty_sct, + true)
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc index eee4128..08f91f4c 100644 --- a/net/quic/quic_http_stream.cc +++ b/net/quic/quic_http_stream.cc
@@ -26,8 +26,8 @@ #include "net/third_party/quic/core/quic_stream_sequencer.h" #include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" -#include "net/third_party/spdy/core/spdy_frame_builder.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" namespace net {
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 9464c551a..c9455d8 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc
@@ -60,9 +60,9 @@ #include "net/third_party/quic/test_tools/quic_connection_peer.h" #include "net/third_party/quic/test_tools/quic_spdy_session_peer.h" #include "net/third_party/quic/test_tools/quic_test_utils.h" -#include "net/third_party/spdy/core/spdy_frame_builder.h" -#include "net/third_party/spdy/core/spdy_framer.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -197,7 +197,7 @@ read_buffer_(base::MakeRefCounted<IOBufferWithSize>(4096)), promise_id_(GetNthServerInitiatedUnidirectionalStreamId(0)), stream_id_(GetNthClientInitiatedBidirectionalStreamId(0)), - connection_id_(quic::QuicConnectionIdFromUInt64(2)), + connection_id_(quic::test::TestConnectionId(2)), client_maker_(version_, connection_id_, &clock_, @@ -591,7 +591,7 @@ std::unique_ptr<quic::QuicReceivedPacket> ConstructAckAndRstStreamPacket( quic::QuicPacketNumber packet_number) { - return ConstructAckAndRstStreamPacket(packet_number, 2, 1, 1); + return ConstructAckAndRstStreamPacket(packet_number, 2, 1, 2); } std::unique_ptr<quic::QuicReceivedPacket> ConstructClientAckPacket( @@ -774,7 +774,7 @@ stream_->SendRequest(headers_, &response_, callback_.callback())); // Ack the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()), IsError(ERR_IO_PENDING)); @@ -826,7 +826,7 @@ 3, GetNthClientInitiatedBidirectionalStreamId(1), kIncludeVersion, kFin, DEFAULT_PRIORITY, GetNthClientInitiatedBidirectionalStreamId(0), &spdy_request_header_frame_length, &offset)); - AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); // Ack the responses. + AddWrite(ConstructClientAckPacket(4, 3, 1, 2)); // Ack the responses. Initialize(); @@ -850,7 +850,7 @@ stream2.SendRequest(headers_, &response_, callback2.callback())); // Ack both requests. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()), IsError(ERR_IO_PENDING)); @@ -907,7 +907,7 @@ 2, GetNthClientInitiatedBidirectionalStreamId(0), kIncludeVersion, kFin, DEFAULT_PRIORITY, &spdy_request_header_frame_length, &header_stream_offset)); - AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); // Ack the data packet. + AddWrite(ConstructClientAckPacket(3, 3, 1, 2)); // Ack the data packet. Initialize(); @@ -921,7 +921,7 @@ EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, callback_.callback())); // Ack the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()), IsError(ERR_IO_PENDING)); @@ -1016,7 +1016,7 @@ stream_->SendRequest(headers_, &response_, callback_.callback())); // Ack the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()), IsError(ERR_IO_PENDING)); @@ -1145,7 +1145,7 @@ stream_->SendRequest(headers_, &response_, callback_.callback())); // Ack the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()), IsError(ERR_IO_PENDING)); @@ -1186,7 +1186,7 @@ stream_->SendRequest(headers_, &response_, callback_.callback())); // Ack the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()), IsError(ERR_IO_PENDING)); @@ -1252,7 +1252,7 @@ &spdy_request_headers_frame_length, {header, kUploadData})); } - AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(3, 3, 1, 2)); Initialize(); @@ -1275,7 +1275,7 @@ stream_->SendRequest(headers_, &response_, callback_.callback())); // Ack both packets in the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Send the response headers (but not the body). SetResponse("200 OK", string()); @@ -1333,7 +1333,7 @@ &spdy_request_headers_frame_length, {header, kUploadData})); } - AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(3, 3, 1, 2)); Initialize(); @@ -1356,7 +1356,7 @@ stream_->SendRequest(headers_, &response_, callback_.callback())); // Ack both packets in the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Send the response headers (but not the body). SetResponse("200 OK", string()); @@ -1422,7 +1422,7 @@ kUploadData)); } - AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(4, 3, 1, 2)); Initialize(); upload_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0); @@ -1446,7 +1446,7 @@ EXPECT_THAT(callback_.WaitForResult(), IsOk()); // Ack both packets in the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Send the response headers (but not the body). SetResponse("200 OK", string()); @@ -1505,7 +1505,7 @@ } AddWrite(ConstructClientDataPacket(3, kIncludeVersion, kFin, chunk_size + header.length(), "")); - AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(4, 3, 1, 2)); Initialize(); upload_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0); @@ -1528,7 +1528,7 @@ chunked_upload_stream->AppendData(nullptr, 0, true); EXPECT_THAT(callback_.WaitForResult(), IsOk()); - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Send the response headers (but not the body). SetResponse("200 OK", string()); @@ -1575,7 +1575,7 @@ DEFAULT_PRIORITY, &spdy_request_headers_frame_length, &header_stream_offset)); AddWrite(ConstructClientDataPacket(3, kIncludeVersion, kFin, 0, "")); - AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(4, 3, 1, 2)); Initialize(); upload_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0); @@ -1597,7 +1597,7 @@ chunked_upload_stream->AppendData(nullptr, 0, true); EXPECT_THAT(callback_.WaitForResult(), IsOk()); - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); // Send the response headers (but not the body). SetResponse("200 OK", string()); @@ -1656,7 +1656,7 @@ stream_->SendRequest(headers_, &response_, callback_.callback())); // Ack the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); EXPECT_THAT(stream_->ReadResponseHeaders( base::Bind(&QuicHttpStreamTest::CloseStream, base::Unretained(this), stream_.get())), @@ -1702,7 +1702,7 @@ stream_->SendRequest(headers_, &response_, callback_.callback())); // Ack the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()), IsError(ERR_IO_PENDING)); @@ -2316,7 +2316,7 @@ client_packet_number++, stream_id_ + quic::test::NextStreamId(version_), !kIncludeVersion, kFin, DEFAULT_PRIORITY, promise_id_, &spdy_request_header_frame_length, &header_stream_offset)); - AddWrite(ConstructClientAckPacket(client_packet_number++, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(client_packet_number++, 3, 1, 2)); AddWrite(ConstructClientRstStreamCancelledPacket(client_packet_number++)); Initialize(); @@ -2384,7 +2384,7 @@ // client-initiated version of |promised_stream_| works as intended. // Ack the request. - ProcessPacket(ConstructServerAckPacket(2, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(2, 1, 1, 1)); SetResponse("404 Not Found", string()); size_t spdy_response_header_frame_length; @@ -2482,7 +2482,7 @@ int result = stream_->SendRequest(headers_, &response_, callback_.callback()); - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); + ProcessPacket(ConstructServerAckPacket(1, 1, 1, 1)); SetResponse("200 OK", string()); EXPECT_THAT(result, IsError(ERR_IO_PENDING));
diff --git a/net/quic/quic_http_utils.h b/net/quic/quic_http_utils.h index 6e763c96..32ca7923 100644 --- a/net/quic/quic_http_utils.h +++ b/net/quic/quic_http_utils.h
@@ -10,8 +10,8 @@ #include "net/base/request_priority.h" #include "net/log/net_log_capture_mode.h" #include "net/third_party/quic/core/quic_packets.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace net {
diff --git a/net/quic/quic_http_utils_test.cc b/net/quic/quic_http_utils_test.cc index d06a531..e9f2746 100644 --- a/net/quic/quic_http_utils_test.cc +++ b/net/quic/quic_http_utils_test.cc
@@ -9,7 +9,7 @@ #include <limits> #include "net/third_party/quic/platform/api/quic_endian.h" -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" +#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h" #include "testing/gtest/include/gtest/gtest.h" namespace net {
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index fae3d65c..dccd471f 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc
@@ -73,8 +73,8 @@ #include "net/third_party/quic/test_tools/mock_random.h" #include "net/third_party/quic/test_tools/quic_spdy_session_peer.h" #include "net/third_party/quic/test_tools/quic_test_utils.h" -#include "net/third_party/spdy/core/spdy_frame_builder.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_job_factory_impl.h" @@ -259,24 +259,26 @@ : version_(std::get<0>(GetParam())), client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), supported_versions_(quic::test::SupportedTransportVersions(version_)), - client_maker_(version_, - quic::EmptyQuicConnectionId(), - &clock_, - kDefaultServerHostName, - quic::Perspective::IS_CLIENT, - client_headers_include_h2_stream_dependency_), - server_maker_(version_, - quic::EmptyQuicConnectionId(), - &clock_, - kDefaultServerHostName, - quic::Perspective::IS_SERVER, - false), + random_generator_(0), + client_maker_( + version_, + quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, + kDefaultServerHostName, + quic::Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), + server_maker_( + version_, + quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, + kDefaultServerHostName, + quic::Perspective::IS_SERVER, + false), cert_transparency_verifier_(new MultiLogCTVerifier()), ssl_config_service_(new SSLConfigServiceDefaults), proxy_resolution_service_(ProxyResolutionService::CreateDirect()), auth_handler_factory_( HttpAuthHandlerFactory::CreateDefault(&host_resolver_)), - random_generator_(0), ssl_data_(ASYNC, OK) { request_.method = "GET"; std::string url("https://"); @@ -948,6 +950,7 @@ quic::QuicTransportVersionVector supported_versions_; QuicFlagSaver flags_; // Save/restore all QUIC flag values. quic::MockClock clock_; + quic::test::MockRandom random_generator_; QuicTestPacketMaker client_maker_; QuicTestPacketMaker server_maker_; std::unique_ptr<HttpNetworkSession> session_; @@ -963,7 +966,6 @@ std::unique_ptr<SSLConfigServiceDefaults> ssl_config_service_; std::unique_ptr<ProxyResolutionService> proxy_resolution_service_; std::unique_ptr<HttpAuthHandlerFactory> auth_handler_factory_; - quic::test::MockRandom random_generator_; HttpServerPropertiesImpl http_server_properties_; HttpNetworkSession::Params session_params_; HttpNetworkSession::Context session_context_; @@ -4138,12 +4140,12 @@ // Second request will go over the pooled QUIC connection, but will be // reset by the server. QuicTestPacketMaker client_maker2( - version_, quic::EmptyQuicConnectionId(), &clock_, origin2.host(), - quic::Perspective::IS_CLIENT, + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, origin2.host(), quic::Perspective::IS_CLIENT, client_headers_include_h2_stream_dependency_); - QuicTestPacketMaker server_maker2(version_, quic::EmptyQuicConnectionId(), - &clock_, origin2.host(), - quic::Perspective::IS_SERVER, false); + QuicTestPacketMaker server_maker2( + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, origin2.host(), quic::Perspective::IS_SERVER, false); mock_quic_data.AddWrite( SYNCHRONOUS, ConstructClientRequestHeadersPacket( @@ -4527,12 +4529,12 @@ // Second request. QuicTestPacketMaker client_maker2( - version_, quic::EmptyQuicConnectionId(), &clock_, origin2.host(), - quic::Perspective::IS_CLIENT, + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, origin2.host(), quic::Perspective::IS_CLIENT, client_headers_include_h2_stream_dependency_); - QuicTestPacketMaker server_maker2(version_, quic::EmptyQuicConnectionId(), - &clock_, origin2.host(), - quic::Perspective::IS_SERVER, false); + QuicTestPacketMaker server_maker2( + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, origin2.host(), quic::Perspective::IS_SERVER, false); mock_quic_data.AddWrite( SYNCHRONOUS, ConstructClientRequestHeadersPacket( @@ -4640,8 +4642,8 @@ quic::QuicStreamOffset response_header_offset = 0; QuicTestPacketMaker client_maker( - version_, quic::EmptyQuicConnectionId(), &clock_, "mail.example.org", - quic::Perspective::IS_CLIENT, + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, "mail.example.org", quic::Perspective::IS_CLIENT, client_headers_include_h2_stream_dependency_); server_maker_.set_hostname("www.example.org"); client_maker_.set_hostname("www.example.org"); @@ -5598,7 +5600,8 @@ socket_factory_.AddSSLSocketDataProvider(&ssl_data_); CreateSession(); - AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START); + AddQuicAlternateProtocolMapping( + MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); SendRequestAndExpectHttpResponse("hello from http"); ExpectBrokenAlternateProtocolMapping(); } @@ -5905,12 +5908,8 @@ TEST_P(QuicNetworkTransactionTest, ConnectionCloseDuringConnect) { MockQuicData mock_quic_data; - mock_quic_data.AddRead(SYNCHRONOUS, ConstructServerConnectionClosePacket(1)); - mock_quic_data.AddWrite( - SYNCHRONOUS, ConstructClientRequestHeadersPacket( - 1, GetNthClientInitiatedBidirectionalStreamId(0), true, - true, GetRequestHeaders("GET", "https", "/"))); - mock_quic_data.AddWrite(SYNCHRONOUS, ConstructClientAckPacket(2, 1, 1, 1)); + mock_quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeDummyCHLOPacket(1)); + mock_quic_data.AddRead(ASYNC, ConstructServerConnectionClosePacket(1)); mock_quic_data.AddSocketDataToFactory(&socket_factory_); // When the QUIC connection fails, we will try the request again over HTTP. @@ -5939,7 +5938,9 @@ EXPECT_THAT(rv, IsOk()); CreateSession(); - AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT); + // TODO(rch): Check if we need a 0RTT version of ConnectionCloseDuringConnect + AddQuicAlternateProtocolMapping( + MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); SendRequestAndExpectHttpResponse("hello world"); } @@ -5973,7 +5974,8 @@ TEST_P(QuicNetworkTransactionTest, ConnectionCloseDuringConnectProxy) { MockQuicData mock_quic_data; - mock_quic_data.AddRead(SYNCHRONOUS, ConstructServerConnectionClosePacket(1)); + mock_quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeDummyCHLOPacket(1)); + mock_quic_data.AddRead(ASYNC, ConstructServerConnectionClosePacket(1)); mock_quic_data.AddWrite( SYNCHRONOUS, ConstructClientRequestHeadersPacket( 1, GetNthClientInitiatedBidirectionalStreamId(0), true, @@ -6017,6 +6019,8 @@ EXPECT_THAT(rv, IsOk()); CreateSession(); + crypto_client_stream_factory_.set_handshake_mode( + MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); SendRequestAndExpectHttpResponseFromProxy("hello world", true, 443); EXPECT_THAT(session_->proxy_resolution_service()->proxy_retry_info(), ElementsAre(Key("quic://myproxy.org:443"))); @@ -7223,12 +7227,12 @@ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); QuicTestPacketMaker client_maker( - version_, quic::EmptyQuicConnectionId(), &clock_, origin1_, - quic::Perspective::IS_CLIENT, + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, origin1_, quic::Perspective::IS_CLIENT, client_headers_include_h2_stream_dependency_); - QuicTestPacketMaker server_maker(version_, quic::EmptyQuicConnectionId(), - &clock_, origin1_, - quic::Perspective::IS_SERVER, false); + QuicTestPacketMaker server_maker( + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, origin1_, quic::Perspective::IS_SERVER, false); quic::QuicStreamOffset request_header_offset(0); quic::QuicStreamOffset response_header_offset(0); @@ -7324,12 +7328,12 @@ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2); QuicTestPacketMaker client_maker1( - version_, quic::EmptyQuicConnectionId(), &clock_, origin1_, - quic::Perspective::IS_CLIENT, + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, origin1_, quic::Perspective::IS_CLIENT, client_headers_include_h2_stream_dependency_); - QuicTestPacketMaker server_maker1(version_, quic::EmptyQuicConnectionId(), - &clock_, origin1_, - quic::Perspective::IS_SERVER, false); + QuicTestPacketMaker server_maker1( + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, origin1_, quic::Perspective::IS_SERVER, false); MockQuicData mock_quic_data1; quic::QuicStreamOffset header_stream_offset1 = 0; @@ -7356,12 +7360,12 @@ mock_quic_data1.AddSocketDataToFactory(&socket_factory_); QuicTestPacketMaker client_maker2( - version_, quic::EmptyQuicConnectionId(), &clock_, origin2_, - quic::Perspective::IS_CLIENT, + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, origin2_, quic::Perspective::IS_CLIENT, client_headers_include_h2_stream_dependency_); - QuicTestPacketMaker server_maker2(version_, quic::EmptyQuicConnectionId(), - &clock_, origin2_, - quic::Perspective::IS_SERVER, false); + QuicTestPacketMaker server_maker2( + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, origin2_, quic::Perspective::IS_SERVER, false); MockQuicData mock_quic_data2; quic::QuicStreamOffset header_stream_offset2 = 0; @@ -8416,12 +8420,12 @@ // reused. See http://crbug.com/544255. for (int i = 0; i < 2; ++i) { client_maker.reset(new QuicTestPacketMaker( - version_, quic::EmptyQuicConnectionId(), &clock_, - kDefaultServerHostName, quic::Perspective::IS_CLIENT, + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, kDefaultServerHostName, quic::Perspective::IS_CLIENT, client_headers_include_h2_stream_dependency_)); server_maker.reset(new QuicTestPacketMaker( - version_, quic::EmptyQuicConnectionId(), &clock_, - kDefaultServerHostName, quic::Perspective::IS_SERVER, false)); + version_, quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, kDefaultServerHostName, quic::Perspective::IS_SERVER, false)); session_params_.enable_quic = true; session_params_.enable_quic_proxies_for_https_urls = true;
diff --git a/net/quic/quic_proxy_client_socket_unittest.cc b/net/quic/quic_proxy_client_socket_unittest.cc index bafdfb3..0c4411f 100644 --- a/net/quic/quic_proxy_client_socket_unittest.cc +++ b/net/quic/quic_proxy_client_socket_unittest.cc
@@ -114,7 +114,7 @@ client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), crypto_config_(quic::test::crypto_test_utils::ProofVerifierForTesting(), quic::TlsClientHandshaker::CreateSslCtx()), - connection_id_(quic::QuicConnectionIdFromUInt64(2)), + connection_id_(quic::test::TestConnectionId(2)), client_maker_(version_, connection_id_, &clock_,
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index 14421d4..21a089d2 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc
@@ -53,6 +53,7 @@ #include "net/third_party/quic/core/crypto/quic_random.h" #include "net/third_party/quic/core/http/quic_client_promised_info.h" #include "net/third_party/quic/core/quic_connection.h" +#include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/core/tls_client_handshaker.h" #include "net/third_party/quic/platform/api/quic_clock.h" #include "net/third_party/quic/platform/api/quic_flags.h" @@ -1754,7 +1755,7 @@ } quic::QuicConnectionId connection_id = - quic::QuicConnectionIdFromUInt64(random_generator_->RandUint64()); + quic::QuicUtils::CreateRandomConnectionId(random_generator_); std::unique_ptr<QuicServerInfo> server_info; if (store_server_configs_in_properties_) { server_info = std::make_unique<PropertiesBasedQuicServerInfo>(
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index ada58429..1a3719d 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc
@@ -49,13 +49,14 @@ #include "net/third_party/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quic/core/http/quic_client_promised_info.h" +#include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/platform/api/quic_test.h" #include "net/third_party/quic/test_tools/mock_clock.h" #include "net/third_party/quic/test_tools/mock_random.h" #include "net/third_party/quic/test_tools/quic_config_peer.h" #include "net/third_party/quic/test_tools/quic_spdy_session_peer.h" #include "net/third_party/quic/test_tools/quic_test_utils.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" +#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -226,18 +227,20 @@ version_(version), client_headers_include_h2_stream_dependency_( client_headers_include_h2_stream_dependency), - client_maker_(version_, - quic::EmptyQuicConnectionId(), - &clock_, - kDefaultServerHostName, - quic::Perspective::IS_CLIENT, - client_headers_include_h2_stream_dependency_), - server_maker_(version_, - quic::EmptyQuicConnectionId(), - &clock_, - kDefaultServerHostName, - quic::Perspective::IS_SERVER, - false), + client_maker_( + version_, + quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, + kDefaultServerHostName, + quic::Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), + server_maker_( + version_, + quic::QuicUtils::CreateRandomConnectionId(&random_generator_), + &clock_, + kDefaultServerHostName, + quic::Perspective::IS_SERVER, + false), cert_verifier_(std::make_unique<MockCertVerifier>()), cert_transparency_verifier_(std::make_unique<DoNothingCTVerifier>()), scoped_mock_network_change_notifier_(nullptr),
diff --git a/net/quic/quic_test_packet_maker.h b/net/quic/quic_test_packet_maker.h index 8d45ef4..33b8d365 100644 --- a/net/quic/quic_test_packet_maker.h +++ b/net/quic/quic_test_packet_maker.h
@@ -19,8 +19,8 @@ #include "net/third_party/quic/platform/api/quic_string_piece.h" #include "net/third_party/quic/test_tools/mock_clock.h" #include "net/third_party/quic/test_tools/mock_random.h" -#include "net/third_party/spdy/core/spdy_framer.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace net { namespace test {
diff --git a/net/reporting/reporting_service.cc b/net/reporting/reporting_service.cc index 1b8ca07..58122f8 100644 --- a/net/reporting/reporting_service.cc +++ b/net/reporting/reporting_service.cc
@@ -49,8 +49,14 @@ if (!context_->delegate()->CanQueueReport(url::Origin::Create(url))) return; - context_->cache()->AddReport(url, user_agent, group, type, std::move(body), - depth, context_->tick_clock()->NowTicks(), 0); + // Strip username, password, and ref fragment from the URL. + GURL sanitized_url = url.GetAsReferrer(); + if (!sanitized_url.is_valid()) + return; + + context_->cache()->AddReport(sanitized_url, user_agent, group, type, + std::move(body), depth, + context_->tick_clock()->NowTicks(), 0); } void ProcessHeader(const GURL& url,
diff --git a/net/reporting/reporting_service_unittest.cc b/net/reporting/reporting_service_unittest.cc index 42613ede..3ca87ce8 100644 --- a/net/reporting/reporting_service_unittest.cc +++ b/net/reporting/reporting_service_unittest.cc
@@ -61,6 +61,31 @@ EXPECT_EQ(kType_, reports[0]->type); } +TEST_F(ReportingServiceTest, QueueReportSanitizeUrl) { + // Same as kUrl_ but with username, password, and fragment. + GURL url = GURL("https://username:password@origin/path#fragment"); + service()->QueueReport(url, kUserAgent_, kGroup_, kType_, + std::make_unique<base::DictionaryValue>(), 0); + + std::vector<const ReportingReport*> reports; + context()->cache()->GetReports(&reports); + ASSERT_EQ(1u, reports.size()); + EXPECT_EQ(kUrl_, reports[0]->url); + EXPECT_EQ(kUserAgent_, reports[0]->user_agent); + EXPECT_EQ(kGroup_, reports[0]->group); + EXPECT_EQ(kType_, reports[0]->type); +} + +TEST_F(ReportingServiceTest, DontQueueReportInvalidUrl) { + GURL url = GURL("https://"); + service()->QueueReport(url, kUserAgent_, kGroup_, kType_, + std::make_unique<base::DictionaryValue>(), 0); + + std::vector<const ReportingReport*> reports; + context()->cache()->GetReports(&reports); + ASSERT_EQ(0u, reports.size()); +} + TEST_F(ReportingServiceTest, ProcessHeader) { service()->ProcessHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" + kEndpoint_.spec() +
diff --git a/net/spdy/bidirectional_stream_spdy_impl.cc b/net/spdy/bidirectional_stream_spdy_impl.cc index 78c79ac5..89f217a 100644 --- a/net/spdy/bidirectional_stream_spdy_impl.cc +++ b/net/spdy/bidirectional_stream_spdy_impl.cc
@@ -16,7 +16,7 @@ #include "net/spdy/spdy_buffer.h" #include "net/spdy/spdy_http_utils.h" #include "net/spdy/spdy_stream.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" namespace net {
diff --git a/net/spdy/buffered_spdy_framer.h b/net/spdy/buffered_spdy_framer.h index 6605590..ca497b9 100644 --- a/net/spdy/buffered_spdy_framer.h +++ b/net/spdy/buffered_spdy_framer.h
@@ -17,11 +17,11 @@ #include "net/base/net_export.h" #include "net/log/net_log_source.h" #include "net/spdy/header_coalescer.h" -#include "net/third_party/spdy/core/http2_frame_decoder_adapter.h" -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" -#include "net/third_party/spdy/core/spdy_framer.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h" +#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace net {
diff --git a/net/spdy/fuzzing/hpack_example_generator.cc b/net/spdy/fuzzing/hpack_example_generator.cc index 201d1f4..c38b288 100644 --- a/net/spdy/fuzzing/hpack_example_generator.cc +++ b/net/spdy/fuzzing/hpack_example_generator.cc
@@ -8,10 +8,10 @@ #include "base/files/file_util.h" #include "base/strings/string_number_conversions.h" #include "net/spdy/fuzzing/hpack_fuzz_util.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/hpack/hpack_encoder.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h" namespace {
diff --git a/net/spdy/fuzzing/hpack_fuzz_util.cc b/net/spdy/fuzzing/hpack_fuzz_util.cc index 7b71bc4c..400ed0d 100644 --- a/net/spdy/fuzzing/hpack_fuzz_util.cc +++ b/net/spdy/fuzzing/hpack_fuzz_util.cc
@@ -9,8 +9,8 @@ #include "base/rand_util.h" #include "base/sys_byteorder.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/platform/api/spdy_ptr_util.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h" namespace spdy {
diff --git a/net/spdy/fuzzing/hpack_fuzz_util.h b/net/spdy/fuzzing/hpack_fuzz_util.h index 442885c..5d95ca2 100644 --- a/net/spdy/fuzzing/hpack_fuzz_util.h +++ b/net/spdy/fuzzing/hpack_fuzz_util.h
@@ -11,11 +11,11 @@ #include <memory> #include <vector> -#include "net/third_party/spdy/core/hpack/hpack_decoder_adapter.h" -#include "net/third_party/spdy/core/hpack/hpack_encoder.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_decoder_adapter.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h" namespace spdy {
diff --git a/net/spdy/fuzzing/hpack_fuzz_util_test.cc b/net/spdy/fuzzing/hpack_fuzz_util_test.cc index 78d569d4..8294fd4 100644 --- a/net/spdy/fuzzing/hpack_fuzz_util_test.cc +++ b/net/spdy/fuzzing/hpack_fuzz_util_test.cc
@@ -11,7 +11,7 @@ #include "base/files/file_util.h" #include "base/path_service.h" #include "base/stl_util.h" -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/net/spdy/header_coalescer.h b/net/spdy/header_coalescer.h index 06e80c26..2adde8c6 100644 --- a/net/spdy/header_coalescer.h +++ b/net/spdy/header_coalescer.h
@@ -8,8 +8,8 @@ #include "base/strings/string_piece.h" #include "net/base/net_export.h" #include "net/log/net_log_with_source.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_headers_handler_interface.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_headers_handler_interface.h" namespace net {
diff --git a/net/spdy/http2_priority_dependencies.h b/net/spdy/http2_priority_dependencies.h index b6a90bdf..077a3ac 100644 --- a/net/spdy/http2_priority_dependencies.h +++ b/net/spdy/http2_priority_dependencies.h
@@ -11,7 +11,7 @@ #include <vector> #include "net/base/net_export.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace net {
diff --git a/net/spdy/http2_push_promise_index.h b/net/spdy/http2_push_promise_index.h index 6bc914f..8e66891 100644 --- a/net/spdy/http2_push_promise_index.h +++ b/net/spdy/http2_push_promise_index.h
@@ -13,7 +13,7 @@ #include "net/base/net_export.h" #include "net/http/http_request_info.h" #include "net/spdy/spdy_session_key.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "url/gurl.h" namespace net {
diff --git a/net/spdy/multiplexed_http_stream.cc b/net/spdy/multiplexed_http_stream.cc index cdfb865..f47dc97 100644 --- a/net/spdy/multiplexed_http_stream.cc +++ b/net/spdy/multiplexed_http_stream.cc
@@ -8,7 +8,7 @@ #include "base/logging.h" #include "net/http/http_raw_request_headers.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" namespace net {
diff --git a/net/spdy/platform/impl/spdy_arraysize_impl.h b/net/spdy/platform/impl/spdy_arraysize_impl.h new file mode 100644 index 0000000..47a09d19 --- /dev/null +++ b/net/spdy/platform/impl/spdy_arraysize_impl.h
@@ -0,0 +1,12 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_ARRAYSIZE_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_ARRAYSIZE_IMPL_H_ + +#include "base/stl_util.h" + +#define SPDY_ARRAYSIZE_IMPL(x) base::size(x) + +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_ARRAYSIZE_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_bug_tracker_impl.h b/net/spdy/platform/impl/spdy_bug_tracker_impl.h similarity index 63% rename from net/third_party/spdy/platform/impl/spdy_bug_tracker_impl.h rename to net/spdy/platform/impl/spdy_bug_tracker_impl.h index 096aadb..2d4bab9 100644 --- a/net/third_party/spdy/platform/impl/spdy_bug_tracker_impl.h +++ b/net/spdy/platform/impl/spdy_bug_tracker_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_BUG_TRACKER_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_BUG_TRACKER_IMPL_H_ +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_BUG_TRACKER_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_BUG_TRACKER_IMPL_H_ #include "base/logging.h" @@ -11,4 +11,4 @@ #define SPDY_BUG_IF_IMPL(condition) LOG_IF(DFATAL, (condition)) #define FLAGS_spdy_always_log_bugs_for_tests_impl (true) -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_BUG_TRACKER_IMPL_H_ +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_BUG_TRACKER_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_containers_impl.h b/net/spdy/platform/impl/spdy_containers_impl.h similarity index 84% rename from net/third_party/spdy/platform/impl/spdy_containers_impl.h rename to net/spdy/platform/impl/spdy_containers_impl.h index 6f67564c..b0dc3803 100644 --- a/net/third_party/spdy/platform/impl/spdy_containers_impl.h +++ b/net/spdy/platform/impl/spdy_containers_impl.h
@@ -1,8 +1,8 @@ // Copyright (c) 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_CONTAINERS_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_CONTAINERS_IMPL_H_ +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_CONTAINERS_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_CONTAINERS_IMPL_H_ #include <unordered_map> #include <unordered_set> @@ -36,4 +36,4 @@ } // namespace spdy -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_CONTAINERS_IMPL_H_ +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_CONTAINERS_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_endianness_util_impl.h b/net/spdy/platform/impl/spdy_endianness_util_impl.h similarity index 76% rename from net/third_party/spdy/platform/impl/spdy_endianness_util_impl.h rename to net/spdy/platform/impl/spdy_endianness_util_impl.h index 315bed3..901f5ba1 100644 --- a/net/third_party/spdy/platform/impl/spdy_endianness_util_impl.h +++ b/net/spdy/platform/impl/spdy_endianness_util_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_ENDIANNESS_UTIL_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_ENDIANNESS_UTIL_IMPL_H_ +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_ENDIANNESS_UTIL_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_ENDIANNESS_UTIL_IMPL_H_ #include "base/sys_byteorder.h" @@ -31,4 +31,4 @@ return base::HostToNet64(x); } -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_ENDIANNESS_UTIL_IMPL_H_ +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_ENDIANNESS_UTIL_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_estimate_memory_usage_impl.h b/net/spdy/platform/impl/spdy_estimate_memory_usage_impl.h similarity index 63% rename from net/third_party/spdy/platform/impl/spdy_estimate_memory_usage_impl.h rename to net/spdy/platform/impl/spdy_estimate_memory_usage_impl.h index 70e8b16..e3882c5e 100644 --- a/net/third_party/spdy/platform/impl/spdy_estimate_memory_usage_impl.h +++ b/net/spdy/platform/impl/spdy_estimate_memory_usage_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_ESTIMATE_MEMORY_USAGE_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_ESTIMATE_MEMORY_USAGE_IMPL_H_ +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_ESTIMATE_MEMORY_USAGE_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_ESTIMATE_MEMORY_USAGE_IMPL_H_ #include <cstddef> @@ -18,4 +18,4 @@ } // namespace spdy -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_ESTIMATE_MEMORY_USAGE_IMPL_H_ +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_ESTIMATE_MEMORY_USAGE_IMPL_H_
diff --git a/net/spdy/platform/impl/spdy_export_impl.h b/net/spdy/platform/impl/spdy_export_impl.h new file mode 100644 index 0000000..d5528a7 --- /dev/null +++ b/net/spdy/platform/impl/spdy_export_impl.h
@@ -0,0 +1,13 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_EXPORT_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_EXPORT_IMPL_H_ + +#include "net/base/net_export.h" + +#define SPDY_EXPORT NET_EXPORT +#define SPDY_EXPORT_PRIVATE NET_EXPORT_PRIVATE + +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_EXPORT_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_flags_impl.cc b/net/spdy/platform/impl/spdy_flags_impl.cc similarity index 76% rename from net/third_party/spdy/platform/impl/spdy_flags_impl.cc rename to net/spdy/platform/impl/spdy_flags_impl.cc index 17c9fb20..f36c4bc 100644 --- a/net/third_party/spdy/platform/impl/spdy_flags_impl.cc +++ b/net/spdy/platform/impl/spdy_flags_impl.cc
@@ -2,6 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/third_party/spdy/platform/impl/spdy_flags_impl.h" +#include "net/spdy/platform/impl/spdy_flags_impl.h" namespace spdy {} // namespace spdy
diff --git a/net/third_party/spdy/platform/impl/spdy_flags_impl.h b/net/spdy/platform/impl/spdy_flags_impl.h similarity index 66% rename from net/third_party/spdy/platform/impl/spdy_flags_impl.h rename to net/spdy/platform/impl/spdy_flags_impl.h index d5a1937..48a03b90 100644 --- a/net/third_party/spdy/platform/impl/spdy_flags_impl.h +++ b/net/spdy/platform/impl/spdy_flags_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_FLAGS_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_FLAGS_IMPL_H_ +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_FLAGS_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_FLAGS_IMPL_H_ #include "net/base/net_export.h" @@ -19,4 +19,4 @@ } // namespace spdy -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_FLAGS_IMPL_H_ +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_FLAGS_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_macros_impl.h b/net/spdy/platform/impl/spdy_macros_impl.h similarity index 65% rename from net/third_party/spdy/platform/impl/spdy_macros_impl.h rename to net/spdy/platform/impl/spdy_macros_impl.h index 0dceaac0..e562f11 100644 --- a/net/third_party/spdy/platform/impl/spdy_macros_impl.h +++ b/net/spdy/platform/impl/spdy_macros_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_MACROS_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_MACROS_IMPL_H_ +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_MACROS_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_MACROS_IMPL_H_ #include "base/compiler_specific.h" #include "base/logging.h" @@ -13,4 +13,4 @@ #define SPDY_DVLOG_IF_IMPL DVLOG_IF -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_MACROS_IMPL_H_ +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_MACROS_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_mem_slice_impl.cc b/net/spdy/platform/impl/spdy_mem_slice_impl.cc similarity index 93% rename from net/third_party/spdy/platform/impl/spdy_mem_slice_impl.cc rename to net/spdy/platform/impl/spdy_mem_slice_impl.cc index 997cf18..e51c593 100644 --- a/net/third_party/spdy/platform/impl/spdy_mem_slice_impl.cc +++ b/net/spdy/platform/impl/spdy_mem_slice_impl.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/third_party/spdy/platform/impl/spdy_mem_slice_impl.h" +#include "net/spdy/platform/impl/spdy_mem_slice_impl.h" #include <utility>
diff --git a/net/third_party/spdy/platform/impl/spdy_mem_slice_impl.h b/net/spdy/platform/impl/spdy_mem_slice_impl.h similarity index 85% rename from net/third_party/spdy/platform/impl/spdy_mem_slice_impl.h rename to net/spdy/platform/impl/spdy_mem_slice_impl.h index ea6e8d2..a4c58ff 100644 --- a/net/third_party/spdy/platform/impl/spdy_mem_slice_impl.h +++ b/net/spdy/platform/impl/spdy_mem_slice_impl.h
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_MEM_SLICE_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_MEM_SLICE_IMPL_H_ +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_MEM_SLICE_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_MEM_SLICE_IMPL_H_ #include "base/memory/ref_counted.h" #include "net/base/io_buffer.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h" namespace spdy { @@ -47,4 +47,4 @@ } // namespace spdy -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_MEM_SLICE_IMPL_H_ +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_MEM_SLICE_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_ptr_util_impl.h b/net/spdy/platform/impl/spdy_ptr_util_impl.h similarity index 73% rename from net/third_party/spdy/platform/impl/spdy_ptr_util_impl.h rename to net/spdy/platform/impl/spdy_ptr_util_impl.h index 68fde31..8d80fd7 100644 --- a/net/third_party/spdy/platform/impl/spdy_ptr_util_impl.h +++ b/net/spdy/platform/impl/spdy_ptr_util_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_PTR_UTIL_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_PTR_UTIL_IMPL_H_ +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_PTR_UTIL_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_PTR_UTIL_IMPL_H_ #include <memory> #include <utility> @@ -24,4 +24,4 @@ } // namespace spdy -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_PTR_UTIL_IMPL_H_ +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_PTR_UTIL_IMPL_H_
diff --git a/net/spdy/platform/impl/spdy_string_impl.h b/net/spdy/platform/impl/spdy_string_impl.h new file mode 100644 index 0000000..8bf8a7c --- /dev/null +++ b/net/spdy/platform/impl/spdy_string_impl.h
@@ -0,0 +1,16 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_STRING_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_STRING_IMPL_H_ + +#include <string> + +namespace spdy { + +using SpdyStringImpl = std::string; + +} // namespace spdy + +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_STRING_IMPL_H_
diff --git a/net/spdy/platform/impl/spdy_string_piece_impl.h b/net/spdy/platform/impl/spdy_string_piece_impl.h new file mode 100644 index 0000000..e6edcd3 --- /dev/null +++ b/net/spdy/platform/impl/spdy_string_piece_impl.h
@@ -0,0 +1,16 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_STRING_PIECE_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_STRING_PIECE_IMPL_H_ + +#include "base/strings/string_piece.h" + +namespace spdy { + +using SpdyStringPieceImpl = base::StringPiece; + +} // namespace spdy + +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_STRING_PIECE_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_string_utils_impl.cc b/net/spdy/platform/impl/spdy_string_utils_impl.cc similarity index 88% rename from net/third_party/spdy/platform/impl/spdy_string_utils_impl.cc rename to net/spdy/platform/impl/spdy_string_utils_impl.cc index e1ab8592..ffc90d56 100644 --- a/net/third_party/spdy/platform/impl/spdy_string_utils_impl.cc +++ b/net/spdy/platform/impl/spdy_string_utils_impl.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/third_party/spdy/platform/impl/spdy_string_utils_impl.h" +#include "net/spdy/platform/impl/spdy_string_utils_impl.h" #include <string>
diff --git a/net/third_party/spdy/platform/impl/spdy_string_utils_impl.h b/net/spdy/platform/impl/spdy_string_utils_impl.h similarity index 77% rename from net/third_party/spdy/platform/impl/spdy_string_utils_impl.h rename to net/spdy/platform/impl/spdy_string_utils_impl.h index b764ebe..3925cf8 100644 --- a/net/third_party/spdy/platform/impl/spdy_string_utils_impl.h +++ b/net/spdy/platform/impl/spdy_string_utils_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_STRING_UTILS_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_STRING_UTILS_IMPL_H_ +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_STRING_UTILS_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_STRING_UTILS_IMPL_H_ #include <sstream> #include <utility> @@ -12,9 +12,9 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "net/base/hex_utils.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_string.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h" namespace spdy { @@ -56,4 +56,4 @@ } // namespace spdy -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_STRING_UTILS_IMPL_H_ +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_STRING_UTILS_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_test_helpers_impl.h b/net/spdy/platform/impl/spdy_test_helpers_impl.h similarity index 69% rename from net/third_party/spdy/platform/impl/spdy_test_helpers_impl.h rename to net/spdy/platform/impl/spdy_test_helpers_impl.h index 4231aac..d029686 100644 --- a/net/third_party/spdy/platform/impl/spdy_test_helpers_impl.h +++ b/net/spdy/platform/impl/spdy_test_helpers_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_TEST_HELPERS_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_TEST_HELPERS_IMPL_H_ +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_TEST_HELPERS_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_TEST_HELPERS_IMPL_H_ #include "net/test/gtest_util.h"
diff --git a/net/spdy/platform/impl/spdy_test_utils_prod_impl.h b/net/spdy/platform/impl/spdy_test_utils_prod_impl.h new file mode 100644 index 0000000..b920d097 --- /dev/null +++ b/net/spdy/platform/impl/spdy_test_utils_prod_impl.h
@@ -0,0 +1,12 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_TEST_UTILS_PROD_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_TEST_UTILS_PROD_IMPL_H_ + +#include "base/gtest_prod_util.h" + +#define SPDY_FRIEND_TEST_IMPL FRIEND_TEST_ALL_PREFIXES + +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_TEST_UTILS_PROD_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl.cc b/net/spdy/platform/impl/spdy_unsafe_arena_impl.cc similarity index 97% rename from net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl.cc rename to net/spdy/platform/impl/spdy_unsafe_arena_impl.cc index 78653558..1d3aa9c 100644 --- a/net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl.cc +++ b/net/spdy/platform/impl/spdy_unsafe_arena_impl.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl.h" +#include "net/spdy/platform/impl/spdy_unsafe_arena_impl.h" #include <string.h>
diff --git a/net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl.h b/net/spdy/platform/impl/spdy_unsafe_arena_impl.h similarity index 87% rename from net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl.h rename to net/spdy/platform/impl/spdy_unsafe_arena_impl.h index f94a5cb0..f7867a7 100644 --- a/net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl.h +++ b/net/spdy/platform/impl/spdy_unsafe_arena_impl.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_UNSAFE_ARENA_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_UNSAFE_ARENA_IMPL_H_ +#ifndef NET_SPDY_PLATFORM_IMPL_SPDY_UNSAFE_ARENA_IMPL_H_ +#define NET_SPDY_PLATFORM_IMPL_SPDY_UNSAFE_ARENA_IMPL_H_ #include <memory> #include <vector> -#include "net/third_party/spdy/platform/api/spdy_export.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h" namespace spdy { @@ -74,4 +74,4 @@ } // namespace spdy -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_UNSAFE_ARENA_IMPL_H_ +#endif // NET_SPDY_PLATFORM_IMPL_SPDY_UNSAFE_ARENA_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl_test.cc b/net/spdy/platform/impl/spdy_unsafe_arena_impl_test.cc similarity index 96% rename from net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl_test.cc rename to net/spdy/platform/impl/spdy_unsafe_arena_impl_test.cc index 1f4f496..6a2b4a7 100644 --- a/net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl_test.cc +++ b/net/spdy/platform/impl/spdy_unsafe_arena_impl_test.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl.h" +#include "net/spdy/platform/impl/spdy_unsafe_arena_impl.h" #include <string> #include <vector> -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" +#include "net/third_party/quiche/src/spdy/platform/api/spdy_string_piece.h" #include "testing/gtest/include/gtest/gtest.h" namespace spdy {
diff --git a/net/spdy/spdy_buffer.cc b/net/spdy/spdy_buffer.cc index 171f6a35..0342cc6 100644 --- a/net/spdy/spdy_buffer.cc +++ b/net/spdy/spdy_buffer.cc
@@ -12,7 +12,7 @@ #include "base/macros.h" #include "base/trace_event/memory_usage_estimator.h" #include "net/base/io_buffer.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace net {
diff --git a/net/spdy/spdy_buffer_producer.cc b/net/spdy/spdy_buffer_producer.cc index eb90716f..355f5ce 100644 --- a/net/spdy/spdy_buffer_producer.cc +++ b/net/spdy/spdy_buffer_producer.cc
@@ -9,7 +9,7 @@ #include "base/logging.h" #include "base/trace_event/memory_usage_estimator.h" #include "net/spdy/spdy_buffer.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace net {
diff --git a/net/spdy/spdy_buffer_unittest.cc b/net/spdy/spdy_buffer_unittest.cc index 8343f26..f336983 100644 --- a/net/spdy/spdy_buffer_unittest.cc +++ b/net/spdy/spdy_buffer_unittest.cc
@@ -14,7 +14,7 @@ #include "base/memory/ref_counted.h" #include "base/stl_util.h" #include "net/base/io_buffer.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "testing/gtest/include/gtest/gtest.h" namespace net {
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc index decc783..62e070b 100644 --- a/net/spdy/spdy_http_stream.cc +++ b/net/spdy/spdy_http_stream.cc
@@ -27,8 +27,8 @@ #include "net/spdy/spdy_http_utils.h" #include "net/spdy/spdy_log_util.h" #include "net/spdy/spdy_session.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace net {
diff --git a/net/spdy/spdy_http_utils.h b/net/spdy/spdy_http_utils.h index 2a76eb8..d1622618 100644 --- a/net/spdy/spdy_http_utils.h +++ b/net/spdy/spdy_http_utils.h
@@ -7,9 +7,9 @@ #include "net/base/net_export.h" #include "net/base/request_priority.h" -#include "net/third_party/spdy/core/spdy_framer.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "url/gurl.h" namespace net {
diff --git a/net/spdy/spdy_http_utils_unittest.cc b/net/spdy/spdy_http_utils_unittest.cc index 24995dd..49dc331 100644 --- a/net/spdy/spdy_http_utils_unittest.cc +++ b/net/spdy/spdy_http_utils_unittest.cc
@@ -9,8 +9,8 @@ #include <limits> #include "net/http/http_request_info.h" -#include "net/third_party/spdy/core/spdy_framer.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace net {
diff --git a/net/spdy/spdy_log_util.h b/net/spdy/spdy_log_util.h index 4eb3c2ac..4eb89b2 100644 --- a/net/spdy/spdy_log_util.h +++ b/net/spdy/spdy_log_util.h
@@ -13,7 +13,7 @@ #include "net/http/http_log_util.h" #include "net/log/net_log.h" #include "net/log/net_log_capture_mode.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" namespace base { class ListValue;
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index e9047be..ea86d7c 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -54,8 +54,8 @@ #include "net/test/gtest_util.h" #include "net/test/test_data_directory.h" #include "net/test/test_with_scoped_task_environment.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/url_request_test_util.h" #include "net/websockets/websocket_test_util.h"
diff --git a/net/spdy/spdy_proxy_client_socket.h b/net/spdy/spdy_proxy_client_socket.h index 98948d5e..4465e5b 100644 --- a/net/spdy/spdy_proxy_client_socket.h +++ b/net/spdy/spdy_proxy_client_socket.h
@@ -31,7 +31,7 @@ #include "net/spdy/spdy_read_queue.h" #include "net/spdy/spdy_session.h" #include "net/spdy/spdy_stream.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/traffic_annotation/network_traffic_annotation.h" namespace net {
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc index 965e586..0f31adc 100644 --- a/net/spdy/spdy_proxy_client_socket_unittest.cc +++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -35,7 +35,7 @@ #include "net/test/gtest_util.h" #include "net/test/test_data_directory.h" #include "net/test/test_with_scoped_task_environment.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index 8e7e0c3..9c3605b 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc
@@ -56,8 +56,8 @@ #include "net/ssl/ssl_cipher_suite_names.h" #include "net/ssl/ssl_connection_status_flags.h" #include "net/third_party/quic/core/http/spdy_utils.h" -#include "net/third_party/spdy/core/spdy_frame_builder.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "url/url_constants.h" namespace net {
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h index 223f05d6..2f846ffd 100644 --- a/net/spdy/spdy_session.h +++ b/net/spdy/spdy_session.h
@@ -46,10 +46,10 @@ #include "net/spdy/spdy_stream.h" #include "net/spdy/spdy_write_queue.h" #include "net/ssl/ssl_config_service.h" -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" -#include "net/third_party/spdy/core/spdy_framer.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "url/gurl.h" #include "url/scheme_host_port.h"
diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc index 3672f3a..27e4f563 100644 --- a/net/spdy/spdy_session_pool.cc +++ b/net/spdy/spdy_session_pool.cc
@@ -28,9 +28,9 @@ #include "net/spdy/bidirectional_stream_spdy_impl.h" #include "net/spdy/spdy_http_stream.h" #include "net/spdy/spdy_session.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/hpack/hpack_huffman_table.h" -#include "net/third_party/spdy/core/hpack/hpack_static_table.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_static_table.h" namespace net {
diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h index f3564baa..4ff38a3f 100644 --- a/net/spdy/spdy_session_pool.h +++ b/net/spdy/spdy_session_pool.h
@@ -31,7 +31,7 @@ #include "net/spdy/spdy_session_key.h" #include "net/ssl/ssl_config_service.h" #include "net/third_party/quic/core/quic_versions.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace base { namespace trace_event {
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc index 47d7726b..878560da 100644 --- a/net/spdy/spdy_session_unittest.cc +++ b/net/spdy/spdy_session_unittest.cc
@@ -47,7 +47,7 @@ #include "net/test/gtest_util.h" #include "net/test/test_data_directory.h" #include "net/test/test_with_scoped_task_environment.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" +#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/platform_test.h"
diff --git a/net/spdy/spdy_stream.h b/net/spdy/spdy_stream.h index 97189763..35fdf444 100644 --- a/net/spdy/spdy_stream.h +++ b/net/spdy/spdy_stream.h
@@ -25,9 +25,9 @@ #include "net/socket/ssl_client_socket.h" #include "net/spdy/spdy_buffer.h" #include "net/ssl/ssl_client_cert_type.h" -#include "net/third_party/spdy/core/spdy_framer.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "url/gurl.h"
diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc index d29a5b96..0923dd0 100644 --- a/net/spdy/spdy_stream_unittest.cc +++ b/net/spdy/spdy_stream_unittest.cc
@@ -37,7 +37,7 @@ #include "net/test/gtest_util.h" #include "net/test/test_data_directory.h" #include "net/test/test_with_scoped_task_environment.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc index 6801300d..c47fc5e 100644 --- a/net/spdy/spdy_test_util_common.cc +++ b/net/spdy/spdy_test_util_common.cc
@@ -31,8 +31,8 @@ #include "net/spdy/spdy_http_utils.h" #include "net/spdy/spdy_stream.h" #include "net/test/gtest_util.h" -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/url_request_job_factory_impl.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h index 8db758d7..0f480ab42 100644 --- a/net/spdy/spdy_test_util_common.h +++ b/net/spdy/spdy_test_util_common.h
@@ -34,7 +34,7 @@ #include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session_pool.h" #include "net/ssl/ssl_config_service_defaults.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_storage.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/net/spdy/spdy_write_queue.h b/net/spdy/spdy_write_queue.h index a31cec8..7c05045 100644 --- a/net/spdy/spdy_write_queue.h +++ b/net/spdy/spdy_write_queue.h
@@ -12,7 +12,7 @@ #include "base/memory/weak_ptr.h" #include "net/base/net_export.h" #include "net/base/request_priority.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/traffic_annotation/network_traffic_annotation.h" namespace net {
diff --git a/net/test/android/javatests/AndroidManifest.xml b/net/test/android/javatests/AndroidManifest.xml index 341949bc..4f0a46e 100644 --- a/net/test/android/javatests/AndroidManifest.xml +++ b/net/test/android/javatests/AndroidManifest.xml
@@ -8,7 +8,7 @@ xmlns:tools="http://schemas.android.com/tools" package="org.chromium.net.test.support"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.INTERNET"/>
diff --git a/net/test/quic_simple_test_server.cc b/net/test/quic_simple_test_server.cc index 39e2cd5c..cd8995d 100644 --- a/net/test/quic_simple_test_server.cc +++ b/net/test/quic_simple_test_server.cc
@@ -22,7 +22,7 @@ #include "net/test/test_data_directory.h" #include "net/third_party/quic/core/quic_dispatcher.h" #include "net/third_party/quic/tools/quic_memory_cache_backend.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/tools/quic/quic_simple_server.h" namespace {
diff --git a/net/third_party/quic/core/congestion_control/bbr_sender.h b/net/third_party/quic/core/congestion_control/bbr_sender.h index 698228b3..37739ad 100644 --- a/net/third_party/quic/core/congestion_control/bbr_sender.h +++ b/net/third_party/quic/core/congestion_control/bbr_sender.h
@@ -263,7 +263,7 @@ QuicPacketNumber last_sent_packet_; // Acknowledgement of any packet after |current_round_trip_end_| will cause // the round trip counter to advance. - QuicPacketCount current_round_trip_end_; + QuicPacketNumber current_round_trip_end_; // The filter that tracks the maximum bandwidth over the multiple recent // round-trips.
diff --git a/net/third_party/quic/core/congestion_control/general_loss_algorithm_test.cc b/net/third_party/quic/core/congestion_control/general_loss_algorithm_test.cc index 82b514d4..daaba8d7 100644 --- a/net/third_party/quic/core/congestion_control/general_loss_algorithm_test.cc +++ b/net/third_party/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -31,7 +31,7 @@ ~GeneralLossAlgorithmTest() override {} - void SendDataPacket(QuicPacketNumber packet_number) { + void SendDataPacket(uint64_t packet_number) { QuicStreamFrame frame; frame.stream_id = QuicUtils::GetHeadersStreamId( CurrentSupportedVersions()[0].transport_version); @@ -49,9 +49,9 @@ false); } - void VerifyLosses(QuicPacketNumber largest_newly_acked, + void VerifyLosses(uint64_t largest_newly_acked, const AckedPacketVector& packets_acked, - const std::vector<QuicPacketNumber>& losses_expected) { + const std::vector<uint64_t>& losses_expected) { if (largest_newly_acked > unacked_packets_.largest_acked()) { unacked_packets_.IncreaseLargestAcked(largest_newly_acked); }
diff --git a/net/third_party/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc b/net/third_party/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc index 5999936..d35b6a9 100644 --- a/net/third_party/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc +++ b/net/third_party/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
@@ -110,7 +110,7 @@ } // Does not increment acked_packet_number_. - void LosePacket(QuicPacketNumber packet_number) { + void LosePacket(uint64_t packet_number) { AckedPacketVector acked_packets; LostPacketVector lost_packets; lost_packets.push_back(LostPacket(packet_number, kDefaultTCPMSS)); @@ -123,7 +123,7 @@ MockClock clock_; std::unique_ptr<TcpCubicSenderBytesPeer> sender_; QuicPacketNumber packet_number_; - QuicPacketNumber acked_packet_number_; + uint64_t acked_packet_number_; QuicByteCount bytes_in_flight_; };
diff --git a/net/third_party/quic/core/crypto/aead_base_decrypter.cc b/net/third_party/quic/core/crypto/aead_base_decrypter.cc index 933f00f..4d6b51e 100644 --- a/net/third_party/quic/core/crypto/aead_base_decrypter.cc +++ b/net/third_party/quic/core/crypto/aead_base_decrypter.cc
@@ -142,7 +142,7 @@ } bool AeadBaseDecrypter::DecryptPacket(QuicTransportVersion /*version*/, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output,
diff --git a/net/third_party/quic/core/crypto/aead_base_decrypter.h b/net/third_party/quic/core/crypto/aead_base_decrypter.h index 385dcdc..47cef9fa 100644 --- a/net/third_party/quic/core/crypto/aead_base_decrypter.h +++ b/net/third_party/quic/core/crypto/aead_base_decrypter.h
@@ -36,7 +36,7 @@ bool SetPreliminaryKey(QuicStringPiece key) override; bool SetDiversificationNonce(const DiversificationNonce& nonce) override; bool DecryptPacket(QuicTransportVersion version, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output,
diff --git a/net/third_party/quic/core/crypto/aead_base_encrypter.cc b/net/third_party/quic/core/crypto/aead_base_encrypter.cc index b061a77..2e61b20a 100644 --- a/net/third_party/quic/core/crypto/aead_base_encrypter.cc +++ b/net/third_party/quic/core/crypto/aead_base_encrypter.cc
@@ -124,7 +124,7 @@ } bool AeadBaseEncrypter::EncryptPacket(QuicTransportVersion /*version*/, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output,
diff --git a/net/third_party/quic/core/crypto/aead_base_encrypter.h b/net/third_party/quic/core/crypto/aead_base_encrypter.h index bac629f..5802055 100644 --- a/net/third_party/quic/core/crypto/aead_base_encrypter.h +++ b/net/third_party/quic/core/crypto/aead_base_encrypter.h
@@ -34,7 +34,7 @@ bool SetNoncePrefix(QuicStringPiece nonce_prefix) override; bool SetIV(QuicStringPiece iv) override; bool EncryptPacket(QuicTransportVersion version, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output,
diff --git a/net/third_party/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc b/net/third_party/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc index e529705..5ccf0dda 100644 --- a/net/third_party/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc +++ b/net/third_party/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -203,7 +203,7 @@ QuicStringPiece nonce, QuicStringPiece associated_data, QuicStringPiece ciphertext) { - QuicPacketNumber packet_number; + uint64_t packet_number; QuicStringPiece nonce_prefix(nonce.data(), nonce.size() - sizeof(packet_number)); decrypter->SetNoncePrefix(nonce_prefix);
diff --git a/net/third_party/quic/core/crypto/aes_128_gcm_encrypter_test.cc b/net/third_party/quic/core/crypto/aes_128_gcm_encrypter_test.cc index d72e51c9..5ec3738d 100644 --- a/net/third_party/quic/core/crypto/aes_128_gcm_encrypter_test.cc +++ b/net/third_party/quic/core/crypto/aes_128_gcm_encrypter_test.cc
@@ -220,7 +220,7 @@ TEST_F(Aes128GcmEncrypterTest, EncryptPacket) { QuicString key = QuicTextUtils::HexDecode("d95a145250826c25a77b6a84fd4d34fc"); QuicString iv = QuicTextUtils::HexDecode("50c4431ebb18283448e276e2"); - QuicPacketNumber packet_num = 0x13278f44; + uint64_t packet_num = 0x13278f44; QuicString aad = QuicTextUtils::HexDecode("875d49f64a70c9cbe713278f44ff000005"); QuicString pt = QuicTextUtils::HexDecode("aa0003a250bd000000000001");
diff --git a/net/third_party/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/net/third_party/quic/core/crypto/chacha20_poly1305_decrypter_test.cc index e8d30399..19c8a3c4 100644 --- a/net/third_party/quic/core/crypto/chacha20_poly1305_decrypter_test.cc +++ b/net/third_party/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
@@ -116,7 +116,7 @@ QuicStringPiece nonce, QuicStringPiece associated_data, QuicStringPiece ciphertext) { - QuicPacketNumber packet_number; + uint64_t packet_number; QuicStringPiece nonce_prefix(nonce.data(), nonce.size() - sizeof(packet_number)); decrypter->SetNoncePrefix(nonce_prefix);
diff --git a/net/third_party/quic/core/crypto/chacha20_poly1305_encrypter_test.cc b/net/third_party/quic/core/crypto/chacha20_poly1305_encrypter_test.cc index 8546813..0a8f9d2 100644 --- a/net/third_party/quic/core/crypto/chacha20_poly1305_encrypter_test.cc +++ b/net/third_party/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
@@ -96,7 +96,7 @@ ASSERT_TRUE(encrypter.SetNoncePrefix("abcd")); ASSERT_TRUE(decrypter.SetNoncePrefix("abcd")); - QuicPacketNumber packet_number = UINT64_C(0x123456789ABC); + uint64_t packet_number = UINT64_C(0x123456789ABC); QuicString associated_data = "associated_data"; QuicString plaintext = "plaintext"; char encrypted[1024];
diff --git a/net/third_party/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc b/net/third_party/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc index 3960f3d..5c7fe14 100644 --- a/net/third_party/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc +++ b/net/third_party/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
@@ -95,7 +95,7 @@ ASSERT_TRUE(encrypter.SetIV("abcdefghijkl")); ASSERT_TRUE(decrypter.SetIV("abcdefghijkl")); - QuicPacketNumber packet_number = UINT64_C(0x123456789ABC); + uint64_t packet_number = UINT64_C(0x123456789ABC); QuicString associated_data = "associated_data"; QuicString plaintext = "plaintext"; char encrypted[1024];
diff --git a/net/third_party/quic/core/crypto/crypto_server_test.cc b/net/third_party/quic/core/crypto/crypto_server_test.cc index 14a9fa5..270bf08 100644 --- a/net/third_party/quic/core/crypto/crypto_server_test.cc +++ b/net/third_party/quic/core/crypto/crypto_server_test.cc
@@ -723,6 +723,26 @@ CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } +TEST_P(CryptoServerTest, CorruptSourceAddressTokenIsStillAccepted) { + // This tests corrupted source address token. + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", (QuicString(1, 'X') + srct_hex_)}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + config_.set_validate_source_address_token(false); + + ShouldSucceed(msg); + EXPECT_EQ(kSHLO, out_.tag()); +} + TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) { // This test corrupts client nonce and source address token. CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO(
diff --git a/net/third_party/quic/core/crypto/null_decrypter.cc b/net/third_party/quic/core/crypto/null_decrypter.cc index c78f6814..337d40e5 100644 --- a/net/third_party/quic/core/crypto/null_decrypter.cc +++ b/net/third_party/quic/core/crypto/null_decrypter.cc
@@ -39,7 +39,7 @@ } bool NullDecrypter::DecryptPacket(QuicTransportVersion version, - QuicPacketNumber /*packet_number*/, + uint64_t /*packet_number*/, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output,
diff --git a/net/third_party/quic/core/crypto/null_decrypter.h b/net/third_party/quic/core/crypto/null_decrypter.h index 49d22fe..6fe3d2bb 100644 --- a/net/third_party/quic/core/crypto/null_decrypter.h +++ b/net/third_party/quic/core/crypto/null_decrypter.h
@@ -36,7 +36,7 @@ bool SetPreliminaryKey(QuicStringPiece key) override; bool SetDiversificationNonce(const DiversificationNonce& nonce) override; bool DecryptPacket(QuicTransportVersion version, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output,
diff --git a/net/third_party/quic/core/crypto/null_encrypter.cc b/net/third_party/quic/core/crypto/null_encrypter.cc index 68a7264e..d8e6407 100644 --- a/net/third_party/quic/core/crypto/null_encrypter.cc +++ b/net/third_party/quic/core/crypto/null_encrypter.cc
@@ -27,7 +27,7 @@ } bool NullEncrypter::EncryptPacket(QuicTransportVersion version, - QuicPacketNumber /*packet_number*/, + uint64_t /*packet_number*/, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output,
diff --git a/net/third_party/quic/core/crypto/null_encrypter.h b/net/third_party/quic/core/crypto/null_encrypter.h index b885b433..f41d187 100644 --- a/net/third_party/quic/core/crypto/null_encrypter.h +++ b/net/third_party/quic/core/crypto/null_encrypter.h
@@ -30,7 +30,7 @@ bool SetNoncePrefix(QuicStringPiece nonce_prefix) override; bool SetIV(QuicStringPiece iv) override; bool EncryptPacket(QuicTransportVersion version, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output,
diff --git a/net/third_party/quic/core/crypto/quic_crypto_client_config.cc b/net/third_party/quic/core/crypto/quic_crypto_client_config.cc index 612db289..fd4c37d 100644 --- a/net/third_party/quic/core/crypto/quic_crypto_client_config.cc +++ b/net/third_party/quic/core/crypto/quic_crypto_client_config.cc
@@ -13,6 +13,7 @@ #include "net/third_party/quic/core/crypto/channel_id.h" #include "net/third_party/quic/core/crypto/common_cert_set.h" #include "net/third_party/quic/core/crypto/crypto_framer.h" +#include "net/third_party/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quic/core/crypto/crypto_utils.h" #include "net/third_party/quic/core/crypto/curve25519_key_exchange.h" #include "net/third_party/quic/core/crypto/key_exchange.h" @@ -442,7 +443,11 @@ CryptoHandshakeMessage* out) const { out->set_tag(kCHLO); // TODO(rch): Remove this when we remove quic_use_chlo_packet_size flag. - out->set_minimum_size(kClientHelloMinimumSize); + if (pad_inchoate_hello_) { + out->set_minimum_size(kClientHelloMinimumSize); + } else { + out->set_minimum_size(1); + } // Server name indication. We only send SNI if it's a valid domain name, as // per the spec. @@ -525,6 +530,12 @@ FillInchoateClientHello(server_id, preferred_version, cached, rand, /* demand_x509_proof= */ true, out_params, out); + if (pad_full_hello_) { + out->set_minimum_size(kClientHelloMinimumSize); + } else { + out->set_minimum_size(1); + } + const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); if (!scfg) { // This should never happen as our caller should have checked
diff --git a/net/third_party/quic/core/crypto/quic_crypto_client_config.h b/net/third_party/quic/core/crypto/quic_crypto_client_config.h index 82eb60e7..d3e8935 100644 --- a/net/third_party/quic/core/crypto/quic_crypto_client_config.h +++ b/net/third_party/quic/core/crypto/quic_crypto_client_config.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "net/third_party/quic/core/crypto/crypto_handshake.h" +#include "net/third_party/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/core/quic_server_id.h" #include "net/third_party/quic/platform/api/quic_export.h" @@ -351,6 +352,14 @@ pre_shared_key_ = QuicString(psk); } + bool pad_inchoate_hello() const { return pad_inchoate_hello_; } + void set_pad_inchoate_hello(bool new_value) { + pad_inchoate_hello_ = new_value; + } + + bool pad_full_hello() const { return pad_full_hello_; } + void set_pad_full_hello(bool new_value) { pad_full_hello_ = new_value; } + private: // Sets the members to reasonable, default values. void SetDefaults(); @@ -402,6 +411,20 @@ // If non-empty, the client will operate in the pre-shared key mode by // incorporating |pre_shared_key_| into the key schedule. QuicString pre_shared_key_; + + // In QUIC, technically, client hello should be fully padded. + // However, fully padding on slow network connection (e.g. 50kbps) can add + // 150ms latency to one roundtrip. Therefore, you can disable padding of + // individual messages. It is recommend to leave at least one message in + // each direction fully padded (e.g. full CHLO and SHLO), but if you know + // the lower-bound MTU, you don't need to pad all of them (keep in mind that + // it's not OK to do it according to the standard). + // + // Also, if you disable padding, you must disable (change) the + // anti-amplification protection. You should only do so if you have some + // other means of verifying the client. + bool pad_inchoate_hello_ = true; + bool pad_full_hello_ = true; }; } // namespace quic
diff --git a/net/third_party/quic/core/crypto/quic_crypto_client_config_test.cc b/net/third_party/quic/core/crypto/quic_crypto_client_config_test.cc index fb249af..38cbccf 100644 --- a/net/third_party/quic/core/crypto/quic_crypto_client_config_test.cc +++ b/net/third_party/quic/core/crypto/quic_crypto_client_config_test.cc
@@ -201,6 +201,26 @@ QuicStringPiece alpn; EXPECT_TRUE(msg.GetStringPiece(kALPN, &alpn)); EXPECT_EQ("hq", alpn); + + EXPECT_EQ(msg.minimum_size(), 1024u); +} + +TEST_F(QuicCryptoClientConfigTest, InchoateChloIsNotPadded) { + QuicCryptoClientConfig::CachedState state; + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + config.set_pad_inchoate_hello(false); + config.set_user_agent_id("quic-tester"); + config.set_alpn("hq"); + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( + new QuicCryptoNegotiatedParameters); + CryptoHandshakeMessage msg; + QuicServerId server_id("www.google.com", 443, false); + MockRandom rand; + config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand, + /* demand_x509_proof= */ true, params, &msg); + + EXPECT_EQ(msg.minimum_size(), 1u); } // Make sure AES-GCM is the preferred encryption algorithm if it has hardware @@ -311,6 +331,30 @@ EXPECT_EQ(CreateQuicVersionLabel(QuicVersionMax()), cver); } +TEST_F(QuicCryptoClientConfigTest, FillClientHelloNoPadding) { + QuicCryptoClientConfig::CachedState state; + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + config.set_pad_full_hello(false); + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( + new QuicCryptoNegotiatedParameters); + QuicConnectionId kConnectionId = TestConnectionId(1234); + QuicString error_details; + MockRandom rand; + CryptoHandshakeMessage chlo; + QuicServerId server_id("www.google.com", 443, false); + config.FillClientHello(server_id, kConnectionId, QuicVersionMax(), &state, + QuicWallTime::Zero(), &rand, + nullptr, // channel_id_key + params, &chlo, &error_details); + + // Verify that the version label has been set correctly in the CHLO. + QuicVersionLabel cver; + EXPECT_EQ(QUIC_NO_ERROR, chlo.GetVersionLabel(kVER, &cver)); + EXPECT_EQ(CreateQuicVersionLabel(QuicVersionMax()), cver); + EXPECT_EQ(chlo.minimum_size(), 1u); +} + TEST_F(QuicCryptoClientConfigTest, ProcessServerDowngradeAttack) { ParsedQuicVersionVector supported_versions = AllSupportedVersions(); if (supported_versions.size() == 1) {
diff --git a/net/third_party/quic/core/crypto/quic_crypto_server_config.cc b/net/third_party/quic/core/crypto/quic_crypto_server_config.cc index 7321db1..a54f320 100644 --- a/net/third_party/quic/core/crypto/quic_crypto_server_config.cc +++ b/net/third_party/quic/core/crypto/quic_crypto_server_config.cc
@@ -33,6 +33,7 @@ #include "net/third_party/quic/core/quic_types.h" #include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quic/platform/api/quic_cert_utils.h" #include "net/third_party/quic/platform/api/quic_clock.h" #include "net/third_party/quic/platform/api/quic_endian.h" #include "net/third_party/quic/platform/api/quic_fallthrough.h" @@ -220,7 +221,11 @@ source_address_token_future_secs_(3600), source_address_token_lifetime_secs_(86400), enable_serving_sct_(false), - rejection_observer_(nullptr) { + rejection_observer_(nullptr), + pad_rej_(true), + pad_shlo_(true), + validate_chlo_size_(true), + validate_source_address_token_(true) { DCHECK(proof_source_.get()); source_address_token_boxer_.SetKeys( {DeriveSourceAddressTokenKey(source_address_token_secret)}); @@ -965,25 +970,13 @@ // TODO(rch): Would it be better to implement a move operator and just // std::move(helper) instead of done_cb? helper.DetachCallback(); - if (GetQuicRestartFlag(quic_use_async_key_exchange)) { - QUIC_RESTART_FLAG_COUNT(quic_use_async_key_exchange); - auto cb = QuicMakeUnique<ProcessClientHelloAfterGetProofCallback>( - this, std::move(proof_source_details), key_exchange->GetFactory(), - std::move(out), public_value, validate_chlo_result, connection_id, - client_address, supported_versions, clock, rand, params, signed_config, - requested_config, primary_config, std::move(done_cb)); - key_exchange->CalculateSharedKey( - public_value, ¶ms->initial_premaster_secret, std::move(cb)); - } else { - found_error = !key_exchange->CalculateSharedKey( - public_value, ¶ms->initial_premaster_secret); - ProcessClientHelloAfterCalculateSharedKeys( - found_error, std::move(proof_source_details), - key_exchange->GetFactory(), std::move(out), public_value, - *validate_chlo_result, connection_id, client_address, - supported_versions, clock, rand, params, signed_config, - requested_config, primary_config, std::move(done_cb)); - } + auto cb = QuicMakeUnique<ProcessClientHelloAfterGetProofCallback>( + this, std::move(proof_source_details), key_exchange->GetFactory(), + std::move(out), public_value, validate_chlo_result, connection_id, + client_address, supported_versions, clock, rand, params, signed_config, + requested_config, primary_config, std::move(done_cb)); + key_exchange->CalculateSharedKey( + public_value, ¶ms->initial_premaster_secret, std::move(cb)); } void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys( @@ -1392,7 +1385,7 @@ const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello; ClientHelloInfo* info = &(client_hello_state->info); - if (client_hello.size() < kClientHelloMinimumSize) { + if (validate_chlo_size_ && client_hello.size() < kClientHelloMinimumSize) { helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH, "Client hello too small", nullptr); return; @@ -1408,22 +1401,27 @@ client_hello.GetStringPiece(kUAID, &info->user_agent_id); HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON; - QuicStringPiece srct; - if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) { - Config& config = - requested_config != nullptr ? *requested_config : *primary_config; - source_address_token_error = - ParseSourceAddressToken(config, srct, &info->source_address_tokens); + if (validate_source_address_token_) { + QuicStringPiece srct; + if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) { + Config& config = + requested_config != nullptr ? *requested_config : *primary_config; + source_address_token_error = + ParseSourceAddressToken(config, srct, &info->source_address_tokens); - if (source_address_token_error == HANDSHAKE_OK) { - source_address_token_error = ValidateSourceAddressTokens( - info->source_address_tokens, info->client_ip, info->now, - &client_hello_state->cached_network_params); + if (source_address_token_error == HANDSHAKE_OK) { + source_address_token_error = ValidateSourceAddressTokens( + info->source_address_tokens, info->client_ip, info->now, + &client_hello_state->cached_network_params); + } + info->valid_source_address_token = + (source_address_token_error == HANDSHAKE_OK); + } else { + source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE; } - info->valid_source_address_token = - (source_address_token_error == HANDSHAKE_OK); } else { - source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE; + source_address_token_error = HANDSHAKE_OK; + info->valid_source_address_token = true; } if (!requested_config.get()) { @@ -1719,8 +1717,22 @@ out->SetStringPiece(kPROF, signed_config.proof.signature); if (should_return_sct) { if (cert_sct.empty()) { - QUIC_LOG_EVERY_N_SEC(WARNING, 60) - << "SCT is expected but it is empty. sni :" << params->sni; + if (!GetQuicReloadableFlag(quic_log_cert_name_for_empty_sct)) { + QUIC_LOG_EVERY_N_SEC(WARNING, 60) + << "SCT is expected but it is empty. sni :" << params->sni; + } else { + // Log SNI and subject name for the leaf cert if its SCT is empty. + // This is for debugging b/28342827. + const std::vector<quic::QuicString>& certs = + signed_config.chain->certs; + QuicStringPiece ca_subject; + if (!certs.empty()) { + QuicCertUtils::ExtractSubjectNameFromDERCert(certs[0], &ca_subject); + } + QUIC_LOG_EVERY_N_SEC(WARNING, 60) + << "SCT is expected but it is empty. sni: '" << params->sni + << "' cert subject: '" << ca_subject << "'"; + } } else { out->SetStringPiece(kCertificateSCTTag, cert_sct); }
diff --git a/net/third_party/quic/core/crypto/quic_crypto_server_config.h b/net/third_party/quic/core/crypto/quic_crypto_server_config.h index 407a1d0..e8f1d4e 100644 --- a/net/third_party/quic/core/crypto/quic_crypto_server_config.h +++ b/net/third_party/quic/core/crypto/quic_crypto_server_config.h
@@ -388,6 +388,19 @@ // valid source-address token. void set_chlo_multiplier(size_t multiplier); + // When sender is allowed to not pad client hello (not standards compliant), + // we need to disable the client hello check. + void set_validate_chlo_size(bool new_value) { + validate_chlo_size_ = new_value; + } + + // When QUIC is tunneled through some other mechanism, source token validation + // may be disabled. Do not disable it if you are not providing other + // protection. (|true| protects against UDP amplification attack.). + void set_validate_source_address_token(bool new_value) { + validate_source_address_token_ = new_value; + } + // set_source_address_token_future_secs sets the number of seconds into the // future that source-address tokens will be accepted from. Since // source-address tokens are authenticated, this should only happen if @@ -423,6 +436,12 @@ pre_shared_key_ = QuicString(psk); } + bool pad_rej() const { return pad_rej_; } + void set_pad_rej(bool new_value) { pad_rej_ = new_value; } + + bool pad_shlo() const { return pad_shlo_; } + void set_pad_shlo(bool new_value) { pad_shlo_ = new_value; } + private: friend class test::QuicCryptoServerConfigPeer; friend struct QuicSignedServerConfig; @@ -822,6 +841,23 @@ // If non-empty, the server will operate in the pre-shared key mode by // incorporating |pre_shared_key_| into the key schedule. QuicString pre_shared_key_; + + // Whether REJ message should be padded to max packet size. + bool pad_rej_; + + // Whether SHLO message should be padded to max packet size. + bool pad_shlo_; + + // If client is allowed to send a small client hello (by disabling padding), + // server MUST not check for the client hello size. + // DO NOT disable this unless you have some other way of validating client. + // (e.g. in realtime scenarios, where quic is tunneled through ICE, ICE will + // do its own peer validation using STUN pings with ufrag/upass). + bool validate_chlo_size_; + + // When source address is validated by some other means (e.g. when using ICE), + // source address token validation may be disabled. + bool validate_source_address_token_; }; struct QUIC_EXPORT_PRIVATE QuicSignedServerConfig
diff --git a/net/third_party/quic/core/crypto/quic_decrypter.h b/net/third_party/quic/core/crypto/quic_decrypter.h index b2b3b5af..f08272f 100644 --- a/net/third_party/quic/core/crypto/quic_decrypter.h +++ b/net/third_party/quic/core/crypto/quic_decrypter.h
@@ -54,7 +54,7 @@ // TODO(wtc): add a way for DecryptPacket to report decryption failure due // to non-authentic inputs, as opposed to other reasons for failure. virtual bool DecryptPacket(QuicTransportVersion version, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output,
diff --git a/net/third_party/quic/core/crypto/quic_encrypter.h b/net/third_party/quic/core/crypto/quic_encrypter.h index 1521400..2ee0daf3 100644 --- a/net/third_party/quic/core/crypto/quic_encrypter.h +++ b/net/third_party/quic/core/crypto/quic_encrypter.h
@@ -35,7 +35,7 @@ // |associated_data|. If |output| overlaps with |plaintext| then // |plaintext| must be <= |output|. virtual bool EncryptPacket(QuicTransportVersion version, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output,
diff --git a/net/third_party/quic/core/frames/quic_ack_frame.cc b/net/third_party/quic/core/frames/quic_ack_frame.cc index 993a1a7..9cd370e 100644 --- a/net/third_party/quic/core/frames/quic_ack_frame.cc +++ b/net/third_party/quic/core/frames/quic_ack_frame.cc
@@ -12,12 +12,13 @@ namespace quic { namespace { -const QuicPacketNumber kMaxPrintRange = 128; +const QuicPacketCount kMaxPrintRange = 128; } // namespace bool IsAwaitingPacket(const QuicAckFrame& ack_frame, QuicPacketNumber packet_number, QuicPacketNumber peer_least_packet_awaiting_ack) { + DCHECK_NE(kInvalidPacketNumber, packet_number); return packet_number >= peer_least_packet_awaiting_ack && !ack_frame.packets.Contains(packet_number); } @@ -73,6 +74,9 @@ default; void PacketNumberQueue::Add(QuicPacketNumber packet_number) { + if (packet_number == kInvalidPacketNumber) { + return; + } // Check if the deque is empty if (packet_number_deque_.empty()) { packet_number_deque_.push_front( @@ -148,7 +152,8 @@ void PacketNumberQueue::AddRange(QuicPacketNumber lower, QuicPacketNumber higher) { - if (lower >= higher) { + if (lower == kInvalidPacketNumber || higher == kInvalidPacketNumber || + lower >= higher) { return; } if (packet_number_deque_.empty()) { @@ -187,7 +192,7 @@ } bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) { - if (Empty()) { + if (higher == kInvalidPacketNumber || Empty()) { return false; } const QuicPacketNumber old_min = Min(); @@ -221,7 +226,7 @@ } bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const { - if (packet_number_deque_.empty()) { + if (packet_number == kInvalidPacketNumber || packet_number_deque_.empty()) { return false; } if (packet_number_deque_.front().min() > packet_number || @@ -278,7 +283,7 @@ return packet_number_deque_.rend(); } -QuicPacketNumber PacketNumberQueue::LastIntervalLength() const { +QuicPacketCount PacketNumberQueue::LastIntervalLength() const { DCHECK(!Empty()); return packet_number_deque_.back().Length(); }
diff --git a/net/third_party/quic/core/frames/quic_ack_frame.h b/net/third_party/quic/core/frames/quic_ack_frame.h index 32d73d3..6685132 100644 --- a/net/third_party/quic/core/frames/quic_ack_frame.h +++ b/net/third_party/quic/core/frames/quic_ack_frame.h
@@ -73,7 +73,7 @@ size_t NumIntervals() const; // Returns the length of last interval. - QuicPacketNumber LastIntervalLength() const; + QuicPacketCount LastIntervalLength() const; // Returns iterators over the packet number intervals. const_iterator begin() const;
diff --git a/net/third_party/quic/core/frames/quic_frames_test.cc b/net/third_party/quic/core/frames/quic_frames_test.cc index 0ddf0bb..fc67e10 100644 --- a/net/third_party/quic/core/frames/quic_frames_test.cc +++ b/net/third_party/quic/core/frames/quic_frames_test.cc
@@ -477,7 +477,7 @@ TEST_F(PacketNumberQueueTest, Removal) { PacketNumberQueue queue; EXPECT_FALSE(queue.Contains(51)); - queue.AddRange(0, 100); + queue.AddRange(1, 100); EXPECT_TRUE(queue.RemoveUpTo(51)); EXPECT_FALSE(queue.RemoveUpTo(51)); @@ -494,7 +494,7 @@ EXPECT_EQ(99u, queue.Max()); PacketNumberQueue queue2; - queue2.AddRange(0, 5); + queue2.AddRange(1, 5); EXPECT_TRUE(queue2.RemoveUpTo(3)); EXPECT_TRUE(queue2.RemoveUpTo(50)); EXPECT_TRUE(queue2.Empty());
diff --git a/net/third_party/quic/core/http/http_decoder.cc b/net/third_party/quic/core/http/http_decoder.cc index 740f7cd..ef82244 100644 --- a/net/third_party/quic/core/http/http_decoder.cc +++ b/net/third_party/quic/core/http/http_decoder.cc
@@ -264,6 +264,24 @@ } return; } + + case 0xE: { // DUPLICATE_PUSH + BufferFramePayload(reader); + if (remaining_frame_length_ != 0) { + return; + } + QuicDataReader reader(buffer_.data(), current_frame_length_, + NETWORK_BYTE_ORDER); + DuplicatePushFrame frame; + if (!reader.ReadVarInt62(&frame.push_id)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id"); + return; + } + visitor_->OnDuplicatePushFrame(frame); + state_ = STATE_READING_FRAME_LENGTH; + current_length_field_size_ = 0; + return; + } // Reserved frame types. // TODO(rch): Since these are actually the same behavior as the // default, we probably don't need to special case them here?
diff --git a/net/third_party/quic/core/http/http_decoder.h b/net/third_party/quic/core/http/http_decoder.h index 04f130df..e2c3f0d2 100644 --- a/net/third_party/quic/core/http/http_decoder.h +++ b/net/third_party/quic/core/http/http_decoder.h
@@ -58,7 +58,10 @@ // Called when a SETTINGS frame has been successfully parsed. virtual void OnSettingsFrame(const SettingsFrame& frame) = 0; - // Called when a DATA frame has been recevied, |frame_lengths| will be + // Called when a DUPLICATE_PUSH frame has been successfully parsed. + virtual void OnDuplicatePushFrame(const DuplicatePushFrame& frame) = 0; + + // Called when a DATA frame has been received, |frame_lengths| will be // passed to inform header length and payload length of the frame. virtual void OnDataFrameStart(Http3FrameLengths frame_length) = 0; // Called when the payload of a DATA frame has read. May be called
diff --git a/net/third_party/quic/core/http/http_decoder_test.cc b/net/third_party/quic/core/http/http_decoder_test.cc index aa847a7c..05c4a34 100644 --- a/net/third_party/quic/core/http/http_decoder_test.cc +++ b/net/third_party/quic/core/http/http_decoder_test.cc
@@ -23,6 +23,7 @@ MOCK_METHOD1(OnMaxPushIdFrame, void(const MaxPushIdFrame& frame)); MOCK_METHOD1(OnGoAwayFrame, void(const GoAwayFrame& frame)); MOCK_METHOD1(OnSettingsFrame, void(const SettingsFrame& frame)); + MOCK_METHOD1(OnDuplicatePushFrame, void(const DuplicatePushFrame& frame)); MOCK_METHOD1(OnDataFrameStart, void(Http3FrameLengths frame_lengths)); MOCK_METHOD1(OnDataFramePayload, void(QuicStringPiece payload)); @@ -182,6 +183,29 @@ EXPECT_EQ("", decoder_.error_detail()); } +TEST_F(HttpDecoderTest, DuplicatePush) { + char input[] = {// length + 0x1, + // type (DUPLICATE_PUSH) + 0x0E, + // Push Id + 0x01}; + // Process the full frame. + EXPECT_CALL(visitor_, OnDuplicatePushFrame(DuplicatePushFrame({1}))); + EXPECT_EQ(QUIC_ARRAYSIZE(input), + decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + + // Process the frame incremently. + EXPECT_CALL(visitor_, OnDuplicatePushFrame(DuplicatePushFrame({1}))); + for (char c : input) { + EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); + } + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); +} + TEST_F(HttpDecoderTest, PriorityFrame) { char input[] = {// length 0x4,
diff --git a/net/third_party/quic/core/http/http_encoder.cc b/net/third_party/quic/core/http/http_encoder.cc index f8c4211..a16a3fa 100644 --- a/net/third_party/quic/core/http/http_encoder.cc +++ b/net/third_party/quic/core/http/http_encoder.cc
@@ -225,6 +225,24 @@ return 0; } +QuicByteCount HttpEncoder::SerializeDuplicatePushFrame( + const DuplicatePushFrame& duplicate_push, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + QuicDataWriter::GetVarInt62Len(duplicate_push.push_id); + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + + if (WriteFrameHeader(payload_length, HttpFrameType::DUPLICATE_PUSH, + &writer) && + writer.WriteVarInt62(duplicate_push.push_id)) { + return total_length; + } + return 0; +} + bool HttpEncoder::WriteFrameHeader(QuicByteCount length, HttpFrameType type, QuicDataWriter* writer) {
diff --git a/net/third_party/quic/core/http/http_encoder.h b/net/third_party/quic/core/http/http_encoder.h index a92316c9..d075151 100644 --- a/net/third_party/quic/core/http/http_encoder.h +++ b/net/third_party/quic/core/http/http_encoder.h
@@ -66,6 +66,12 @@ QuicByteCount SerializeMaxPushIdFrame(const MaxPushIdFrame& max_push_id, std::unique_ptr<char[]>* output); + // Serialize a DUPLICATE_PUSH frame into a new buffer stored in |output|. + // Returns the length of the buffer on success, or 0 otherwise. + QuicByteCount SerializeDuplicatePushFrame( + const DuplicatePushFrame& duplicate_push, + std::unique_ptr<char[]>* output); + private: bool WriteFrameHeader(QuicByteCount length, HttpFrameType type,
diff --git a/net/third_party/quic/core/http/http_encoder_test.cc b/net/third_party/quic/core/http/http_encoder_test.cc index a3b2cc0..0e83970 100644 --- a/net/third_party/quic/core/http/http_encoder_test.cc +++ b/net/third_party/quic/core/http/http_encoder_test.cc
@@ -169,5 +169,22 @@ QUIC_ARRAYSIZE(output)); } +TEST_F(HttpEncoderTest, SerializeDuplicatePushFrame) { + DuplicatePushFrame duplicate_push; + duplicate_push.push_id = 0x1; + char output[] = {// length + 0x1, + // type (DUPLICATE_PUSH) + 0x0E, + // Push Id + 0x01}; + std::unique_ptr<char[]> buffer; + uint64_t length = + encoder_.SerializeDuplicatePushFrame(duplicate_push, &buffer); + EXPECT_EQ(QUIC_ARRAYSIZE(output), length); + CompareCharArraysWithHexError("DUPLICATE_PUSH", buffer.get(), length, output, + QUIC_ARRAYSIZE(output)); +} + } // namespace test } // namespace quic
diff --git a/net/third_party/quic/core/http/http_frames.h b/net/third_party/quic/core/http/http_frames.h index f33a1432..5088ba8 100644 --- a/net/third_party/quic/core/http/http_frames.h +++ b/net/third_party/quic/core/http/http_frames.h
@@ -9,7 +9,7 @@ #include "net/third_party/quic/core/quic_types.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" namespace quic { @@ -21,10 +21,11 @@ SETTINGS = 0x4, PUSH_PROMISE = 0x5, GOAWAY = 0x7, - MAX_PUSH_ID = 0xD + MAX_PUSH_ID = 0xD, + DUPLICATE_PUSH = 0xE }; -// 4.2.2. DATA +// 4.2.1. DATA // // DATA frames (type=0x0) convey arbitrary, variable-length sequences of // octets associated with an HTTP request or response payload. @@ -32,7 +33,7 @@ QuicStringPiece data; }; -// 4.2.3. HEADERS +// 4.2.2. HEADERS // // The HEADERS frame (type=0x1) is used to carry a header block, // compressed using QPACK. @@ -40,7 +41,7 @@ QuicStringPiece headers; }; -// 4.2.4. PRIORITY +// 4.2.3. PRIORITY // // The PRIORITY (type=0x02) frame specifies the sender-advised priority // of a stream @@ -69,7 +70,7 @@ } }; -// 4.2.5. CANCEL_PUSH +// 4.2.4. CANCEL_PUSH // // The CANCEL_PUSH frame (type=0x3) is used to request cancellation of // server push prior to the push stream being created. @@ -83,7 +84,7 @@ } }; -// 4.2.6. SETTINGS +// 4.2.5. SETTINGS // // The SETTINGS frame (type=0x4) conveys configuration parameters that // affect how endpoints communicate, such as preferences and constraints @@ -100,7 +101,7 @@ } }; -// 4.2.7. PUSH_PROMISE +// 4.2.6. PUSH_PROMISE // // The PUSH_PROMISE frame (type=0x05) is used to carry a request header // set from server to client, as in HTTP/2. @@ -113,7 +114,7 @@ } }; -// 4.2.8. GOAWAY +// 4.2.7. GOAWAY // // The GOAWAY frame (type=0x7) is used to initiate graceful shutdown of // a connection by a server. @@ -125,7 +126,7 @@ } }; -// 4.2.9. MAX_PUSH_ID +// 4.2.8. MAX_PUSH_ID // // The MAX_PUSH_ID frame (type=0xD) is used by clients to control the // number of server pushes that the server can initiate. @@ -137,6 +138,19 @@ } }; +// 4.2.9. DUPLICATE_PUSH +// +// The DUPLICATE_PUSH frame (type=0xE) is used by servers to indicate +// that an existing pushed resource is related to multiple client +// requests. +struct DuplicatePushFrame { + PushId push_id; + + bool operator==(const DuplicatePushFrame& rhs) const { + return push_id == rhs.push_id; + } +}; + } // namespace quic #endif // NET_THIRD_PARTY_QUIC_CORE_HTTP_HTTP_FRAMES_H_
diff --git a/net/third_party/quic/core/http/quic_client_promised_info.cc b/net/third_party/quic/core/http/quic_client_promised_info.cc index b9ecc72..7a42950 100644 --- a/net/third_party/quic/core/http/quic_client_promised_info.cc +++ b/net/third_party/quic/core/http/quic_client_promised_info.cc
@@ -10,7 +10,7 @@ #include "net/third_party/quic/platform/api/quic_logging.h" #include "net/third_party/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quic/platform/api/quic_string.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" using spdy::SpdyHeaderBlock;
diff --git a/net/third_party/quic/core/http/quic_client_promised_info.h b/net/third_party/quic/core/http/quic_client_promised_info.h index c56eb6e..6da81de1 100644 --- a/net/third_party/quic/core/http/quic_client_promised_info.h +++ b/net/third_party/quic/core/http/quic_client_promised_info.h
@@ -14,7 +14,7 @@ #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/platform/api/quic_export.h" #include "net/third_party/quic/platform/api/quic_string.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" namespace quic {
diff --git a/net/third_party/quic/core/http/quic_header_list.cc b/net/third_party/quic/core/http/quic_header_list.cc index e0589680..7d995d2 100644 --- a/net/third_party/quic/core/http/quic_header_list.cc +++ b/net/third_party/quic/core/http/quic_header_list.cc
@@ -7,7 +7,7 @@ #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/platform/api/quic_flags.h" #include "net/third_party/quic/platform/api/quic_string.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace quic {
diff --git a/net/third_party/quic/core/http/quic_header_list.h b/net/third_party/quic/core/http/quic_header_list.h index 016b484..5cd11ff 100644 --- a/net/third_party/quic/core/http/quic_header_list.h +++ b/net/third_party/quic/core/http/quic_header_list.h
@@ -14,8 +14,8 @@ #include "net/third_party/quic/platform/api/quic_export.h" #include "net/third_party/quic/platform/api/quic_string.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_headers_handler_interface.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_headers_handler_interface.h" namespace quic {
diff --git a/net/third_party/quic/core/http/quic_headers_stream.h b/net/third_party/quic/core/http/quic_headers_stream.h index 3221522..518d1e86 100644 --- a/net/third_party/quic/core/http/quic_headers_stream.h +++ b/net/third_party/quic/core/http/quic_headers_stream.h
@@ -14,7 +14,7 @@ #include "net/third_party/quic/core/quic_stream.h" #include "net/third_party/quic/platform/api/quic_containers.h" #include "net/third_party/quic/platform/api/quic_export.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" namespace quic {
diff --git a/net/third_party/quic/core/http/quic_headers_stream_test.cc b/net/third_party/quic/core/http/quic_headers_stream_test.cc index cce16ae5..a09c9ec1 100644 --- a/net/third_party/quic/core/http/quic_headers_stream_test.cc +++ b/net/third_party/quic/core/http/quic_headers_stream_test.cc
@@ -26,10 +26,10 @@ #include "net/third_party/quic/test_tools/quic_spdy_session_peer.h" #include "net/third_party/quic/test_tools/quic_stream_peer.h" #include "net/third_party/quic/test_tools/quic_test_utils.h" -#include "net/third_party/spdy/core/http2_frame_decoder_adapter.h" -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" +#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h" +#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" using spdy::ERROR_CODE_PROTOCOL_ERROR; using spdy::SETTINGS_ENABLE_PUSH;
diff --git a/net/third_party/quic/core/http/quic_server_session_base.h b/net/third_party/quic/core/http/quic_server_session_base.h index 3ac0ada6..3f59728 100644 --- a/net/third_party/quic/core/http/quic_server_session_base.h +++ b/net/third_party/quic/core/http/quic_server_session_base.h
@@ -126,7 +126,7 @@ QuicTime last_scup_time_; // Number of packets sent to the peer, at the time we last sent a SCUP. - int64_t last_scup_packet_number_; + QuicPacketNumber last_scup_packet_number_; // Converts QuicBandwidth to an int32 bytes/second that can be // stored in CachedNetworkParameters. TODO(jokulik): This function
diff --git a/net/third_party/quic/core/http/quic_spdy_client_stream.cc b/net/third_party/quic/core/http/quic_spdy_client_stream.cc index 61c884d4..3213dfc 100644 --- a/net/third_party/quic/core/http/quic_spdy_client_stream.cc +++ b/net/third_party/quic/core/http/quic_spdy_client_stream.cc
@@ -11,7 +11,7 @@ #include "net/third_party/quic/core/http/spdy_utils.h" #include "net/third_party/quic/core/quic_alarm.h" #include "net/third_party/quic/platform/api/quic_logging.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" using spdy::SpdyHeaderBlock;
diff --git a/net/third_party/quic/core/http/quic_spdy_client_stream.h b/net/third_party/quic/core/http/quic_spdy_client_stream.h index ad84c219..0431b0c 100644 --- a/net/third_party/quic/core/http/quic_spdy_client_stream.h +++ b/net/third_party/quic/core/http/quic_spdy_client_stream.h
@@ -12,7 +12,7 @@ #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/platform/api/quic_string.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" namespace quic {
diff --git a/net/third_party/quic/core/http/quic_spdy_session.cc b/net/third_party/quic/core/http/quic_spdy_session.cc index b3e494c..119138d 100644 --- a/net/third_party/quic/core/http/quic_spdy_session.cc +++ b/net/third_party/quic/core/http/quic_spdy_session.cc
@@ -19,7 +19,7 @@ #include "net/third_party/quic/platform/api/quic_str_cat.h" #include "net/third_party/quic/platform/api/quic_string.h" #include "net/third_party/quic/platform/api/quic_text_utils.h" -#include "net/third_party/spdy/core/http2_frame_decoder_adapter.h" +#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h" using http2::Http2DecoderAdapter; using spdy::HpackEntry;
diff --git a/net/third_party/quic/core/http/quic_spdy_session.h b/net/third_party/quic/core/http/quic_spdy_session.h index cf24dbca..88c2e9bf 100644 --- a/net/third_party/quic/core/http/quic_spdy_session.h +++ b/net/third_party/quic/core/http/quic_spdy_session.h
@@ -16,7 +16,7 @@ #include "net/third_party/quic/platform/api/quic_export.h" #include "net/third_party/quic/platform/api/quic_string.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" -#include "net/third_party/spdy/core/http2_frame_decoder_adapter.h" +#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h" namespace quic {
diff --git a/net/third_party/quic/core/http/quic_spdy_session_test.cc b/net/third_party/quic/core/http/quic_spdy_session_test.cc index a5d2716..b8c2b47 100644 --- a/net/third_party/quic/core/http/quic_spdy_session_test.cc +++ b/net/third_party/quic/core/http/quic_spdy_session_test.cc
@@ -31,7 +31,7 @@ #include "net/third_party/quic/test_tools/quic_stream_peer.h" #include "net/third_party/quic/test_tools/quic_stream_send_buffer_peer.h" #include "net/third_party/quic/test_tools/quic_test_utils.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" using spdy::kV3HighestPriority; using spdy::Spdy3PriorityToHttp2Weight;
diff --git a/net/third_party/quic/core/http/quic_spdy_stream.cc b/net/third_party/quic/core/http/quic_spdy_stream.cc index d8f6a78..0599927 100644 --- a/net/third_party/quic/core/http/quic_spdy_stream.cc +++ b/net/third_party/quic/core/http/quic_spdy_stream.cc
@@ -18,7 +18,7 @@ #include "net/third_party/quic/platform/api/quic_string.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" #include "net/third_party/quic/platform/api/quic_text_utils.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" using spdy::SpdyHeaderBlock; using spdy::SpdyPriority; @@ -59,6 +59,10 @@ CloseConnectionOnWrongFrame("Settings"); } + void OnDuplicatePushFrame(const DuplicatePushFrame& frame) override { + CloseConnectionOnWrongFrame("Duplicate Push"); + } + void OnDataFrameStart(Http3FrameLengths frame_lengths) override { stream_->OnDataFrameStart(frame_lengths); }
diff --git a/net/third_party/quic/core/http/quic_spdy_stream.h b/net/third_party/quic/core/http/quic_spdy_stream.h index 8b2f3f54..e727bb7 100644 --- a/net/third_party/quic/core/http/quic_spdy_stream.h +++ b/net/third_party/quic/core/http/quic_spdy_stream.h
@@ -26,7 +26,7 @@ #include "net/third_party/quic/platform/api/quic_flags.h" #include "net/third_party/quic/platform/api/quic_socket_address.h" #include "net/third_party/quic/platform/api/quic_string.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" namespace quic {
diff --git a/net/third_party/quic/core/http/spdy_utils.cc b/net/third_party/quic/core/http/spdy_utils.cc index 0477824..f18b87d 100644 --- a/net/third_party/quic/core/http/spdy_utils.cc +++ b/net/third_party/quic/core/http/spdy_utils.cc
@@ -14,9 +14,9 @@ #include "net/third_party/quic/platform/api/quic_string.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" #include "net/third_party/quic/platform/api/quic_text_utils.h" -#include "net/third_party/spdy/core/spdy_frame_builder.h" -#include "net/third_party/spdy/core/spdy_framer.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "url/gurl.h" using spdy::SpdyHeaderBlock;
diff --git a/net/third_party/quic/core/http/spdy_utils.h b/net/third_party/quic/core/http/spdy_utils.h index 1a5881a5..c489d04c 100644 --- a/net/third_party/quic/core/http/spdy_utils.h +++ b/net/third_party/quic/core/http/spdy_utils.h
@@ -13,7 +13,7 @@ #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/platform/api/quic_export.h" #include "net/third_party/quic/platform/api/quic_string.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" namespace quic {
diff --git a/net/third_party/quic/core/http/spdy_utils_test.cc b/net/third_party/quic/core/http/spdy_utils_test.cc index b6bf144..f4d32614 100644 --- a/net/third_party/quic/core/http/spdy_utils_test.cc +++ b/net/third_party/quic/core/http/spdy_utils_test.cc
@@ -327,6 +327,24 @@ EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); } +TEST_F(GetPromisedUrlFromHeaders, InvalidUserinfo) { + SpdyHeaderBlock headers; + headers[":method"] = "GET"; + headers[":authority"] = "user@www.google.com"; + headers[":scheme"] = "https"; + headers[":path"] = "/"; + EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); +} + +TEST_F(GetPromisedUrlFromHeaders, InvalidPath) { + SpdyHeaderBlock headers; + headers[":method"] = "GET"; + headers[":authority"] = "www.google.com"; + headers[":scheme"] = "https"; + headers[":path"] = ""; + EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); +} + using GetPromisedHostNameFromHeaders = QuicTest; TEST_F(GetPromisedHostNameFromHeaders, NormalUsage) {
diff --git a/net/third_party/quic/core/packet_number_indexed_queue.h b/net/third_party/quic/core/packet_number_indexed_queue.h index 006280bf..7b2b354c 100644 --- a/net/third_party/quic/core/packet_number_indexed_queue.h +++ b/net/third_party/quic/core/packet_number_indexed_queue.h
@@ -6,7 +6,9 @@ #define NET_THIRD_PARTY_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_ #include "base/logging.h" +#include "net/third_party/quic/core/quic_constants.h" #include "net/third_party/quic/core/quic_types.h" +#include "net/third_party/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quic/platform/api/quic_containers.h" namespace quic { @@ -36,7 +38,7 @@ class PacketNumberIndexedQueue { public: PacketNumberIndexedQueue() - : number_of_present_entries_(0), first_packet_(0) {} + : number_of_present_entries_(0), first_packet_(kInvalidPacketNumber) {} // Retrieve the entry associated with the packet number. Returns the pointer // to the entry in case of success, or nullptr if the entry does not exist. @@ -65,15 +67,15 @@ // proportional to the memory usage of the queue. size_t entry_slots_used() const { return entries_.size(); } - // Packet number of the first entry in the queue. Zero if the queue is empty. - size_t first_packet() const { return first_packet_; } + // Packet number of the first entry in the queue. + QuicPacketNumber first_packet() const { return first_packet_; } // Packet number of the last entry ever inserted in the queue. Note that the // entry in question may have already been removed. Zero if the queue is // empty. - size_t last_packet() const { + QuicPacketNumber last_packet() const { if (IsEmpty()) { - return 0; + return kInvalidPacketNumber; } return first_packet_ + entries_.size() - 1; } @@ -127,9 +129,14 @@ template <typename... Args> bool PacketNumberIndexedQueue<T>::Emplace(QuicPacketNumber packet_number, Args&&... args) { + if (packet_number == kInvalidPacketNumber) { + QUIC_BUG << "Try to insert an uninitialized packet number"; + return false; + } + if (IsEmpty()) { DCHECK(entries_.empty()); - DCHECK_EQ(0u, first_packet_); + DCHECK_EQ(kInvalidPacketNumber, first_packet_); entries_.emplace_back(std::forward<Args>(args)...); number_of_present_entries_ = 1; @@ -176,18 +183,19 @@ first_packet_++; } if (entries_.empty()) { - first_packet_ = 0; + first_packet_ = kInvalidPacketNumber; } } template <typename T> -auto PacketNumberIndexedQueue<T>::GetEntryWrapper(QuicPacketNumber offset) const - -> const EntryWrapper* { - if (offset < first_packet_) { +auto PacketNumberIndexedQueue<T>::GetEntryWrapper( + QuicPacketNumber packet_number) const -> const EntryWrapper* { + if (packet_number == kInvalidPacketNumber || IsEmpty() || + packet_number < first_packet_) { return nullptr; } - offset -= first_packet_; + uint64_t offset = packet_number - first_packet_; if (offset >= entries_.size()) { return nullptr; }
diff --git a/net/third_party/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc b/net/third_party/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc index 47d72ee..6ed0fcf 100644 --- a/net/third_party/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc +++ b/net/third_party/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc
@@ -9,7 +9,7 @@ #include "net/third_party/quic/core/qpack/qpack_encoder_test_utils.h" #include "net/third_party/quic/platform/api/quic_fuzzed_data_provider.h" #include "net/third_party/quic/platform/api/quic_string.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" namespace quic { namespace test {
diff --git a/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.h b/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.h index 8866549..05a51ec 100644 --- a/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.h +++ b/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.h
@@ -8,7 +8,7 @@ #include "net/third_party/quic/core/qpack/qpack_decoder.h" #include "net/third_party/quic/core/qpack/qpack_decoder_test_utils.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" namespace quic {
diff --git a/net/third_party/quic/core/qpack/qpack_decoder_test.cc b/net/third_party/quic/core/qpack/qpack_decoder_test.cc index e6bb78e..6476aca1 100644 --- a/net/third_party/quic/core/qpack/qpack_decoder_test.cc +++ b/net/third_party/quic/core/qpack/qpack_decoder_test.cc
@@ -9,7 +9,7 @@ #include "net/third_party/quic/core/qpack/qpack_test_utils.h" #include "net/third_party/quic/platform/api/quic_test.h" #include "net/third_party/quic/platform/api/quic_text_utils.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" using ::testing::Eq; using ::testing::Sequence;
diff --git a/net/third_party/quic/core/qpack/qpack_decoder_test_utils.h b/net/third_party/quic/core/qpack/qpack_decoder_test_utils.h index 6d2202bc..427fee1 100644 --- a/net/third_party/quic/core/qpack/qpack_decoder_test_utils.h +++ b/net/third_party/quic/core/qpack/qpack_decoder_test_utils.h
@@ -9,7 +9,7 @@ #include "net/third_party/quic/core/qpack/qpack_progressive_decoder.h" #include "net/third_party/quic/core/qpack/qpack_test_utils.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "testing/gmock/include/gmock/gmock.h" namespace quic {
diff --git a/net/third_party/quic/core/qpack/qpack_encoder.h b/net/third_party/quic/core/qpack/qpack_encoder.h index b50a90c..39132e45 100644 --- a/net/third_party/quic/core/qpack/qpack_encoder.h +++ b/net/third_party/quic/core/qpack/qpack_encoder.h
@@ -13,7 +13,7 @@ #include "net/third_party/quic/core/qpack/qpack_header_table.h" #include "net/third_party/quic/core/quic_types.h" #include "net/third_party/quic/platform/api/quic_export.h" -#include "net/third_party/spdy/core/hpack/hpack_encoder.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h" namespace spdy {
diff --git a/net/third_party/quic/core/qpack/qpack_encoder_test_utils.cc b/net/third_party/quic/core/qpack/qpack_encoder_test_utils.cc index 9435070..e95adbf 100644 --- a/net/third_party/quic/core/qpack/qpack_encoder_test_utils.cc +++ b/net/third_party/quic/core/qpack/qpack_encoder_test_utils.cc
@@ -4,7 +4,7 @@ #include "net/third_party/quic/core/qpack/qpack_encoder_test_utils.h" -#include "net/third_party/spdy/core/hpack/hpack_encoder.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h" namespace quic { namespace test {
diff --git a/net/third_party/quic/core/qpack/qpack_encoder_test_utils.h b/net/third_party/quic/core/qpack/qpack_encoder_test_utils.h index 69e6b67..1442aae 100644 --- a/net/third_party/quic/core/qpack/qpack_encoder_test_utils.h +++ b/net/third_party/quic/core/qpack/qpack_encoder_test_utils.h
@@ -10,7 +10,7 @@ #include "net/third_party/quic/platform/api/quic_string.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" #include "net/third_party/quic/platform/api/quic_test.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" namespace quic { namespace test {
diff --git a/net/third_party/quic/core/qpack/qpack_header_table.h b/net/third_party/quic/core/qpack/qpack_header_table.h index 1d1f90c..319386d6 100644 --- a/net/third_party/quic/core/qpack/qpack_header_table.h +++ b/net/third_party/quic/core/qpack/qpack_header_table.h
@@ -9,8 +9,8 @@ #include "net/third_party/quic/platform/api/quic_export.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" -#include "net/third_party/spdy/core/hpack/hpack_entry.h" -#include "net/third_party/spdy/core/hpack/hpack_header_table.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_header_table.h" namespace quic {
diff --git a/net/third_party/quic/core/qpack/qpack_header_table_test.cc b/net/third_party/quic/core/qpack/qpack_header_table_test.cc index 9238478..6f4496f 100644 --- a/net/third_party/quic/core/qpack/qpack_header_table_test.cc +++ b/net/third_party/quic/core/qpack/qpack_header_table_test.cc
@@ -8,7 +8,7 @@ #include "net/third_party/quic/core/qpack/qpack_test_utils.h" #include "net/third_party/quic/platform/api/quic_arraysize.h" #include "net/third_party/quic/platform/api/quic_test.h" -#include "net/third_party/spdy/core/hpack/hpack_entry.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_entry.h" #include "testing/gtest/include/gtest/gtest.h" namespace quic {
diff --git a/net/third_party/quic/core/qpack/qpack_progressive_encoder.h b/net/third_party/quic/core/qpack/qpack_progressive_encoder.h index 07442be..519a572 100644 --- a/net/third_party/quic/core/qpack/qpack_progressive_encoder.h +++ b/net/third_party/quic/core/qpack/qpack_progressive_encoder.h
@@ -11,8 +11,8 @@ #include "net/third_party/quic/core/qpack/qpack_instruction_encoder.h" #include "net/third_party/quic/core/quic_types.h" #include "net/third_party/quic/platform/api/quic_export.h" -#include "net/third_party/spdy/core/hpack/hpack_encoder.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" namespace quic {
diff --git a/net/third_party/quic/core/qpack/qpack_round_trip_test.cc b/net/third_party/quic/core/qpack/qpack_round_trip_test.cc index 117b0b7..de99dce 100644 --- a/net/third_party/quic/core/qpack/qpack_round_trip_test.cc +++ b/net/third_party/quic/core/qpack/qpack_round_trip_test.cc
@@ -10,7 +10,7 @@ #include "net/third_party/quic/platform/api/quic_string.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" #include "net/third_party/quic/platform/api/quic_test.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "testing/gtest/include/gtest/gtest.h" using ::testing::Combine;
diff --git a/net/third_party/quic/core/qpack/qpack_static_table.h b/net/third_party/quic/core/qpack/qpack_static_table.h index e5367b9..4c2c3dc 100644 --- a/net/third_party/quic/core/qpack/qpack_static_table.h +++ b/net/third_party/quic/core/qpack/qpack_static_table.h
@@ -8,8 +8,8 @@ #include <vector> #include "net/third_party/quic/platform/api/quic_export.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/hpack/hpack_static_table.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_static_table.h" namespace quic {
diff --git a/net/third_party/quic/core/quic_connection.cc b/net/third_party/quic/core/quic_connection.cc index a1d5d9d..3c261c19 100644 --- a/net/third_party/quic/core/quic_connection.cc +++ b/net/third_party/quic/core/quic_connection.cc
@@ -47,10 +47,6 @@ namespace { -// The largest gap in packets we'll accept without closing the connection. -// This will likely have to be tuned. -const QuicPacketNumber kMaxPacketGap = 5000; - // Maximum number of acks received before sending an ack in response. // TODO(fayang): Remove this constant when deprecating QUIC_VERSION_35. const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20; @@ -79,7 +75,7 @@ const int kMinReleaseTimeIntoFutureMs = 1; bool Near(QuicPacketNumber a, QuicPacketNumber b) { - QuicPacketNumber delta = (a > b) ? a - b : b - a; + QuicPacketCount delta = (a > b) ? a - b : b - a; return delta <= kMaxPacketGap; }
diff --git a/net/third_party/quic/core/quic_connection.h b/net/third_party/quic/core/quic_connection.h index c2f4ef96..691d4d0 100644 --- a/net/third_party/quic/core/quic_connection.h +++ b/net/third_party/quic/core/quic_connection.h
@@ -792,6 +792,20 @@ fill_up_link_during_probing_ = new_value; } + // This setting may be changed during the crypto handshake in order to + // enable/disable padding of different packets in the crypto handshake. + // + // This setting should never be set to false in public facing endpoints. It + // can only be set to false if there is some other mechanism of preventing + // amplification attacks, such as ICE (plus its a non-standard quic). + void set_fully_pad_crypto_hadshake_packets(bool new_value) { + packet_generator_.set_fully_pad_crypto_hadshake_packets(new_value); + } + + bool fully_pad_during_crypto_handshake() const { + return packet_generator_.fully_pad_crypto_handshake_packets(); + } + size_t min_received_before_ack_decimation() const { return min_received_before_ack_decimation_; }
diff --git a/net/third_party/quic/core/quic_connection_stats.h b/net/third_party/quic/core/quic_connection_stats.h index 552da5d..6a67121 100644 --- a/net/third_party/quic/core/quic_connection_stats.h +++ b/net/third_party/quic/core/quic_connection_stats.h
@@ -73,7 +73,7 @@ // Number of packets received out of packet number order. QuicPacketCount packets_reordered; // Maximum reordering observed in packet number space. - QuicPacketNumber max_sequence_reordering; + QuicPacketCount max_sequence_reordering; // Maximum reordering observed in microseconds int64_t max_time_reordering_us;
diff --git a/net/third_party/quic/core/quic_connection_test.cc b/net/third_party/quic/core/quic_connection_test.cc index 310006a..29d1001 100644 --- a/net/third_party/quic/core/quic_connection_test.cc +++ b/net/third_party/quic/core/quic_connection_test.cc
@@ -108,7 +108,7 @@ bool SetIV(QuicStringPiece iv) override { return true; } bool EncryptPacket(QuicTransportVersion /*version*/, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output, @@ -173,7 +173,7 @@ } bool DecryptPacket(QuicTransportVersion /*version*/, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output, @@ -575,7 +575,7 @@ } void SendPacket(EncryptionLevel level, - QuicPacketNumber packet_number, + uint64_t packet_number, std::unique_ptr<QuicPacket> packet, HasRetransmittableData retransmittable, bool has_ack, @@ -930,7 +930,7 @@ void use_tagging_decrypter() { writer_->use_tagging_decrypter(); } - void ProcessPacket(QuicPacketNumber number) { + void ProcessPacket(uint64_t number) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacket(number); if (connection_.GetSendAlarm()->IsSet()) { @@ -1005,7 +1005,7 @@ QuicReceivedPacket(encrypted_buffer, encrypted_length, clock_.Now())); } - size_t ProcessFramePacketAtLevel(QuicPacketNumber number, + size_t ProcessFramePacketAtLevel(uint64_t number, QuicFrame frame, EncryptionLevel level) { QuicPacketHeader header; @@ -1030,11 +1030,11 @@ return encrypted_length; } - size_t ProcessDataPacket(QuicPacketNumber number) { + size_t ProcessDataPacket(uint64_t number) { return ProcessDataPacketAtLevel(number, false, ENCRYPTION_NONE); } - size_t ProcessDataPacketAtLevel(QuicPacketNumber number, + size_t ProcessDataPacketAtLevel(uint64_t number, bool has_stop_waiting, EncryptionLevel level) { std::unique_ptr<QuicPacket> packet( @@ -1051,7 +1051,7 @@ return encrypted_length; } - void ProcessClosePacket(QuicPacketNumber number) { + void ProcessClosePacket(uint64_t number) { std::unique_ptr<QuicPacket> packet(ConstructClosePacket(number)); char buffer[kMaxPacketSize]; size_t encrypted_length = peer_framer_.EncryptPayload( @@ -1105,7 +1105,7 @@ connection_.OnStreamReset(id, error); } - void ProcessAckPacket(QuicPacketNumber packet_number, QuicAckFrame* frame) { + void ProcessAckPacket(uint64_t packet_number, QuicAckFrame* frame) { QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, packet_number - 1); ProcessFramePacket(QuicFrame(frame)); } @@ -1118,7 +1118,7 @@ ProcessFramePacket(QuicFrame(frame)); } - size_t ProcessStopWaitingPacketAtLevel(QuicPacketNumber number, + size_t ProcessStopWaitingPacketAtLevel(uint64_t number, QuicStopWaitingFrame* frame, EncryptionLevel level) { return ProcessFramePacketAtLevel(number, QuicFrame(frame), @@ -1129,7 +1129,7 @@ ProcessFramePacket(QuicFrame(frame)); } - bool IsMissing(QuicPacketNumber number) { + bool IsMissing(uint64_t number) { return IsAwaitingPacket(*outgoing_ack(), number, 0); } @@ -1140,7 +1140,7 @@ return packet; } - std::unique_ptr<QuicPacket> ConstructDataPacket(QuicPacketNumber number, + std::unique_ptr<QuicPacket> ConstructDataPacket(uint64_t number, bool has_stop_waiting) { QuicPacketHeader header; // Set connection_id to peer's in memory representation as this data packet @@ -1174,7 +1174,7 @@ &peer_creator_); } - std::unique_ptr<QuicPacket> ConstructClosePacket(QuicPacketNumber number) { + std::unique_ptr<QuicPacket> ConstructClosePacket(uint64_t number) { QuicPacketHeader header; // Set connection_id to peer's in memory representation as this connection // close packet is created by peer_framer. @@ -1201,8 +1201,7 @@ return QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); } - const QuicStopWaitingFrame InitStopWaitingFrame( - QuicPacketNumber least_unacked) { + const QuicStopWaitingFrame InitStopWaitingFrame(uint64_t least_unacked) { QuicStopWaitingFrame frame; frame.least_unacked = least_unacked; return frame; @@ -1211,8 +1210,7 @@ // Construct a ack_frame that acks all packet numbers between 1 and // |largest_acked|, except |missing|. // REQUIRES: 1 <= |missing| < |largest_acked| - QuicAckFrame ConstructAckFrame(QuicPacketNumber largest_acked, - QuicPacketNumber missing) { + QuicAckFrame ConstructAckFrame(uint64_t largest_acked, uint64_t missing) { if (missing == 1) { return InitAckFrame({{missing + 1, largest_acked + 1}}); } @@ -2457,17 +2455,11 @@ ProcessAckPacket(&frame); } -TEST_P(QuicConnectionTest, AckAll) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(1); - - QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1); - QuicAckFrame frame1; - ProcessAckPacket(&frame1); -} - TEST_P(QuicConnectionTest, BasicSending) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacket(QuicPacketNumber(1)); + QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, QuicPacketNumber(2)); QuicPacketNumber last_packet; SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet); // Packet 1 EXPECT_EQ(1u, last_packet); @@ -2665,6 +2657,10 @@ // Process a data packet to queue up a pending ack. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacket(1); + QuicPacketNumber last_packet; + SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet); + // Verify ack is bundled with outging packet. + EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_CALL(visitor_, OnCanWrite()) .WillOnce(DoAll(IgnoreResult(InvokeWithoutArgs( @@ -2674,9 +2670,9 @@ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - // Process an ack to cause the visitor's OnCanWrite to be invoked. - QuicAckFrame ack_one; - ProcessAckPacket(3, &ack_one); + // Process a data packet to cause the visitor's OnCanWrite to be invoked. + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacket(2); EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); @@ -3379,6 +3375,10 @@ // Test sending multiple acks from the connection to the session. TEST_P(QuicConnectionTest, MultipleAcks) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacket(1); + QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2); QuicPacketNumber last_packet; SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet); // Packet 1 EXPECT_EQ(1u, last_packet); @@ -3395,7 +3395,6 @@ // Client will ack packets 1, 2, [!3], 4, 5. EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); QuicAckFrame frame1 = ConstructAckFrame(5, 3); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessAckPacket(&frame1); // Now the client implicitly acks 3, and explicitly acks 6. @@ -3405,11 +3404,14 @@ } TEST_P(QuicConnectionTest, DontLatchUnackedPacket) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacket(1); + QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2); SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr); // Packet 1; // From now on, we send acks, so the send algorithm won't mark them pending. SendAckPacketToPeer(); // Packet 2 - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); QuicAckFrame frame = InitAckFrame(1); ProcessAckPacket(&frame); @@ -4153,7 +4155,8 @@ connection_.GetMtuDiscoveryAlarm()->Fire(); EXPECT_EQ(kMtuDiscoveryTargetPacketSizeHigh, probe_size); - const QuicPacketCount probe_packet_number = packets_between_probes_base + 1; + const QuicPacketNumber probe_packet_number = + kFirstSendingPacketNumber + packets_between_probes_base; ASSERT_EQ(probe_packet_number, creator_->packet_number()); // Acknowledge all packets sent so far. @@ -4282,7 +4285,8 @@ connection_.GetMtuDiscoveryAlarm()->Fire(); EXPECT_EQ(mtu_limit, probe_size); - const QuicPacketCount probe_sequence_number = packets_between_probes_base + 1; + const QuicPacketNumber probe_sequence_number = + kFirstSendingPacketNumber + packets_between_probes_base; ASSERT_EQ(probe_sequence_number, creator_->packet_number()); // Acknowledge all packets sent so far. @@ -6590,6 +6594,9 @@ } TEST_P(QuicConnectionTest, SendAcksImmediately) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacket(1); CongestionBlockWrites(); SendAckPacketToPeer(); } @@ -6981,6 +6988,9 @@ } TEST_P(QuicConnectionTest, NoPathDegradingAfterSendingAck) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacket(1); SendAckPacketToPeer(); EXPECT_FALSE(connection_.sent_packet_manager().unacked_packets().empty()); EXPECT_FALSE(connection_.sent_packet_manager().HasInFlightPackets());
diff --git a/net/third_party/quic/core/quic_constants.h b/net/third_party/quic/core/quic_constants.h index fe15bda..e4b7d63 100644 --- a/net/third_party/quic/core/quic_constants.h +++ b/net/third_party/quic/core/quic_constants.h
@@ -181,7 +181,7 @@ // The largest gap in packets we'll accept without closing the connection. // This will likely have to be tuned. -const QuicPacketNumber kMaxPacketGap = 5000; +const QuicPacketCount kMaxPacketGap = 5000; // The maximum number of random padding bytes to add. const QuicByteCount kMaxNumRandomPaddingBytes = 256; @@ -224,6 +224,11 @@ // Maximum length allowed for the token in a NEW_TOKEN frame. const size_t kMaxNewTokenTokenLength = 0xffff; +// Packet number of first sending packet of a connection. Please note, this +// cannot be used as first received packet because peer can choose its starting +// packet number. +const QuicPacketNumber kFirstSendingPacketNumber = 1; + // Used to represent an invalid packet number. const QuicPacketNumber kInvalidPacketNumber = 0;
diff --git a/net/third_party/quic/core/quic_crypto_client_handshaker.cc b/net/third_party/quic/core/quic_crypto_client_handshaker.cc index 2ddcfe4..b8b6498 100644 --- a/net/third_party/quic/core/quic_crypto_client_handshaker.cc +++ b/net/third_party/quic/core/quic_crypto_client_handshaker.cc
@@ -340,11 +340,10 @@ "CHLO too large"); return; } - // TODO(rch): Remove this when we remove quic_use_chlo_packet_size flag. - out.set_minimum_size( - static_cast<size_t>(max_packet_size - kFramingOverhead)); next_state_ = STATE_RECV_REJ; CryptoUtils::HashHandshakeMessage(out, &chlo_hash_, Perspective::IS_CLIENT); + session()->connection()->set_fully_pad_crypto_hadshake_packets( + crypto_config_->pad_inchoate_hello()); SendHandshakeMessage(out); return; } @@ -379,6 +378,8 @@ *cached->proof_verify_details()); } next_state_ = STATE_RECV_SHLO; + session()->connection()->set_fully_pad_crypto_hadshake_packets( + crypto_config_->pad_full_hello()); SendHandshakeMessage(out); // Be prepared to decrypt with the new server write key. session()->connection()->SetAlternativeDecrypter(
diff --git a/net/third_party/quic/core/quic_crypto_client_handshaker_test.cc b/net/third_party/quic/core/quic_crypto_client_handshaker_test.cc new file mode 100644 index 0000000..8a8d2ca --- /dev/null +++ b/net/third_party/quic/core/quic_crypto_client_handshaker_test.cc
@@ -0,0 +1,213 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quic/core/quic_crypto_client_handshaker.h" +#include "net/third_party/quic/core/proto/crypto_server_config.pb.h" +#include "net/third_party/quic/core/tls_client_handshaker.h" +#include "net/third_party/quic/core/tls_server_handshaker.h" +#include "net/third_party/quic/test_tools/quic_test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace quic { +namespace { + +using ::testing::Test; + +class TestProofHandler : public QuicCryptoClientStream::ProofHandler { + public: + ~TestProofHandler() override {} + void OnProofValid( + const QuicCryptoClientConfig::CachedState& cached) override {} + void OnProofVerifyDetailsAvailable( + const ProofVerifyDetails& verify_details) override {} +}; + +class InsecureProofVerifier : public ProofVerifier { + public: + InsecureProofVerifier() {} + ~InsecureProofVerifier() override {} + + // ProofVerifier override. + QuicAsyncStatus VerifyProof( + const QuicString& hostname, + const uint16_t port, + const QuicString& server_config, + QuicTransportVersion transport_version, + QuicStringPiece chlo_hash, + const std::vector<QuicString>& certs, + const QuicString& cert_sct, + const QuicString& signature, + const ProofVerifyContext* context, + QuicString* error_details, + std::unique_ptr<ProofVerifyDetails>* verify_details, + std::unique_ptr<ProofVerifierCallback> callback) override { + return QUIC_SUCCESS; + } + + QuicAsyncStatus VerifyCertChain( + const QuicString& hostname, + const std::vector<QuicString>& certs, + const ProofVerifyContext* context, + QuicString* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> callback) override { + return QUIC_SUCCESS; + } + + std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override { + return nullptr; + } +}; + +class DummyProofSource : public ProofSource { + public: + DummyProofSource() {} + ~DummyProofSource() override {} + + // ProofSource override. + void GetProof(const QuicSocketAddress& server_address, + const QuicString& hostname, + const QuicString& server_config, + QuicTransportVersion transport_version, + QuicStringPiece chlo_hash, + std::unique_ptr<Callback> callback) override { + QuicReferenceCountedPointer<ProofSource::Chain> chain = + GetCertChain(server_address, hostname); + QuicCryptoProof proof; + proof.signature = "Dummy signature"; + proof.leaf_cert_scts = "Dummy timestamp"; + callback->Run(true, chain, proof, nullptr /* details */); + } + + QuicReferenceCountedPointer<Chain> GetCertChain( + const QuicSocketAddress& server_address, + const QuicString& hostname) override { + std::vector<QuicString> certs; + certs.push_back("Dummy cert"); + return QuicReferenceCountedPointer<ProofSource::Chain>( + new ProofSource::Chain(certs)); + } + + void ComputeTlsSignature( + const QuicSocketAddress& server_address, + const QuicString& hostname, + uint16_t signature_algorithm, + QuicStringPiece in, + std::unique_ptr<SignatureCallback> callback) override { + callback->Run(true, "Dummy signature"); + } +}; + +class Handshaker : public QuicCryptoClientHandshaker { + public: + Handshaker(const QuicServerId& server_id, + QuicCryptoClientStream* stream, + QuicSession* session, + std::unique_ptr<ProofVerifyContext> verify_context, + QuicCryptoClientConfig* crypto_config, + QuicCryptoClientStream::ProofHandler* proof_handler) + : QuicCryptoClientHandshaker(server_id, + stream, + session, + std::move(verify_context), + crypto_config, + proof_handler) {} + + void DoSendCHLOTest(QuicCryptoClientConfig::CachedState* cached) { + QuicCryptoClientHandshaker::DoSendCHLO(cached); + } +}; + +class QuicCryptoClientHandshakerTest : public Test { + protected: + QuicCryptoClientHandshakerTest() + : proof_handler_(), + helper_(), + alarm_factory_(), + server_id_("host", 123), + connection_(new test::MockQuicConnection(&helper_, + &alarm_factory_, + Perspective::IS_CLIENT)), + session_(connection_, false), + crypto_client_config_(std::make_unique<InsecureProofVerifier>(), + quic::TlsClientHandshaker::CreateSslCtx()), + client_stream_(new QuicCryptoClientStream(server_id_, + &session_, + nullptr, + &crypto_client_config_, + &proof_handler_)), + handshaker_(server_id_, + client_stream_, + &session_, + nullptr, + &crypto_client_config_, + &proof_handler_), + state_() { + // Session takes the ownership of the client stream! (but handshaker also + // takes a reference to it, but doesn't take the ownership). + session_.SetCryptoStream(client_stream_); + session_.Initialize(); + } + + void InitializeServerParametersToEnableFullHello() { + QuicCryptoServerConfig::ConfigOptions options; + std::unique_ptr<QuicServerConfigProtobuf> config = + QuicCryptoServerConfig::GenerateConfig(helper_.GetRandomGenerator(), + helper_.GetClock(), options); + state_.Initialize( + config->config(), "sourcetoken", std::vector<QuicString>{"Dummy cert"}, + "", "chlo_hash", "signature", helper_.GetClock()->WallNow(), + helper_.GetClock()->WallNow().Add(QuicTime::Delta::FromSeconds(30))); + + state_.SetProofValid(); + } + + TestProofHandler proof_handler_; + test::MockQuicConnectionHelper helper_; + test::MockAlarmFactory alarm_factory_; + QuicServerId server_id_; + // Session takes the ownership of the connection. + test::MockQuicConnection* connection_; + test::MockQuicSession session_; + QuicCryptoClientConfig crypto_client_config_; + QuicCryptoClientStream* client_stream_; + Handshaker handshaker_; + QuicCryptoClientConfig::CachedState state_; +}; + +TEST_F(QuicCryptoClientHandshakerTest, TestSendFullPaddingInInchoateHello) { + handshaker_.DoSendCHLOTest(&state_); + + EXPECT_TRUE(connection_->fully_pad_during_crypto_handshake()); +} + +TEST_F(QuicCryptoClientHandshakerTest, TestDisabledPaddingInInchoateHello) { + crypto_client_config_.set_pad_inchoate_hello(false); + handshaker_.DoSendCHLOTest(&state_); + EXPECT_FALSE(connection_->fully_pad_during_crypto_handshake()); +} + +TEST_F(QuicCryptoClientHandshakerTest, + TestPaddingInFullHelloEvenIfInchoateDisabled) { + // Disable inchoate, but full hello should still be padded. + crypto_client_config_.set_pad_inchoate_hello(false); + + InitializeServerParametersToEnableFullHello(); + + handshaker_.DoSendCHLOTest(&state_); + EXPECT_TRUE(connection_->fully_pad_during_crypto_handshake()); +} + +TEST_F(QuicCryptoClientHandshakerTest, TestNoPaddingInFullHelloWhenDisabled) { + crypto_client_config_.set_pad_full_hello(false); + + InitializeServerParametersToEnableFullHello(); + + handshaker_.DoSendCHLOTest(&state_); + EXPECT_FALSE(connection_->fully_pad_during_crypto_handshake()); +} + +} // namespace +} // namespace quic
diff --git a/net/third_party/quic/core/quic_crypto_server_handshaker.cc b/net/third_party/quic/core/quic_crypto_server_handshaker.cc index 2660edb..e8adf17 100644 --- a/net/third_party/quic/core/quic_crypto_server_handshaker.cc +++ b/net/third_party/quic/core/quic_crypto_server_handshaker.cc
@@ -184,6 +184,8 @@ // retransmitted. session()->connection()->EnableSavingCryptoPackets(); } + session()->connection()->set_fully_pad_crypto_hadshake_packets( + crypto_config_->pad_rej()); SendHandshakeMessage(*reply); if (reply->tag() == kSREJ) { @@ -233,6 +235,8 @@ std::move(crypto_negotiated_params_->initial_crypters.decrypter)); session()->connection()->SetDiversificationNonce(*diversification_nonce); + session()->connection()->set_fully_pad_crypto_hadshake_packets( + crypto_config_->pad_shlo()); SendHandshakeMessage(*reply); session()->connection()->SetEncrypter(
diff --git a/net/third_party/quic/core/quic_dispatcher_test.cc b/net/third_party/quic/core/quic_dispatcher_test.cc index 919cc7f..8f6aa01 100644 --- a/net/third_party/quic/core/quic_dispatcher_test.cc +++ b/net/third_party/quic/core/quic_dispatcher_test.cc
@@ -268,7 +268,7 @@ const QuicString& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, - QuicPacketNumber packet_number) { + uint64_t packet_number) { ProcessPacket(peer_address, connection_id, has_version_flag, CurrentSupportedVersions().front(), data, connection_id_length, packet_number_length, packet_number); @@ -282,7 +282,7 @@ const QuicString& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, - QuicPacketNumber packet_number) { + uint64_t packet_number) { ParsedQuicVersionVector versions(SupportedVersions(version)); std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( connection_id, EmptyQuicConnectionId(), has_version_flag, false,
diff --git a/net/third_party/quic/core/quic_framer.cc b/net/third_party/quic/core/quic_framer.cc index dc455af..6304730c 100644 --- a/net/third_party/quic/core/quic_framer.cc +++ b/net/third_party/quic/core/quic_framer.cc
@@ -130,7 +130,7 @@ const uint8_t kSourceConnectionIdLengthMask = 0x0F; // Returns the absolute value of the difference between |a| and |b|. -QuicPacketNumber Delta(QuicPacketNumber a, QuicPacketNumber b) { +uint64_t Delta(uint64_t a, uint64_t b) { // Since these are unsigned numbers, we can't just return abs(a - b) if (a < b) { return b - a; @@ -138,9 +138,7 @@ return a - b; } -QuicPacketNumber ClosestTo(QuicPacketNumber target, - QuicPacketNumber a, - QuicPacketNumber b) { +uint64_t ClosestTo(uint64_t target, uint64_t a, uint64_t b) { return (Delta(target, a) < Delta(target, b)) ? a : b; } @@ -331,7 +329,7 @@ Perspective perspective) : visitor_(nullptr), error_(QUIC_NO_ERROR), - largest_packet_number_(0), + largest_packet_number_(kInvalidPacketNumber), last_serialized_connection_id_(EmptyQuicConnectionId()), last_version_label_(0), last_header_form_(GOOGLE_QUIC_PACKET), @@ -1055,10 +1053,30 @@ return writer.length(); } +size_t QuicFramer::BuildIetfConnectivityProbingPacket( + const QuicPacketHeader& header, + char* buffer, + size_t packet_length) { + QuicFrames frames; + + // Write a PING frame, which has no data payload. + QuicPingFrame ping_frame; + frames.push_back(QuicFrame(ping_frame)); + + // Add padding to the rest of the packet. + QuicPaddingFrame padding_frame; + frames.push_back(QuicFrame(padding_frame)); + + return BuildIetfDataPacket(header, frames, buffer, packet_length); +} + size_t QuicFramer::BuildConnectivityProbingPacket( const QuicPacketHeader& header, char* buffer, size_t packet_length) { + if (version_.transport_version == QUIC_VERSION_99) { + return BuildIetfConnectivityProbingPacket(header, buffer, packet_length); + } QuicDataWriter writer(packet_length, buffer, endianness()); if (!AppendPacketHeader(header, &writer)) { @@ -1093,47 +1111,25 @@ size_t packet_length, QuicPathFrameBuffer* payload, QuicRandom* randomizer) { - QuicDataWriter writer(packet_length, buffer, endianness()); - DCHECK_EQ(version_.transport_version, QUIC_VERSION_99) - << "Attempt to build a PATH_CHALLENGE Connectivity Probing packet and " - "not doing IETF QUIC"; - - if (!AppendPacketHeader(header, &writer)) { - QUIC_BUG << "AppendPacketHeader failed"; + if (version_.transport_version != QUIC_VERSION_99) { + QUIC_BUG << "Attempt to build a PATH_CHALLENGE Connectivity Probing " + "packet and not doing IETF QUIC"; return 0; } + QuicFrames frames; // Write a PATH_CHALLENGE frame, which has a random 8-byte payload randomizer->RandBytes(payload->data(), payload->size()); QuicPathChallengeFrame path_challenge_frame(0, *payload); - if (!AppendTypeByte(QuicFrame(&path_challenge_frame), - /* last_frame_in_packet = */ false, &writer)) { - QUIC_BUG - << "AppendTypeByte failed for PATH_CHALLENGE frame in probing packet"; - return 0; - } - - if (!AppendPathChallengeFrame(path_challenge_frame, &writer)) { - QUIC_BUG << "AppendPathChallengeFrame failed for PATH_CHALLENGE frame in " - "probing packet"; - return 0; - } + frames.push_back(QuicFrame(&path_challenge_frame)); // Add padding to the rest of the packet in order to assess Path MTU // characteristics. QuicPaddingFrame padding_frame; - if (!AppendTypeByte(QuicFrame(padding_frame), true, &writer)) { - QUIC_BUG << "AppendTypeByte failed for padding frame in probing packet"; - return 0; - } - if (!AppendPaddingFrame(padding_frame, &writer)) { - QUIC_BUG << "AppendPaddingFrame of " << padding_frame.num_padding_bytes - << " failed"; - return 0; - } + frames.push_back(QuicFrame(padding_frame)); - return writer.length(); + return BuildIetfDataPacket(header, frames, buffer, packet_length); } size_t QuicFramer::BuildPathResponsePacket( @@ -1147,53 +1143,33 @@ << "Attempt to generate connectivity response with no request payloads"; return 0; } - - QuicDataWriter writer(packet_length, buffer, endianness()); - - DCHECK_EQ(version_.transport_version, QUIC_VERSION_99) - << "Attempt to build a PATH_RESPONSE Connectivity Probing packet and " - "not doing IETF QUIC"; - - if (!AppendPacketHeader(header, &writer)) { - QUIC_BUG << "AppendPacketHeader failed"; + if (version_.transport_version != QUIC_VERSION_99) { + QUIC_BUG << "Attempt to build a PATH_RESPONSE Connectivity Probing " + "packet and not doing IETF QUIC"; return 0; } - // Write a set of PATH_RESPONSE frames to a single packet, each with the - // 8-byte payload of the corresponding PATH_REQUEST frame from a single - // received packet. + std::vector<std::unique_ptr<QuicPathResponseFrame>> path_response_frames; for (const QuicPathFrameBuffer& payload : payloads) { // Note that the control frame ID can be 0 since this is not retransmitted. - QuicPathResponseFrame path_response_frame(0, payload); + path_response_frames.push_back( + QuicMakeUnique<QuicPathResponseFrame>(0, payload)); + } - if (!AppendTypeByte(QuicFrame(&path_response_frame), false, &writer)) { - QUIC_BUG - << "AppendTypeByte failed for PATH_RESPONSE frame in probing packet"; - return 0; - } - - if (!AppendPathResponseFrame(path_response_frame, &writer)) { - QUIC_BUG << "AppendPathChallengeFrame failed for PATH_CHALLENGE frame in " - "probing packet"; - return 0; - } + QuicFrames frames; + for (const std::unique_ptr<QuicPathResponseFrame>& path_response_frame : + path_response_frames) { + frames.push_back(QuicFrame(path_response_frame.get())); } if (is_padded) { // Add padding to the rest of the packet in order to assess Path MTU // characteristics. QuicPaddingFrame padding_frame; - if (!AppendTypeByte(QuicFrame(padding_frame), true, &writer)) { - QUIC_BUG << "AppendTypeByte failed for padding frame in probing packet"; - return 0; - } - if (!AppendPaddingFrame(padding_frame, &writer)) { - QUIC_BUG << "AppendPaddingFrame of " << padding_frame.num_padding_bytes - << " failed"; - return 0; - } + frames.push_back(QuicFrame(padding_frame)); } - return writer.length(); + + return BuildIetfDataPacket(header, frames, buffer, packet_length); } // static @@ -1493,15 +1469,15 @@ header->long_packet_type != VERSION_NEGOTIATION) { // Process packet number. QuicPacketNumber base_packet_number = largest_packet_number_; - + uint64_t full_packet_number; if (!ProcessAndCalculatePacketNumber( encrypted_reader, header->packet_number_length, base_packet_number, - &header->packet_number)) { + &full_packet_number)) { set_detailed_error("Unable to read packet number."); return RaiseError(QUIC_INVALID_PACKET_HEADER); } - if (header->packet_number == kInvalidPacketNumber) { + if (full_packet_number == kInvalidPacketNumber) { if (IsIetfStatelessResetPacket(*header)) { // This is a stateless reset packet. QuicIetfStatelessResetPacket packet( @@ -1512,6 +1488,7 @@ set_detailed_error("packet numbers cannot be 0."); return RaiseError(QUIC_INVALID_PACKET_HEADER); } + header->packet_number = full_packet_number; } // A nonce should only present in SHLO from the server to the client when @@ -1880,10 +1857,10 @@ return QuicTime::Delta::FromMicroseconds(time); } -QuicPacketNumber QuicFramer::CalculatePacketNumberFromWire( +uint64_t QuicFramer::CalculatePacketNumberFromWire( QuicPacketNumberLength packet_number_length, QuicPacketNumber base_packet_number, - QuicPacketNumber packet_number) const { + uint64_t packet_number) const { // The new packet number might have wrapped to the next epoch, or // it might have reverse wrapped to the previous epoch, or it might // remain in the same epoch. Select the packet number closest to the @@ -1892,12 +1869,14 @@ // epoch_delta is the delta between epochs the packet number was serialized // with, so the correct value is likely the same epoch as the last sequence // number or an adjacent epoch. - const QuicPacketNumber epoch_delta = UINT64_C(1) - << (8 * packet_number_length); - QuicPacketNumber next_packet_number = base_packet_number + 1; - QuicPacketNumber epoch = base_packet_number & ~(epoch_delta - 1); - QuicPacketNumber prev_epoch = epoch - epoch_delta; - QuicPacketNumber next_epoch = epoch + epoch_delta; + if (base_packet_number == kInvalidPacketNumber) { + return packet_number; + } + const uint64_t epoch_delta = UINT64_C(1) << (8 * packet_number_length); + uint64_t next_packet_number = base_packet_number + 1; + uint64_t epoch = base_packet_number & ~(epoch_delta - 1); + uint64_t prev_epoch = epoch - epoch_delta; + uint64_t next_epoch = epoch + epoch_delta; return ClosestTo(next_packet_number, epoch + packet_number, ClosestTo(next_packet_number, prev_epoch + packet_number, @@ -2048,7 +2027,7 @@ new_ack_info.num_ack_blocks < std::numeric_limits<uint8_t>::max(); previous_start = itr->min(), ++itr) { const auto& interval = *itr; - const QuicPacketNumber total_gap = previous_start - interval.max(); + const QuicPacketCount total_gap = previous_start - interval.max(); new_ack_info.num_ack_blocks += (total_gap + std::numeric_limits<uint8_t>::max() - 1) / std::numeric_limits<uint8_t>::max(); @@ -2061,18 +2040,19 @@ bool QuicFramer::ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader, QuicPacketHeader* header) { QuicPacketNumber base_packet_number = largest_packet_number_; - + uint64_t full_packet_number; if (!ProcessAndCalculatePacketNumber( encrypted_reader, header->packet_number_length, base_packet_number, - &header->packet_number)) { + &full_packet_number)) { set_detailed_error("Unable to read packet number."); return RaiseError(QUIC_INVALID_PACKET_HEADER); } - if (header->packet_number == kInvalidPacketNumber) { + if (full_packet_number == kInvalidPacketNumber) { set_detailed_error("packet numbers cannot be 0."); return RaiseError(QUIC_INVALID_PACKET_HEADER); } + header->packet_number = full_packet_number; if (!visitor_->OnUnauthenticatedHeader(*header)) { set_detailed_error( @@ -2228,8 +2208,8 @@ QuicDataReader* reader, QuicPacketNumberLength packet_number_length, QuicPacketNumber base_packet_number, - QuicPacketNumber* packet_number) { - QuicPacketNumber wire_packet_number; + uint64_t* packet_number) { + uint64_t wire_packet_number; if (!reader->ReadBytesToUInt64(packet_number_length, &wire_packet_number)) { return false; } @@ -2906,12 +2886,20 @@ ExtractBits(frame_type, kQuicSequenceNumberLengthNumBits, kLargestAckedOffset)); - QuicPacketNumber largest_acked; + uint64_t largest_acked; if (!reader->ReadBytesToUInt64(largest_acked_length, &largest_acked)) { set_detailed_error("Unable to read largest acked."); return false; } + if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) && largest_acked == 0u) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 1, 3); + // Connection always sends packet starting from kFirstSendingPacketNumber > + // 0, peer has observed an unsent packet. + set_detailed_error("Largest acked is 0."); + return false; + } + uint64_t ack_delay_time_us; if (!reader->ReadUFloat16(&ack_delay_time_us)) { set_detailed_error("Unable to read ack delay time."); @@ -2943,6 +2931,8 @@ if (first_block_length == 0) { // For non-empty ACKs, the first block length must be non-zero. + // TODO(fayang): remove this if and return false directly when deprecating + // quic_reloadable_flag_quic_disallow_peer_ack_0. if (largest_acked != 0 || num_ack_blocks != 0) { set_detailed_error( QuicStrCat("First block length is zero but ACK is " @@ -2952,9 +2942,15 @@ .c_str()); return false; } + DCHECK(!GetQuicReloadableFlag(quic_disallow_peer_ack_0)); } - - if (first_block_length > largest_acked + 1) { + bool first_ack_block_underflow = first_block_length > largest_acked + 1; + if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) && + first_block_length == largest_acked + 1) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 2, 3); + first_ack_block_underflow = true; + } + if (first_ack_block_underflow) { set_detailed_error(QuicStrCat("Underflow with first ack block length ", first_block_length, " largest acked is ", largest_acked, ".") @@ -2983,7 +2979,13 @@ set_detailed_error("Unable to ack block length."); return false; } - if (first_received < gap + current_block_length) { + bool ack_block_underflow = first_received < gap + current_block_length; + if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) && + first_received == gap + current_block_length) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 3, 3); + ack_block_underflow = true; + } + if (ack_block_underflow) { set_detailed_error( QuicStrCat("Underflow with ack block length ", current_block_length, ", end of block is ", first_received - gap, ".") @@ -3073,11 +3075,17 @@ bool QuicFramer::ProcessIetfAckFrame(QuicDataReader* reader, uint64_t frame_type, QuicAckFrame* ack_frame) { - QuicPacketNumber largest_acked; + uint64_t largest_acked; if (!reader->ReadVarInt62(&largest_acked)) { set_detailed_error("Unable to read largest acked."); return false; } + if (largest_acked == 0u) { + // Connection always sends packet starting from kFirstSendingPacketNumber > + // 0, peer has observed an unsent packet. + set_detailed_error("Largest acked is 0."); + return false; + } ack_frame->largest_acked = static_cast<QuicPacketNumber>(largest_acked); uint64_t ack_delay_time_in_us; if (!reader->ReadVarInt62(&ack_delay_time_in_us)) { @@ -3146,7 +3154,7 @@ // largest_acked packet which are in the block being acked. Thus, // its maximum value is largest_acked-1. Test this, reporting an // error if the value is wrong. - if (ack_block_value > largest_acked) { + if (ack_block_value >= largest_acked) { set_detailed_error(QuicStrCat("Underflow with first ack block length ", ack_block_value + 1, " largest acked is ", largest_acked, ".") @@ -3197,7 +3205,7 @@ set_detailed_error("Unable to read ack block value."); return false; } - if (ack_block_value > (block_high - 1)) { + if (ack_block_value >= (block_high - 1)) { set_detailed_error( QuicStrCat("Underflow with ack block length ", ack_block_value + 1, " latest ack block end is ", block_high - 1, ".") @@ -3225,7 +3233,7 @@ bool QuicFramer::ProcessStopWaitingFrame(QuicDataReader* reader, const QuicPacketHeader& header, QuicStopWaitingFrame* stop_waiting) { - QuicPacketNumber least_unacked_delta; + uint64_t least_unacked_delta; if (!reader->ReadBytesToUInt64(header.packet_number_length, &least_unacked_delta)) { set_detailed_error("Unable to read least unacked delta."); @@ -3639,18 +3647,18 @@ size_t ack_block_count_size = QuicDataWriter::GetVarInt62Len(ack_block_count); ack_frame_size += ack_block_count_size; - QuicPacketNumber first_ack_block = ack_block_largest - ack_block_smallest; + uint64_t first_ack_block = ack_block_largest - ack_block_smallest; size_t first_ack_block_size = QuicDataWriter::GetVarInt62Len(first_ack_block); ack_frame_size += first_ack_block_size; // Account for the remaining Intervals, if any. while (ack_block_count != 0) { - QuicPacketNumber gap_size = ack_block_smallest - itr->max(); + uint64_t gap_size = ack_block_smallest - itr->max(); // Decrement per the protocol specification size_t size_of_gap_size = QuicDataWriter::GetVarInt62Len(gap_size - 1); ack_frame_size += size_of_gap_size; - QuicPacketNumber block_size = itr->max() - itr->min(); + uint64_t block_size = itr->max() - itr->min(); // Decrement per the protocol specification size_t size_of_block_size = QuicDataWriter::GetVarInt62Len(block_size - 1); ack_frame_size += size_of_block_size; @@ -3666,6 +3674,7 @@ size_t QuicFramer::GetAckFrameSize( const QuicAckFrame& ack, QuicPacketNumberLength packet_number_length) { + DCHECK(!ack.packets.Empty()); size_t ack_size = 0; if (version_.transport_version == QUIC_VERSION_99) { @@ -3939,7 +3948,7 @@ // static bool QuicFramer::AppendAckBlock(uint8_t gap, QuicPacketNumberLength length_length, - QuicPacketNumber length, + uint64_t length, QuicDataWriter* writer) { return writer->WriteUInt8(gap) && AppendPacketNumber(length_length, length, writer); @@ -4227,7 +4236,7 @@ itr != frame.packets.rend() && num_ack_blocks_written < num_ack_blocks; previous_start = itr->min(), ++itr) { const auto& interval = *itr; - const QuicPacketNumber total_gap = previous_start - interval.max(); + const uint64_t total_gap = previous_start - interval.max(); const size_t num_encoded_gaps = (total_gap + std::numeric_limits<uint8_t>::max() - 1) / std::numeric_limits<uint8_t>::max(); @@ -4301,8 +4310,7 @@ auto it = frame.received_packet_times.begin(); QuicPacketNumber packet_number = it->first; - QuicPacketNumber delta_from_largest_observed = - LargestAcked(frame) - packet_number; + uint64_t delta_from_largest_observed = LargestAcked(frame) - packet_number; DCHECK_GE(std::numeric_limits<uint8_t>::max(), delta_from_largest_observed); if (delta_from_largest_observed > std::numeric_limits<uint8_t>::max()) { @@ -4349,7 +4357,8 @@ const QuicStopWaitingFrame& frame, QuicDataWriter* writer) { DCHECK_GE(QUIC_VERSION_43, version_.transport_version); - DCHECK_GE(header.packet_number, frame.least_unacked); + DCHECK(frame.least_unacked != kInvalidPacketNumber && + header.packet_number >= frame.least_unacked); const QuicPacketNumber least_unacked_delta = header.packet_number - frame.least_unacked; const QuicPacketNumber length_shift = header.packet_number_length * 8; @@ -4386,7 +4395,7 @@ return 0; } available_space -= encoded_size; - uint64_t previous_ack_end = itr->min(); + QuicPacketNumber previous_ack_end = itr->min(); ack_block_count--; while (ack_block_count) { @@ -4517,7 +4526,7 @@ return false; } - QuicPacketNumber first_ack_block = ack_block_largest - ack_block_smallest; + uint64_t first_ack_block = ack_block_largest - ack_block_smallest; if (!writer->WriteVarInt62(first_ack_block)) { set_detailed_error("No room for first ack block in ack frame"); return false; @@ -4525,13 +4534,13 @@ // For the remaining QuicAckFrame Intervals, if any while (ack_block_count != 0) { - QuicPacketNumber gap_size = ack_block_smallest - itr->max(); + uint64_t gap_size = ack_block_smallest - itr->max(); if (!writer->WriteVarInt62(gap_size - 1)) { set_detailed_error("No room for gap block in ack frame"); return false; } - QuicPacketNumber block_size = itr->max() - itr->min(); + uint64_t block_size = itr->max() - itr->min(); if (!writer->WriteVarInt62(block_size - 1)) { set_detailed_error("No room for nth ack block in ack frame"); return false;
diff --git a/net/third_party/quic/core/quic_framer.h b/net/third_party/quic/core/quic_framer.h index dc144e77..79b35a3 100644 --- a/net/third_party/quic/core/quic_framer.h +++ b/net/third_party/quic/core/quic_framer.h
@@ -378,6 +378,12 @@ char* buffer, size_t packet_length); + // Serializes an IETF probing packet, which is a padded PING packet. + // Returns the length of the packet. Returns 0 if it fails to serialize. + size_t BuildIetfConnectivityProbingPacket(const QuicPacketHeader& header, + char* buffer, + size_t packet_length); + // Serialize a probing packet that uses IETF QUIC's PATH CHALLENGE frame. Also // fills the packet with padding. size_t BuildPaddedPathChallengePacket(const QuicPacketHeader& header, @@ -549,9 +555,9 @@ ~AckFrameInfo(); // The maximum ack block length. - QuicPacketNumber max_block_length; + QuicPacketCount max_block_length; // Length of first ack block. - QuicPacketNumber first_block_length; + QuicPacketCount first_block_length; // Number of ACK blocks needed for the ACK frame. size_t num_ack_blocks; }; @@ -601,7 +607,7 @@ QuicDataReader* reader, QuicPacketNumberLength packet_number_length, QuicPacketNumber base_packet_number, - QuicPacketNumber* packet_number); + uint64_t* packet_number); bool ProcessFrameData(QuicDataReader* reader, const QuicPacketHeader& header); bool ProcessIetfFrameData(QuicDataReader* reader, const QuicPacketHeader& header); @@ -639,10 +645,10 @@ // Returns the full packet number from the truncated // wire format version and the last seen packet number. - QuicPacketNumber CalculatePacketNumberFromWire( + uint64_t CalculatePacketNumberFromWire( QuicPacketNumberLength packet_number_length, QuicPacketNumber base_packet_number, - QuicPacketNumber packet_number) const; + uint64_t packet_number) const; // Returns the QuicTime::Delta corresponding to the time from when the framer // was created. @@ -679,7 +685,7 @@ // successfully appended. static bool AppendAckBlock(uint8_t gap, QuicPacketNumberLength length_length, - QuicPacketNumber length, + uint64_t length, QuicDataWriter* writer); static uint8_t GetPacketNumberFlags(
diff --git a/net/third_party/quic/core/quic_framer_test.cc b/net/third_party/quic/core/quic_framer_test.cc index 169182c..43cde29 100644 --- a/net/third_party/quic/core/quic_framer_test.cc +++ b/net/third_party/quic/core/quic_framer_test.cc
@@ -36,8 +36,8 @@ namespace test { namespace { -const QuicPacketNumber kEpoch = UINT64_C(1) << 32; -const QuicPacketNumber kMask = kEpoch - 1; +const uint64_t kEpoch = UINT64_C(1) << 32; +const uint64_t kMask = kEpoch - 1; const QuicUint128 kTestStatelessResetToken = 1010101; // 0x0F69B5 @@ -83,7 +83,7 @@ bool SetNoncePrefix(QuicStringPiece nonce_prefix) override { return true; } bool SetIV(QuicStringPiece iv) override { return true; } bool EncryptPacket(QuicTransportVersion version, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output, @@ -129,7 +129,7 @@ return true; } bool DecryptPacket(QuicTransportVersion version, - QuicPacketNumber packet_number, + uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output, @@ -585,9 +585,9 @@ EXPECT_EQ(str, QuicString(frame->data_buffer, frame->data_length)); } - void CheckCalculatePacketNumber(QuicPacketNumber expected_packet_number, + void CheckCalculatePacketNumber(uint64_t expected_packet_number, QuicPacketNumber last_packet_number) { - QuicPacketNumber wire_packet_number = expected_packet_number & kMask; + uint64_t wire_packet_number = expected_packet_number & kMask; EXPECT_EQ(expected_packet_number, QuicFramerPeer::CalculatePacketNumberFromWire( &framer_, PACKET_4BYTE_PACKET_NUMBER, last_packet_number, @@ -636,7 +636,7 @@ CheckCalculatePacketNumber(kEpoch, kMask); // Cases where the last number was close to the start of the range. - for (uint64_t last = 0; last < 10; last++) { + for (QuicPacketNumber last = 0; last < 10; last++) { // Small numbers should not wrap (even if they're out of order). for (uint64_t j = 0; j < 10; j++) { CheckCalculatePacketNumber(j, last); @@ -673,7 +673,7 @@ const uint64_t cur_epoch = 2 * kEpoch; // Cases where the last number was close to the start of the range for (uint64_t i = 0; i < 10; i++) { - uint64_t last = cur_epoch + i; + QuicPacketNumber last = cur_epoch + i; // Small number should not wrap (even if they're out of order). for (uint64_t j = 0; j < 10; j++) { CheckCalculatePacketNumber(cur_epoch + j, last); @@ -3131,7 +3131,7 @@ CheckFramingBoundaries(packet99, QUIC_INVALID_ACK_DATA); } -// An ack block that acks the entire range, 0...0x3fffffffffffffff +// An ack block that acks the entire range, 1...0x3fffffffffffffff TEST_P(QuicFramerTest, AckBlockAcksEverything) { if (framer_.transport_version() != QUIC_VERSION_99) { // for now, only v99 @@ -3164,7 +3164,7 @@ // first ack block length. {"Unable to read first ack block length.", {kVarInt62EightBytes + 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff}}, + 0xff, 0xff, 0xff, 0xfe}}, }; // clang-format on @@ -3175,8 +3175,7 @@ const QuicAckFrame& frame = *visitor_.ack_frames_[0]; EXPECT_EQ(1u, frame.packets.NumIntervals()); EXPECT_EQ(kLargestIetfLargestObserved, LargestAcked(frame)); - // +1 because it's 0..Largest, inclusive. - EXPECT_EQ(kLargestIetfLargestObserved + 1, frame.packets.NumPacketsSlow()); + EXPECT_EQ(kLargestIetfLargestObserved, frame.packets.NumPacketsSlow()); } // This test looks for a malformed ack where @@ -8310,6 +8309,49 @@ data.length(), AsChars(p), packet_size); } +// Test that the IETF connectivity probing packet is serialized correctly as a +// padded PING packet, v99 only. +TEST_P(QuicFramerTest, BuildIetfConnectivityProbingPacket) { + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + QuicPacketHeader header; + header.destination_connection_id = FramerTestConnectionId(); + header.reset_flag = false; + header.version_flag = false; + header.packet_number = kPacketNumber; + + unsigned char packet99[] = {// type (short header, 4 byte packet number) + 0x43, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type + 0x07, + // frame type (padding frame) + 0x00, 0x00, 0x00, 0x00, 0x00}; + // clang-format on + + unsigned char* p = packet99; + size_t packet_size = QUIC_ARRAYSIZE(packet99); + + std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); + + size_t length = framer_.BuildIetfConnectivityProbingPacket( + header, buffer.get(), packet_size); + + EXPECT_NE(0u, length); + QuicPacket data(buffer.release(), length, true, + header.destination_connection_id_length, + header.source_connection_id_length, header.version_flag, + header.nonce != nullptr, header.packet_number_length); + + test::CompareCharArraysWithHexError("constructed packet", data.data(), + data.length(), AsChars(p), packet_size); +} + // Test that the path challenge connectivity probing packet is serialized // correctly as a padded PATH CHALLENGE packet. TEST_P(QuicFramerTest, BuildPaddedPathChallengePacket) { @@ -11160,6 +11202,366 @@ QUIC_ARRAYSIZE(packet99)); } +TEST_P(QuicFramerTest, AckFrameWithInvalidLargestObserved) { + // clang-format off + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x2C, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x78, 0x56, 0x34, 0x12, + + // frame type (ack frame) + 0x45, + // largest observed + 0x00, 0x00, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x00, 0x00, + // num timestamps. + 0x00 + }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x2C, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (ack frame) + 0x45, + // largest observed + 0x00, 0x00, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x00, 0x00, + // num timestamps. + 0x00 + }; + + unsigned char packet44[] = { + // type (short header, 4 byte packet number) + 0x32, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (ack frame) + 0x45, + // largest observed + 0x00, 0x00, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x00, 0x00, + // num timestamps. + 0x00 + }; + + unsigned char packet99[] = { + // type (short header, 4 byte packet number) + 0x32, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (ack frame) + 0x1a, + // Largest acked + kVarInt62OneByte + 0x00, + // Zero delta time. + kVarInt62OneByte + 0x00, + // Ack block count 0 + kVarInt62OneByte + 0x00, + // First ack block length + kVarInt62OneByte + 0x00, + }; + // clang-format on + + unsigned char* p = packet; + size_t p_size = QUIC_ARRAYSIZE(packet); + if (framer_.transport_version() == QUIC_VERSION_99) { + p = packet99; + p_size = QUIC_ARRAYSIZE(packet99); + } else if (framer_.transport_version() > QUIC_VERSION_43) { + p = packet44; + p_size = QUIC_ARRAYSIZE(packet44); + } else if (framer_.transport_version() != QUIC_VERSION_35) { + p = packet39; + } + + QuicEncryptedPacket encrypted(AsChars(p), p_size, false); + if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) && + framer_.transport_version() != QUIC_VERSION_99) { + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + return; + } + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + EXPECT_EQ(framer_.detailed_error(), "Largest acked is 0."); +} + +TEST_P(QuicFramerTest, FirstAckBlockJustUnderFlow) { + // clang-format off + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x2C, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x78, 0x56, 0x34, 0x12, + + // frame type (ack frame) + 0x45, + // largest observed + 0x02, 0x00, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x03, 0x00, + // num timestamps. + 0x00 + }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x2C, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (ack frame) + 0x45, + // largest observed + 0x00, 0x02, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x00, 0x03, + // num timestamps. + 0x00 + }; + + unsigned char packet44[] = { + // type (short header, 4 byte packet number) + 0x32, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (ack frame) + 0x45, + // largest observed + 0x00, 0x02, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x00, 0x03, + // num timestamps. + 0x00 + }; + + unsigned char packet99[] = { + // type (short header, 4 byte packet number) + 0x32, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (ack frame) + 0x1a, + // Largest acked + kVarInt62OneByte + 0x02, + // Zero delta time. + kVarInt62OneByte + 0x00, + // Ack block count 0 + kVarInt62OneByte + 0x00, + // First ack block length + kVarInt62OneByte + 0x02, + }; + // clang-format on + + unsigned char* p = packet; + size_t p_size = QUIC_ARRAYSIZE(packet); + if (framer_.transport_version() == QUIC_VERSION_99) { + p = packet99; + p_size = QUIC_ARRAYSIZE(packet99); + } else if (framer_.transport_version() > QUIC_VERSION_43) { + p = packet44; + p_size = QUIC_ARRAYSIZE(packet44); + } else if (framer_.transport_version() != QUIC_VERSION_35) { + p = packet39; + } + + QuicEncryptedPacket encrypted(AsChars(p), p_size, false); + if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) && + framer_.transport_version() != QUIC_VERSION_99) { + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + return; + } + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + EXPECT_EQ(framer_.detailed_error(), + "Underflow with first ack block length 3 largest acked is 2."); +} + +TEST_P(QuicFramerTest, ThirdAckBlockJustUnderflow) { + // clang-format off + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x2C, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x78, 0x56, 0x34, 0x12, + + // frame type (ack frame) + 0x60, + // largest observed + 0x0A, + // Zero delta time. + 0x00, 0x00, + // Num of ack blocks + 0x02, + // first ack block length. + 0x02, + // gap to next block + 0x01, + // ack block length + 0x01, + // gap to next block + 0x01, + // ack block length + 0x06, + // num timestamps. + 0x00 + }; + + unsigned char packet39[] = { + // public flags (8 byte connection_id) + 0x2C, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (ack frame) + 0x60, + // largest observed + 0x0A, + // Zero delta time. + 0x00, 0x00, + // Num of ack blocks + 0x02, + // first ack block length. + 0x02, + // gap to next block + 0x01, + // ack block length + 0x01, + // gap to next block + 0x01, + // ack block length + 0x06, + // num timestamps. + 0x00 + }; + + unsigned char packet44[] = { + // type (short header, 4 byte packet number) + 0x32, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (ack frame) + 0x60, + // largest observed + 0x0A, + // Zero delta time. + 0x00, 0x00, + // Num of ack blocks + 0x02, + // first ack block length. + 0x02, + // gap to next block + 0x01, + // ack block length + 0x01, + // gap to next block + 0x01, + // ack block length + 0x06, + // num timestamps. + 0x00 + }; + + unsigned char packet99[] = { + // type (short header, 4 byte packet number) + 0x32, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (ack frame) + 0x1a, + // Largest acked + kVarInt62OneByte + 0x0A, + // Zero delta time. + kVarInt62OneByte + 0x00, + // Ack block count 2 + kVarInt62OneByte + 0x02, + // First ack block length + kVarInt62OneByte + 0x01, + // gap to next block length + kVarInt62OneByte + 0x00, + // ack block length + kVarInt62OneByte + 0x00, + // gap to next block length + kVarInt62OneByte + 0x00, + // ack block length + kVarInt62OneByte + 0x05, + }; + // clang-format on + + unsigned char* p = packet; + size_t p_size = QUIC_ARRAYSIZE(packet); + if (framer_.transport_version() == QUIC_VERSION_99) { + p = packet99; + p_size = QUIC_ARRAYSIZE(packet99); + } else if (framer_.transport_version() > QUIC_VERSION_43) { + p = packet44; + p_size = QUIC_ARRAYSIZE(packet44); + } else if (framer_.transport_version() != QUIC_VERSION_35) { + p = packet39; + } + + QuicEncryptedPacket encrypted(AsChars(p), p_size, false); + if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) && + framer_.transport_version() != QUIC_VERSION_99) { + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + return; + } + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + if (framer_.transport_version() == QUIC_VERSION_99) { + EXPECT_EQ(framer_.detailed_error(), + "Underflow with ack block length 6 latest ack block end is 5."); + } else { + EXPECT_EQ(framer_.detailed_error(), + "Underflow with ack block length 6, end of block is 6."); + } +} + } // namespace } // namespace test } // namespace quic
diff --git a/net/third_party/quic/core/quic_packet_creator.cc b/net/third_party/quic/core/quic_packet_creator.cc index 25ba1b2..9fa7532 100644 --- a/net/third_party/quic/core/quic_packet_creator.cc +++ b/net/third_party/quic/core/quic_packet_creator.cc
@@ -52,7 +52,12 @@ connection_id_length_(PACKET_8BYTE_CONNECTION_ID), packet_size_(0), connection_id_(connection_id), - packet_(0, PACKET_1BYTE_PACKET_NUMBER, nullptr, 0, false, false), + packet_(kInvalidPacketNumber, + PACKET_1BYTE_PACKET_NUMBER, + nullptr, + 0, + false, + false), long_header_type_(HANDSHAKE), pending_padding_bytes_(0), needs_full_padding_(false), @@ -123,7 +128,7 @@ } DCHECK_LE(least_packet_awaited_by_peer, packet_.packet_number + 1); - const QuicPacketNumber current_delta = + const uint64_t current_delta = packet_.packet_number + 1 - least_packet_awaited_by_peer; const uint64_t delta = std::max(current_delta, max_packets_in_flight); packet_.packet_number_length = QuicFramer::GetMinPacketNumberLength( @@ -658,8 +663,8 @@ // TODO(b/74062209): Make this a public method of framer? SerializedPacket QuicPacketCreator::NoPacket() { - return SerializedPacket(0, PACKET_1BYTE_PACKET_NUMBER, nullptr, 0, false, - false); + return SerializedPacket(kInvalidPacketNumber, PACKET_1BYTE_PACKET_NUMBER, + nullptr, 0, false, false); } QuicConnectionIdLength QuicPacketCreator::GetDestinationConnectionIdLength() @@ -702,7 +707,12 @@ } else { header->nonce = nullptr; } - header->packet_number = ++packet_.packet_number; + if (packet_.packet_number == kInvalidPacketNumber) { + packet_.packet_number = kFirstSendingPacketNumber; + } else { + ++packet_.packet_number; + } + header->packet_number = packet_.packet_number; header->packet_number_length = GetPacketNumberLength(); if (!HasIetfLongHeader()) { return;
diff --git a/net/third_party/quic/core/quic_packet_creator_test.cc b/net/third_party/quic/core/quic_packet_creator_test.cc index 0a28595b..4694ebf 100644 --- a/net/third_party/quic/core/quic_packet_creator_test.cc +++ b/net/third_party/quic/core/quic_packet_creator_test.cc
@@ -268,7 +268,8 @@ for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) { EncryptionLevel level = static_cast<EncryptionLevel>(i); creator_.set_encryption_level(level); - frames_.push_back(QuicFrame(new QuicAckFrame())); + frames_.push_back( + QuicFrame(new QuicAckFrame(InitAckFrame(QuicPacketNumber(1))))); frames_.push_back(QuicFrame(QuicStreamFrame( QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), false, 0u, QuicStringPiece()))); @@ -289,21 +290,11 @@ EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); EXPECT_CALL(framer_visitor_, OnAckFrameStart(_, _)) .WillOnce(Return(true)); - // This test includes an ack frame with largest_acked == 0 and - // the size of the first ack-block == 1 (serialized as - // 0). This is an invalid format for pre-version99, valid - // for version 99. - if (client_framer_.transport_version() != QUIC_VERSION_99) { - // pre-version 99; ensure that the error is gracefully - // handled. - EXPECT_CALL(framer_visitor_, OnAckRange(1, 1)).WillOnce(Return(true)); - EXPECT_CALL(framer_visitor_, OnAckFrameEnd(1)).WillOnce(Return(true)); - } else { - // version 99; ensure that the correct packet is signalled - // properly. - EXPECT_CALL(framer_visitor_, OnAckRange(0, 1)).WillOnce(Return(true)); - EXPECT_CALL(framer_visitor_, OnAckFrameEnd(0)).WillOnce(Return(true)); - } + EXPECT_CALL(framer_visitor_, + OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2))) + .WillOnce(Return(true)); + EXPECT_CALL(framer_visitor_, OnAckFrameEnd(QuicPacketNumber(1))) + .WillOnce(Return(true)); EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); EXPECT_CALL(framer_visitor_, OnPacketComplete()); @@ -1562,7 +1553,7 @@ creator_.set_can_set_transmission_type(true); creator_.SetTransmissionType(NOT_RETRANSMISSION); - QuicAckFrame temp_ack_frame; + QuicAckFrame temp_ack_frame = InitAckFrame(1); QuicFrame ack_frame(&temp_ack_frame); ASSERT_FALSE(QuicUtils::IsRetransmittableFrame(ack_frame.type));
diff --git a/net/third_party/quic/core/quic_packet_generator.cc b/net/third_party/quic/core/quic_packet_generator.cc index 4e59b59..df7974a 100644 --- a/net/third_party/quic/core/quic_packet_generator.cc +++ b/net/third_party/quic/core/quic_packet_generator.cc
@@ -26,7 +26,8 @@ flusher_attached_(false), should_send_ack_(false), should_send_stop_waiting_(false), - random_generator_(random_generator) {} + random_generator_(random_generator), + fully_pad_crypto_handshake_packets_(true) {} QuicPacketGenerator::~QuicPacketGenerator() { DeleteFrames(&queued_control_frames_); @@ -93,10 +94,13 @@ HAS_RETRANSMITTABLE_DATA, has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) { QuicFrame frame; + bool needs_full_padding = + has_handshake && fully_pad_crypto_handshake_packets_; + if (!packet_creator_.ConsumeData(id, write_length, total_bytes_consumed, offset + total_bytes_consumed, fin, - has_handshake, next_transmission_type_, - &frame)) { + needs_full_padding, + next_transmission_type_, &frame)) { // The creator is always flushed if there's not enough room for a new // stream frame before ConsumeData, so ConsumeData should always succeed. QUIC_BUG << "Failed to ConsumeData, stream:" << id;
diff --git a/net/third_party/quic/core/quic_packet_generator.h b/net/third_party/quic/core/quic_packet_generator.h index 1ea66000..da9794b 100644 --- a/net/third_party/quic/core/quic_packet_generator.h +++ b/net/third_party/quic/core/quic_packet_generator.h
@@ -221,6 +221,14 @@ bool should_send_ack() const { return should_send_ack_; } + void set_fully_pad_crypto_hadshake_packets(bool new_value) { + fully_pad_crypto_handshake_packets_ = new_value; + } + + bool fully_pad_crypto_handshake_packets() const { + return fully_pad_crypto_handshake_packets_; + } + private: friend class test::QuicPacketGeneratorPeer; @@ -265,6 +273,9 @@ QuicStopWaitingFrame pending_stop_waiting_frame_; QuicRandom* random_generator_; + + // Whether crypto handshake packets should be fully padded. + bool fully_pad_crypto_handshake_packets_; }; } // namespace quic
diff --git a/net/third_party/quic/core/quic_packet_generator_test.cc b/net/third_party/quic/core/quic_packet_generator_test.cc index d63e844c..ab3b28728 100644 --- a/net/third_party/quic/core/quic_packet_generator_test.cc +++ b/net/third_party/quic/core/quic_packet_generator_test.cc
@@ -154,7 +154,8 @@ &random_generator_, &delegate_, &producer_), - creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)) { + creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)), + ack_frame_(InitAckFrame(QuicPacketNumber(1))) { EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr)); creator_->SetEncrypter( ENCRYPTION_FORWARD_SECURE, @@ -470,6 +471,35 @@ EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length); } +// Test the behavior of ConsumeData when the data is for the crypto handshake +// stream, but padding is disabled. +TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake_PaddingDisabled) { + generator_.set_fully_pad_crypto_hadshake_packets(false); + + delegate_.SetCanWriteAnything(); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); + MakeIOVector("foo", &iov_); + QuicConsumedData consumed = generator_.ConsumeData( + QuicUtils::GetCryptoStreamId(framer_.transport_version()), &iov_, 1u, + iov_.iov_len, 0, NO_FIN); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); + + PacketContents contents; + contents.num_stream_frames = 1; + contents.num_padding_frames = 0; + CheckPacketContains(contents, 0); + + ASSERT_EQ(1u, packets_.size()); + + // Packet is not fully padded, but we want to future packets to be larger. + ASSERT_EQ(kDefaultMaxPacketSize, generator_.GetCurrentMaxPacketLength()); + EXPECT_EQ(27, packets_[0].encrypted_length); +} + TEST_F(QuicPacketGeneratorTest, ConsumeData_EmptyData) { EXPECT_QUIC_BUG(generator_.ConsumeData(QuicUtils::GetHeadersStreamId( framer_.transport_version()),
diff --git a/net/third_party/quic/core/quic_sent_packet_manager_test.cc b/net/third_party/quic/core/quic_sent_packet_manager_test.cc index 57ff4afd..b3414f2 100644 --- a/net/third_party/quic/core/quic_sent_packet_manager_test.cc +++ b/net/third_party/quic/core/quic_sent_packet_manager_test.cc
@@ -54,7 +54,7 @@ class QuicSentPacketManagerTest : public QuicTestWithParam<bool> { public: - void RetransmitCryptoPacket(QuicPacketNumber packet_number) { + void RetransmitCryptoPacket(uint64_t packet_number) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength, HAS_RETRANSMITTABLE_DATA)); @@ -66,8 +66,7 @@ HAS_RETRANSMITTABLE_DATA); } - void RetransmitDataPacket(QuicPacketNumber packet_number, - TransmissionType type) { + void RetransmitDataPacket(uint64_t packet_number, TransmissionType type) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength, HAS_RETRANSMITTABLE_DATA)); @@ -139,7 +138,7 @@ } } - void ExpectAck(QuicPacketNumber largest_observed) { + void ExpectAck(uint64_t largest_observed) { EXPECT_CALL( *send_algorithm_, // Ensure the AckedPacketVector argument contains largest_observed. @@ -149,15 +148,15 @@ EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); } - void ExpectUpdatedRtt(QuicPacketNumber largest_observed) { + void ExpectUpdatedRtt(uint64_t largest_observed) { EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, IsEmpty(), IsEmpty())); EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); } void ExpectAckAndLoss(bool rtt_updated, - QuicPacketNumber largest_observed, - QuicPacketNumber lost_packet) { + uint64_t largest_observed, + uint64_t lost_packet) { EXPECT_CALL( *send_algorithm_, OnCongestionEvent(rtt_updated, _, _, @@ -188,14 +187,14 @@ .Times(AnyNumber()); } - void RetransmitAndSendPacket(QuicPacketNumber old_packet_number, - QuicPacketNumber new_packet_number) { + void RetransmitAndSendPacket(uint64_t old_packet_number, + uint64_t new_packet_number) { RetransmitAndSendPacket(old_packet_number, new_packet_number, TLP_RETRANSMISSION); } - void RetransmitAndSendPacket(QuicPacketNumber old_packet_number, - QuicPacketNumber new_packet_number, + void RetransmitAndSendPacket(uint64_t old_packet_number, + uint64_t new_packet_number, TransmissionType transmission_type) { bool is_lost = false; if (manager_.session_decides_what_to_write()) { @@ -243,12 +242,11 @@ new_packet_number)); } - SerializedPacket CreateDataPacket(QuicPacketNumber packet_number) { + SerializedPacket CreateDataPacket(uint64_t packet_number) { return CreatePacket(packet_number, true); } - SerializedPacket CreatePacket(QuicPacketNumber packet_number, - bool retransmittable) { + SerializedPacket CreatePacket(uint64_t packet_number, bool retransmittable) { SerializedPacket packet(packet_number, PACKET_4BYTE_PACKET_NUMBER, nullptr, kDefaultLength, false, false); if (retransmittable) { @@ -258,7 +256,7 @@ return packet; } - void SendDataPacket(QuicPacketNumber packet_number) { + void SendDataPacket(uint64_t packet_number) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), packet_number, _, _)); SerializedPacket packet(CreateDataPacket(packet_number)); @@ -266,7 +264,7 @@ HAS_RETRANSMITTABLE_DATA); } - void SendCryptoPacket(QuicPacketNumber packet_number) { + void SendCryptoPacket(uint64_t packet_number) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength, HAS_RETRANSMITTABLE_DATA)); @@ -282,8 +280,7 @@ } } - void SendAckPacket(QuicPacketNumber packet_number, - QuicPacketNumber largest_acked) { + void SendAckPacket(uint64_t packet_number, uint64_t largest_acked) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength, NO_RETRANSMITTABLE_DATA)); @@ -294,7 +291,7 @@ } // Based on QuicConnection's WritePendingRetransmissions. - void RetransmitNextPacket(QuicPacketNumber retransmission_packet_number) { + void RetransmitNextPacket(uint64_t retransmission_packet_number) { EXPECT_TRUE(manager_.HasPendingRetransmissions()); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, retransmission_packet_number, kDefaultLength,
diff --git a/net/third_party/quic/core/quic_stream.cc b/net/third_party/quic/core/quic_stream.cc index bafd8a4..f72b4d85 100644 --- a/net/third_party/quic/core/quic_stream.cc +++ b/net/third_party/quic/core/quic_stream.cc
@@ -293,12 +293,15 @@ (kMaxStreamLength - frame.offset < frame.data_length); if (is_stream_too_long) { // Close connection if stream becomes too long. - QUIC_PEER_BUG - << "Receive stream frame reaches max stream length. frame offset " - << frame.offset << " length " << frame.data_length; + QUIC_PEER_BUG << "Receive stream frame on stream " << id_ + << " reaches max stream length. frame offset " << frame.offset + << " length " << frame.data_length << ". " + << sequencer_.DebugString(); CloseConnectionWithDetails( QUIC_STREAM_LENGTH_OVERFLOW, - "Peer sends more data than allowed on this stream."); + QuicStrCat("Peer sends more data than allowed on stream ", id_, + ". frame: offset = ", frame.offset, ", length = ", + frame.data_length, ". ", sequencer_.DebugString())); return; } if (frame.fin) {
diff --git a/net/third_party/quic/core/quic_stream.h b/net/third_party/quic/core/quic_stream.h index 60ef393..5dee6de 100644 --- a/net/third_party/quic/core/quic_stream.h +++ b/net/third_party/quic/core/quic_stream.h
@@ -33,7 +33,7 @@ #include "net/third_party/quic/platform/api/quic_reference_counted.h" #include "net/third_party/quic/platform/api/quic_string.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" namespace quic {
diff --git a/net/third_party/quic/core/quic_stream_sequencer_buffer.cc b/net/third_party/quic/core/quic_stream_sequencer_buffer.cc index 20083145..a9f5f897 100644 --- a/net/third_party/quic/core/quic_stream_sequencer_buffer.cc +++ b/net/third_party/quic/core/quic_stream_sequencer_buffer.cc
@@ -93,7 +93,7 @@ // Extend the right edge of last interval. // TODO(fayang): Encapsulate this into a future version of QuicIntervalSet // if this is more efficient than Add. - const_cast<QuicInterval<QuicPacketNumber>*>(&(*bytes_received_.rbegin())) + const_cast<QuicInterval<QuicStreamOffset>*>(&(*bytes_received_.rbegin())) ->SetMax(starting_offset + size); } else { bytes_received_.Add(starting_offset, starting_offset + size);
diff --git a/net/third_party/quic/core/quic_stream_test.cc b/net/third_party/quic/core/quic_stream_test.cc index b086db2..01c452ee 100644 --- a/net/third_party/quic/core/quic_stream_test.cc +++ b/net/third_party/quic/core/quic_stream_test.cc
@@ -687,7 +687,8 @@ QuicStreamFrame stream_frame(stream_->id(), false, kMaxStreamLength, QuicStringPiece(".")); EXPECT_QUIC_PEER_BUG(stream_->OnStreamFrame(stream_frame), - "Receive stream frame reaches max stream length"); + QuicStrCat("Receive stream frame on stream ", + stream_->id(), " reaches max stream length")); } TEST_P(QuicParameterizedStreamTest, SetDrainingIncomingOutgoing) {
diff --git a/net/third_party/quic/core/quic_unacked_packet_map.cc b/net/third_party/quic/core/quic_unacked_packet_map.cc index 0224340..7c46bfac0 100644 --- a/net/third_party/quic/core/quic_unacked_packet_map.cc +++ b/net/third_party/quic/core/quic_unacked_packet_map.cc
@@ -29,7 +29,7 @@ largest_sent_retransmittable_packet_(0), largest_sent_largest_acked_(0), largest_acked_(0), - least_unacked_(1), + least_unacked_(kFirstSendingPacketNumber), bytes_in_flight_(0), pending_crypto_packet_count_(0), last_crypto_packet_sent_time_(QuicTime::Zero()),
diff --git a/net/third_party/quic/core/quic_unacked_packet_map_test.cc b/net/third_party/quic/core/quic_unacked_packet_map_test.cc index de6854d..b33b065 100644 --- a/net/third_party/quic/core/quic_unacked_packet_map_test.cc +++ b/net/third_party/quic/core/quic_unacked_packet_map_test.cc
@@ -134,8 +134,8 @@ unacked_packets_.GetMutableTransmissionInfo(packet_number)->state = state; } - void RetransmitAndSendPacket(QuicPacketNumber old_packet_number, - QuicPacketNumber new_packet_number, + void RetransmitAndSendPacket(uint64_t old_packet_number, + uint64_t new_packet_number, TransmissionType transmission_type) { DCHECK(unacked_packets_.HasRetransmittableFrames(old_packet_number)); if (!unacked_packets_.session_decides_what_to_write()) {
diff --git a/net/third_party/quic/core/quic_write_blocked_list.h b/net/third_party/quic/core/quic_write_blocked_list.h index 3588b60f..c4e73d5 100644 --- a/net/third_party/quic/core/quic_write_blocked_list.h +++ b/net/third_party/quic/core/quic_write_blocked_list.h
@@ -13,7 +13,7 @@ #include "net/third_party/quic/platform/api/quic_containers.h" #include "net/third_party/quic/platform/api/quic_export.h" #include "net/third_party/quic/platform/api/quic_map_util.h" -#include "net/third_party/spdy/core/priority_write_scheduler.h" +#include "net/third_party/quiche/src/spdy/core/priority_write_scheduler.h" namespace quic {
diff --git a/net/third_party/quic/platform/api/quic_cert_utils.h b/net/third_party/quic/platform/api/quic_cert_utils.h new file mode 100644 index 0000000..be4b4f4 --- /dev/null +++ b/net/third_party/quic/platform/api/quic_cert_utils.h
@@ -0,0 +1,23 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file._ + +#ifndef NET_THIRD_PARTY_QUIC_PLATFORM_API_QUIC_CERT_UTILS_H_ +#define NET_THIRD_PARTY_QUIC_PLATFORM_API_QUIC_CERT_UTILS_H_ + +#include "net/third_party/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quic/platform/impl/quic_cert_utils_impl.h" + +namespace quic { + +class QuicCertUtils { + public: + static bool ExtractSubjectNameFromDERCert(QuicStringPiece cert, + QuicStringPiece* subject_out) { + return QuicCertUtilsImpl::ExtractSubjectNameFromDERCert(cert, subject_out); + } +}; + +} // namespace quic + +#endif // NET_THIRD_PARTY_QUIC_PLATFORM_API_QUIC_CERT_UTILS_H_
diff --git a/net/third_party/quic/platform/impl/quic_cert_utils_impl.h b/net/third_party/quic/platform/impl/quic_cert_utils_impl.h new file mode 100644 index 0000000..3ccfd77 --- /dev/null +++ b/net/third_party/quic/platform/impl/quic_cert_utils_impl.h
@@ -0,0 +1,23 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file._ + +#ifndef NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_CERT_UTILS_IMPL_H_ +#define NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_CERT_UTILS_IMPL_H_ + +#include "net/cert/asn1_util.h" +#include "net/third_party/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QuicCertUtilsImpl { + public: + static bool ExtractSubjectNameFromDERCert(QuicStringPiece cert, + QuicStringPiece* subject_out) { + return net::asn1::ExtractSubjectFromDERCert(cert, subject_out); + } +}; + +} // namespace quic + +#endif // NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_CERT_UTILS_IMPL_H_
diff --git a/net/third_party/quic/quartc/quartc_session.cc b/net/third_party/quic/quartc/quartc_session.cc index 65b58f5..ff5cff0 100644 --- a/net/third_party/quic/quartc/quartc_session.cc +++ b/net/third_party/quic/quartc/quartc_session.cc
@@ -142,6 +142,8 @@ std::unique_ptr<ProofVerifier> proof_verifier(new InsecureProofVerifier); quic_crypto_client_config_ = QuicMakeUnique<QuicCryptoClientConfig>( std::move(proof_verifier), TlsClientHandshaker::CreateSslCtx()); + quic_crypto_client_config_->set_pad_inchoate_hello(false); + quic_crypto_client_config_->set_pad_full_hello(false); } else { std::unique_ptr<ProofSource> proof_source(new DummyProofSource); // Generate a random source address token secret. For long-running servers @@ -154,6 +156,29 @@ QuicString(source_address_token_secret, kInputKeyingMaterialLength), helper_->GetRandomGenerator(), std::move(proof_source), KeyExchangeSource::Default(), TlsServerHandshaker::CreateSslCtx()); + + // Effectively disables the anti-amplification measures (we don't need + // them because we use ICE, and we need to disable them because we disable + // padding of crypto packets). + // This multiplier must be large enough so that the crypto handshake packet + // (approx. 300 bytes) multiplied by this multiplier is larger than a fully + // sized packet (currently 1200 bytes). + // 1500 is a bit extreme: if you can imagine sending a 1 byte packet, and + // your largest MTU would be below 1500 bytes, 1500*1 >= + // any_packet_that_you_can_imagine_sending. + // (again, we hardcode packet size to 1200, so we are not dealing with jumbo + // frames). + quic_crypto_server_config_->set_chlo_multiplier(1500); + + // We are sending small client hello, we must not validate its size. + quic_crypto_server_config_->set_validate_chlo_size(false); + + // We run QUIC over ICE, and ICE is verifying remote side with STUN pings. + // We disable source address token validation in order to allow for 0-rtt + // setup (plus source ip addresses are changing even during the connection + // when ICE is used). + quic_crypto_server_config_->set_validate_source_address_token(false); + // Provide server with serialized config string to prove ownership. QuicCryptoServerConfig::ConfigOptions options; // The |message| is used to handle the return value of AddDefaultConfig @@ -161,6 +186,8 @@ std::unique_ptr<CryptoHandshakeMessage> message( quic_crypto_server_config_->AddDefaultConfig( helper_->GetRandomGenerator(), helper_->GetClock(), options)); + quic_crypto_server_config_->set_pad_rej(false); + quic_crypto_server_config_->set_pad_shlo(false); } } @@ -257,12 +284,25 @@ void QuartcSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { QuicSession::OnCryptoHandshakeEvent(event); - if (event == HANDSHAKE_CONFIRMED) { - DCHECK(IsEncryptionEstablished()); - DCHECK(IsCryptoHandshakeConfirmed()); + switch (event) { + case ENCRYPTION_FIRST_ESTABLISHED: + case ENCRYPTION_REESTABLISHED: + // 1-rtt setup triggers 'ENCRYPTION_REESTABLISHED' (after REJ, when the + // CHLO is sent). + DCHECK(IsEncryptionEstablished()); + DCHECK(session_delegate_); + session_delegate_->OnConnectionWritable(); + break; + case HANDSHAKE_CONFIRMED: + // On the server, handshake confirmed is the first time when you can start + // writing packets. + DCHECK(IsEncryptionEstablished()); + DCHECK(IsCryptoHandshakeConfirmed()); - DCHECK(session_delegate_); - session_delegate_->OnCryptoHandshakeComplete(); + DCHECK(session_delegate_); + session_delegate_->OnConnectionWritable(); + session_delegate_->OnCryptoHandshakeComplete(); + break; } }
diff --git a/net/third_party/quic/quartc/quartc_session.h b/net/third_party/quic/quartc/quartc_session.h index 1bb4faca..fa6d2ec 100644 --- a/net/third_party/quic/quartc/quartc_session.h +++ b/net/third_party/quic/quartc/quartc_session.h
@@ -126,9 +126,18 @@ public: virtual ~Delegate() {} - // Called when the crypto handshake is complete. + // Called when the crypto handshake is complete. Crypto handshake on the + // client is only completed _after_ SHLO is received, but we can actually + // start sending media data right after CHLO is sent. virtual void OnCryptoHandshakeComplete() = 0; + // Connection can be writable even before crypto handshake is complete. + // In particular, on the client, we can start sending data after sending + // full CHLO, without waiting for SHLO. This reduces a send delay by 1-rtt. + // + // This may be called multiple times. + virtual void OnConnectionWritable() = 0; + // Called when a new stream is received from the remote endpoint. virtual void OnIncomingStream(QuartcStream* stream) = 0;
diff --git a/net/third_party/quic/quartc/quartc_session_test.cc b/net/third_party/quic/quartc/quartc_session_test.cc index 6215052b..8e298f2 100644 --- a/net/third_party/quic/quartc/quartc_session_test.cc +++ b/net/third_party/quic/quartc/quartc_session_test.cc
@@ -5,11 +5,11 @@ #include "net/third_party/quic/quartc/quartc_session.h" #include "build/build_config.h" -#include "net/third_party/quic/core/proto/crypto_server_config.pb.h" #include "net/third_party/quic/core/quic_simple_buffer_allocator.h" #include "net/third_party/quic/core/quic_types.h" #include "net/third_party/quic/core/tls_client_handshaker.h" #include "net/third_party/quic/core/tls_server_handshaker.h" +#include "net/third_party/quic/platform/api/quic_clock.h" #include "net/third_party/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quic/platform/api/quic_string_utils.h" #include "net/third_party/quic/platform/api/quic_test.h" @@ -35,18 +35,30 @@ class FakeQuartcSessionDelegate : public QuartcSession::Delegate { public: - explicit FakeQuartcSessionDelegate(QuartcStream::Delegate* stream_delegate) - : stream_delegate_(stream_delegate) {} + explicit FakeQuartcSessionDelegate(QuartcStream::Delegate* stream_delegate, + const QuicClock* clock) + : stream_delegate_(stream_delegate), clock_(clock) {} + + void OnConnectionWritable() override { + LOG(INFO) << "Connection writable!"; + if (!writable_time_.IsInitialized()) { + writable_time_ = clock_->Now(); + } + } + // Called when peers have established forward-secure encryption void OnCryptoHandshakeComplete() override { LOG(INFO) << "Crypto handshake complete!"; + crypto_handshake_time_ = clock_->Now(); } + // Called when connection closes locally, or remotely by peer. void OnConnectionClosed(QuicErrorCode error_code, const QuicString& error_details, ConnectionCloseSource source) override { connected_ = false; } + // Called when an incoming QUIC stream is created. void OnIncomingStream(QuartcStream* quartc_stream) override { last_incoming_stream_ = quartc_stream; @@ -69,12 +81,17 @@ } bool connected() { return connected_; } + QuicTime writable_time() const { return writable_time_; } + QuicTime crypto_handshake_time() const { return crypto_handshake_time_; } private: QuartcStream* last_incoming_stream_; std::vector<QuicString> incoming_messages_; bool connected_ = true; QuartcStream::Delegate* stream_delegate_; + QuicTime writable_time_ = QuicTime::Zero(); + QuicTime crypto_handshake_time_ = QuicTime::Zero(); + const QuicClock* clock_; }; class FakeQuartcStreamDelegate : public QuartcStream::Delegate { @@ -132,11 +149,11 @@ client_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>(); client_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>( - client_stream_delegate_.get()); + client_stream_delegate_.get(), simulator_.GetClock()); server_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>(); server_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>( - server_stream_delegate_.get()); + server_stream_delegate_.get(), simulator_.GetClock()); QuartcFactoryConfig factory_config; factory_config.alarm_factory = simulator_.GetAlarmFactory(); @@ -362,6 +379,29 @@ TestSendLongMessage(); } +TEST_F(QuartcSessionTest, TestCryptoHandshakeCanWriteTriggers) { + CreateClientAndServerSessions(QuartcSessionConfig()); + + StartHandshake(); + + RunTasks(); + + ASSERT_TRUE(client_session_delegate_->writable_time().IsInitialized()); + ASSERT_TRUE( + client_session_delegate_->crypto_handshake_time().IsInitialized()); + // On client, we are writable 1-rtt before crypto handshake is complete. + ASSERT_LT(client_session_delegate_->writable_time(), + client_session_delegate_->crypto_handshake_time()); + + ASSERT_TRUE(server_session_delegate_->writable_time().IsInitialized()); + ASSERT_TRUE( + server_session_delegate_->crypto_handshake_time().IsInitialized()); + // On server, the writable time and crypto handshake are the same. (when SHLO + // is sent). + ASSERT_EQ(server_session_delegate_->writable_time(), + server_session_delegate_->crypto_handshake_time()); +} + TEST_F(QuartcSessionTest, PreSharedKeyHandshake) { CreateClientAndServerSessions(QuartcSessionConfig()); client_peer_->SetPreSharedKey("foo");
diff --git a/net/third_party/quic/quartc/quartc_stream_test.cc b/net/third_party/quic/quartc/quartc_stream_test.cc index 846bd98..f75fdb0 100644 --- a/net/third_party/quic/quartc/quartc_stream_test.cc +++ b/net/third_party/quic/quartc/quartc_stream_test.cc
@@ -36,7 +36,7 @@ #include "net/third_party/quic/quartc/quartc_factory.h" #include "net/third_party/quic/test_tools/mock_clock.h" #include "net/third_party/quic/test_tools/quic_test_utils.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -225,7 +225,7 @@ alarm_factory_ = QuicMakeUnique<test::MockAlarmFactory>(); connection_ = QuicMakeUnique<QuicConnection>( - EmptyQuicConnectionId(), QuicSocketAddress(ip, 0), + test::TestConnectionId(0), QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/, alarm_factory_.get(), new DummyPacketWriter(), owns_writer, perspective, ParsedVersionOfIndex(CurrentSupportedVersions(), 0));
diff --git a/net/third_party/quic/test_tools/quic_framer_peer.cc b/net/third_party/quic/test_tools/quic_framer_peer.cc index 74f4a62..fb3d8bc 100644 --- a/net/third_party/quic/test_tools/quic_framer_peer.cc +++ b/net/third_party/quic/test_tools/quic_framer_peer.cc
@@ -13,11 +13,11 @@ namespace test { // static -QuicPacketNumber QuicFramerPeer::CalculatePacketNumberFromWire( +uint64_t QuicFramerPeer::CalculatePacketNumberFromWire( QuicFramer* framer, QuicPacketNumberLength packet_number_length, QuicPacketNumber last_packet_number, - QuicPacketNumber packet_number) { + uint64_t packet_number) { return framer->CalculatePacketNumberFromWire( packet_number_length, last_packet_number, packet_number); }
diff --git a/net/third_party/quic/test_tools/quic_framer_peer.h b/net/third_party/quic/test_tools/quic_framer_peer.h index 13decf55..5812bff7 100644 --- a/net/third_party/quic/test_tools/quic_framer_peer.h +++ b/net/third_party/quic/test_tools/quic_framer_peer.h
@@ -18,11 +18,11 @@ public: QuicFramerPeer() = delete; - static QuicPacketNumber CalculatePacketNumberFromWire( + static uint64_t CalculatePacketNumberFromWire( QuicFramer* framer, QuicPacketNumberLength packet_number_length, QuicPacketNumber last_packet_number, - QuicPacketNumber packet_number); + uint64_t packet_number); static void SetLastSerializedConnectionId(QuicFramer* framer, QuicConnectionId connection_id); static void SetLargestPacketNumber(QuicFramer* framer,
diff --git a/net/third_party/quic/test_tools/quic_spdy_session_peer.h b/net/third_party/quic/test_tools/quic_spdy_session_peer.h index 345fa33c..8f659d8 100644 --- a/net/third_party/quic/test_tools/quic_spdy_session_peer.h +++ b/net/third_party/quic/test_tools/quic_spdy_session_peer.h
@@ -8,7 +8,7 @@ #include "base/macros.h" #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/core/quic_write_blocked_list.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" namespace quic {
diff --git a/net/third_party/quic/test_tools/quic_test_utils.cc b/net/third_party/quic/test_tools/quic_test_utils.cc index a083396..47e3108 100644 --- a/net/third_party/quic/test_tools/quic_test_utils.cc +++ b/net/third_party/quic/test_tools/quic_test_utils.cc
@@ -25,7 +25,7 @@ #include "net/third_party/quic/test_tools/crypto_test_utils.h" #include "net/third_party/quic/test_tools/quic_config_peer.h" #include "net/third_party/quic/test_tools/quic_connection_peer.h" -#include "net/third_party/spdy/core/spdy_frame_builder.h" +#include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h" #include "third_party/boringssl/src/include/openssl/sha.h" using testing::_; @@ -79,12 +79,12 @@ return ack; } -QuicAckFrame InitAckFrame(QuicPacketNumber largest_acked) { +QuicAckFrame InitAckFrame(uint64_t largest_acked) { return InitAckFrame({{1, largest_acked + 1}}); } QuicAckFrame MakeAckFrameWithAckBlocks(size_t num_ack_blocks, - QuicPacketNumber least_unacked) { + uint64_t least_unacked) { QuicAckFrame ack; ack.largest_acked = 2 * num_ack_blocks + least_unacked; // Add enough received packets to get num_ack_blocks ack blocks. @@ -786,7 +786,7 @@ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag, - QuicPacketNumber packet_number, + uint64_t packet_number, const QuicString& data) { return ConstructEncryptedPacket( destination_connection_id, source_connection_id, version_flag, reset_flag, @@ -799,7 +799,7 @@ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag, - QuicPacketNumber packet_number, + uint64_t packet_number, const QuicString& data, QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length, @@ -815,7 +815,7 @@ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag, - QuicPacketNumber packet_number, + uint64_t packet_number, const QuicString& data, QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length, @@ -832,7 +832,7 @@ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag, - QuicPacketNumber packet_number, + uint64_t packet_number, const QuicString& data, QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length, @@ -884,7 +884,7 @@ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag, - QuicPacketNumber packet_number, + uint64_t packet_number, const QuicString& data, QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length,
diff --git a/net/third_party/quic/test_tools/quic_test_utils.h b/net/third_party/quic/test_tools/quic_test_utils.h index 7f8aefe..b9940d60 100644 --- a/net/third_party/quic/test_tools/quic_test_utils.h +++ b/net/third_party/quic/test_tools/quic_test_utils.h
@@ -78,7 +78,7 @@ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag, - QuicPacketNumber packet_number, + uint64_t packet_number, const QuicString& data, QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length, @@ -95,7 +95,7 @@ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag, - QuicPacketNumber packet_number, + uint64_t packet_number, const QuicString& data, QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length, @@ -108,7 +108,7 @@ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag, - QuicPacketNumber packet_number, + uint64_t packet_number, const QuicString& data, QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length, @@ -122,7 +122,7 @@ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag, - QuicPacketNumber packet_number, + uint64_t packet_number, const QuicString& data); // Constructs a received packet for testing. The caller must take ownership of @@ -141,7 +141,7 @@ QuicConnectionId source_connection_id, bool version_flag, bool reset_flag, - QuicPacketNumber packet_number, + uint64_t packet_number, const QuicString& data, QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length, @@ -201,7 +201,7 @@ // Testing convenience method to construct a QuicAckFrame with |num_ack_blocks| // ack blocks of width 1 packet, starting from |least_unacked| + 2. QuicAckFrame MakeAckFrameWithAckBlocks(size_t num_ack_blocks, - QuicPacketNumber least_unacked); + uint64_t least_unacked); // Returns a QuicPacket that is owned by the caller, and // is populated with the fields in |header| and |frames|, or is nullptr if the
diff --git a/net/third_party/quic/tools/quic_client_bin.cc b/net/third_party/quic/tools/quic_client_bin.cc index 297a1e9..2da7b9d 100644 --- a/net/third_party/quic/tools/quic_client_bin.cc +++ b/net/third_party/quic/tools/quic_client_bin.cc
@@ -62,7 +62,7 @@ #include "net/third_party/quic/platform/api/quic_text_utils.h" #include "net/third_party/quic/tools/quic_client.h" #include "net/third_party/quic/tools/quic_url.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/tools/epoll_server/epoll_server.h" #include "net/tools/quic/synchronous_host_resolver.h"
diff --git a/net/third_party/quic/tools/quic_memory_cache_backend.h b/net/third_party/quic/tools/quic_memory_cache_backend.h index e17fb5b3..b584f4bb 100644 --- a/net/third_party/quic/tools/quic_memory_cache_backend.h +++ b/net/third_party/quic/tools/quic_memory_cache_backend.h
@@ -17,7 +17,7 @@ #include "net/third_party/quic/tools/quic_backend_response.h" #include "net/third_party/quic/tools/quic_simple_server_backend.h" #include "net/third_party/quic/tools/quic_url.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" namespace quic {
diff --git a/net/third_party/quic/tools/quic_simple_server_stream.cc b/net/third_party/quic/tools/quic_simple_server_stream.cc index 0df95b7..6cc752a 100644 --- a/net/third_party/quic/tools/quic_simple_server_stream.cc +++ b/net/third_party/quic/tools/quic_simple_server_stream.cc
@@ -16,7 +16,7 @@ #include "net/third_party/quic/platform/api/quic_map_util.h" #include "net/third_party/quic/platform/api/quic_text_utils.h" #include "net/third_party/quic/tools/quic_simple_server_session.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" using spdy::SpdyHeaderBlock;
diff --git a/net/third_party/quic/tools/quic_simple_server_stream.h b/net/third_party/quic/tools/quic_simple_server_stream.h index f3380f16..328f249 100644 --- a/net/third_party/quic/tools/quic_simple_server_stream.h +++ b/net/third_party/quic/tools/quic_simple_server_stream.h
@@ -11,7 +11,7 @@ #include "net/third_party/quic/platform/api/quic_string_piece.h" #include "net/third_party/quic/tools/quic_backend_response.h" #include "net/third_party/quic/tools/quic_simple_server_backend.h" -#include "net/third_party/spdy/core/spdy_framer.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" namespace quic {
diff --git a/net/third_party/spdy/PRESUBMIT.py b/net/third_party/spdy/PRESUBMIT.py deleted file mode 100644 index 09ab19bf..0000000 --- a/net/third_party/spdy/PRESUBMIT.py +++ /dev/null
@@ -1,71 +0,0 @@ -# Copyright 2017 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import re - -def CheckForbiddenRegex(change, forbidden_regex, message_type, message): - problems = [] - for path, change_per_file in change: - line_num = 1 - for line in change_per_file: - if forbidden_regex.match(line): - problems.extend([" %s:%d" % (path, line_num)]) - line_num += 1 - if not problems: - return [] - return [message_type(message + ":\n" + "\n".join(problems))] - - -def CheckChange(input_api, message_type): - result = [] - shared_source_files = re.compile("^net/third_party/spdy/(core|platform/api)/.*\.(h|cc)$") - change = [(affected_file.LocalPath(), affected_file.NewContents()) - for affected_file in input_api.AffectedTestableFiles() - if shared_source_files.match(affected_file.LocalPath())] - forbidden_regex_list = [ - r"^#include \"net/base/net_export.h\"$", - r"\bNET_EXPORT\b", - r"\bNET_EXPORT_PRIVATE\b", - "^#include <string>$", - r"\bstd::string\b", - r"^#include \"base/strings/string_piece.h\"$", - r"^#include \"net/base/hex_utils.h\"$", - r"\bbase::StringPiece\b", - r"\bbase::StringPrintf\b", - r"\bbase::StringAppendF\b", - r"\bbase::HexDigitToInt\b", - r"\bHexDecode\b", - r"\bHexDump\b", - ] - messages = [ - "Include \"net/third_party/spdy/platform/api/spdy_export.h\" " - "instead of \"net/base/net_export.h\"", - "Use SPDY_EXPORT instead of NET_EXPORT", - "Use SPDY_EXPORT_PRIVATE instead of NET_EXPORT_PRIVATE", - "Include \"net/third_party/spdy/platform/api/spdy_string.h\" instead of <string>", - "Use SpdyString instead of std::string", - "Include \"net/third_party/spdy/platform/api/spdy_string_piece.h\" " - "instead of \"base/strings/string_piece.h\"", - "Include \"net/third_party/spdy/platform/api/spdy_string_utils.h\" " - "instead of \"net/base/hex_utils.h\"", - "Use SpdyStringPiece instead of base::StringPiece", - "Use SpdyStrCat instead of base::StringPrintf", - "Use SpdyStrCat instead of base::StringAppendF", - "Use SpdyHexDigitToInt instead of base::HexDigitToInt", - "Use SpdyHexDecode instead of HexDecode", - "Use SpdyHexDump instead of HexDump", - ] - for forbidden_regex, message in zip(forbidden_regex_list, messages): - result.extend(CheckForbiddenRegex( - change, re.compile(forbidden_regex), message_type, message)) - return result - -# Warn before uploading but allow developer to skip warning -# so that CLs can be shared and reviewed before addressing all issues. -def CheckChangeOnUpload(input_api, output_api): - return CheckChange(input_api, output_api.PresubmitPromptWarning) - -# Do not allow code with forbidden patterns to be checked in. -def CheckChangeOnCommit(input_api, output_api): - return CheckChange(input_api, output_api.PresubmitError)
diff --git a/net/third_party/spdy/core/array_output_buffer.cc b/net/third_party/spdy/core/array_output_buffer.cc deleted file mode 100644 index 21f9f23c..0000000 --- a/net/third_party/spdy/core/array_output_buffer.cc +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/array_output_buffer.h" - -namespace spdy { - -void ArrayOutputBuffer::Next(char** data, int* size) { - *data = current_; - *size = capacity_ > 0 ? capacity_ : 0; -} - -void ArrayOutputBuffer::AdvanceWritePtr(int64_t count) { - current_ += count; - capacity_ -= count; -} - -uint64_t ArrayOutputBuffer::BytesFree() const { - return capacity_; -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/array_output_buffer.h b/net/third_party/spdy/core/array_output_buffer.h deleted file mode 100644 index 206a2813..0000000 --- a/net/third_party/spdy/core/array_output_buffer.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_ARRAY_OUTPUT_BUFFER_H_ -#define NET_THIRD_PARTY_SPDY_CORE_ARRAY_OUTPUT_BUFFER_H_ - -#include <cstddef> -#include "net/third_party/spdy/core/zero_copy_output_buffer.h" - -namespace spdy { - -class ArrayOutputBuffer : public ZeroCopyOutputBuffer { - public: - // |buffer| is pointed to the output to write to, and |size| is the capacity - // of the output. - ArrayOutputBuffer(char* buffer, int64_t size) - : current_(buffer), begin_(buffer), capacity_(size) {} - ~ArrayOutputBuffer() override {} - - ArrayOutputBuffer(const ArrayOutputBuffer&) = delete; - ArrayOutputBuffer& operator=(const ArrayOutputBuffer&) = delete; - - void Next(char** data, int* size) override; - void AdvanceWritePtr(int64_t count) override; - uint64_t BytesFree() const override; - - size_t Size() const { return current_ - begin_; } - char* Begin() const { return begin_; } - - // Resets the buffer to its original state. - void Reset() { - capacity_ += Size(); - current_ = begin_; - } - - private: - char* current_ = nullptr; - char* begin_ = nullptr; - uint64_t capacity_ = 0; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_ARRAY_OUTPUT_BUFFER_H_
diff --git a/net/third_party/spdy/core/array_output_buffer_test.cc b/net/third_party/spdy/core/array_output_buffer_test.cc deleted file mode 100644 index f314d158..0000000 --- a/net/third_party/spdy/core/array_output_buffer_test.cc +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/array_output_buffer.h" - -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { -namespace test { - -// This test verifies that ArrayOutputBuffer is initialized properly. -TEST(ArrayOutputBufferTest, InitializedFromArray) { - char array[100]; - ArrayOutputBuffer buffer(array, sizeof(array)); - EXPECT_EQ(sizeof(array), buffer.BytesFree()); - EXPECT_EQ(0u, buffer.Size()); - EXPECT_EQ(array, buffer.Begin()); -} - -// This test verifies that Reset() causes an ArrayOutputBuffer's capacity and -// size to be reset to the initial state. -TEST(ArrayOutputBufferTest, WriteAndReset) { - char array[100]; - ArrayOutputBuffer buffer(array, sizeof(array)); - - // Let's write some bytes. - char* dst; - int size; - buffer.Next(&dst, &size); - ASSERT_GT(size, 1); - ASSERT_NE(nullptr, dst); - const int64_t written = size / 2; - memset(dst, 'x', written); - buffer.AdvanceWritePtr(written); - - // The buffer should be partially used. - EXPECT_EQ(static_cast<uint64_t>(size) - written, buffer.BytesFree()); - EXPECT_EQ(static_cast<uint64_t>(written), buffer.Size()); - - buffer.Reset(); - - // After a reset, the buffer should regain its full capacity. - EXPECT_EQ(sizeof(array), buffer.BytesFree()); - EXPECT_EQ(0u, buffer.Size()); -} - -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_constants.cc b/net/third_party/spdy/core/hpack/hpack_constants.cc deleted file mode 100644 index 61c8b34..0000000 --- a/net/third_party/spdy/core/hpack/hpack_constants.cc +++ /dev/null
@@ -1,386 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_constants.h" - -#include <cstddef> -#include <memory> -#include <vector> - -#include "base/logging.h" -#include "net/third_party/spdy/core/hpack/hpack_huffman_table.h" -#include "net/third_party/spdy/core/hpack/hpack_static_table.h" -#include "net/third_party/spdy/platform/api/spdy_arraysize.h" - -namespace spdy { - -// Produced by applying the python program [1] with tables provided by [2] -// (inserted into the source of the python program) and copy-paste them into -// this file. -// -// [1] net/tools/build_hpack_constants.py in Chromium -// [2] http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08 - -// HpackHuffmanSymbol entries are initialized as {code, length, id}. -// Codes are specified in the |length| most-significant bits of |code|. -const std::vector<HpackHuffmanSymbol>& HpackHuffmanCodeVector() { - static const auto* kHpackHuffmanCode = new std::vector<HpackHuffmanSymbol>{ - {0xffc00000ul, 13, 0}, // 11111111|11000 - {0xffffb000ul, 23, 1}, // 11111111|11111111|1011000 - {0xfffffe20ul, 28, 2}, // 11111111|11111111|11111110|0010 - {0xfffffe30ul, 28, 3}, // 11111111|11111111|11111110|0011 - {0xfffffe40ul, 28, 4}, // 11111111|11111111|11111110|0100 - {0xfffffe50ul, 28, 5}, // 11111111|11111111|11111110|0101 - {0xfffffe60ul, 28, 6}, // 11111111|11111111|11111110|0110 - {0xfffffe70ul, 28, 7}, // 11111111|11111111|11111110|0111 - {0xfffffe80ul, 28, 8}, // 11111111|11111111|11111110|1000 - {0xffffea00ul, 24, 9}, // 11111111|11111111|11101010 - {0xfffffff0ul, 30, 10}, // 11111111|11111111|11111111|111100 - {0xfffffe90ul, 28, 11}, // 11111111|11111111|11111110|1001 - {0xfffffea0ul, 28, 12}, // 11111111|11111111|11111110|1010 - {0xfffffff4ul, 30, 13}, // 11111111|11111111|11111111|111101 - {0xfffffeb0ul, 28, 14}, // 11111111|11111111|11111110|1011 - {0xfffffec0ul, 28, 15}, // 11111111|11111111|11111110|1100 - {0xfffffed0ul, 28, 16}, // 11111111|11111111|11111110|1101 - {0xfffffee0ul, 28, 17}, // 11111111|11111111|11111110|1110 - {0xfffffef0ul, 28, 18}, // 11111111|11111111|11111110|1111 - {0xffffff00ul, 28, 19}, // 11111111|11111111|11111111|0000 - {0xffffff10ul, 28, 20}, // 11111111|11111111|11111111|0001 - {0xffffff20ul, 28, 21}, // 11111111|11111111|11111111|0010 - {0xfffffff8ul, 30, 22}, // 11111111|11111111|11111111|111110 - {0xffffff30ul, 28, 23}, // 11111111|11111111|11111111|0011 - {0xffffff40ul, 28, 24}, // 11111111|11111111|11111111|0100 - {0xffffff50ul, 28, 25}, // 11111111|11111111|11111111|0101 - {0xffffff60ul, 28, 26}, // 11111111|11111111|11111111|0110 - {0xffffff70ul, 28, 27}, // 11111111|11111111|11111111|0111 - {0xffffff80ul, 28, 28}, // 11111111|11111111|11111111|1000 - {0xffffff90ul, 28, 29}, // 11111111|11111111|11111111|1001 - {0xffffffa0ul, 28, 30}, // 11111111|11111111|11111111|1010 - {0xffffffb0ul, 28, 31}, // 11111111|11111111|11111111|1011 - {0x50000000ul, 6, 32}, // ' ' 010100 - {0xfe000000ul, 10, 33}, // '!' 11111110|00 - {0xfe400000ul, 10, 34}, // '"' 11111110|01 - {0xffa00000ul, 12, 35}, // '#' 11111111|1010 - {0xffc80000ul, 13, 36}, // '$' 11111111|11001 - {0x54000000ul, 6, 37}, // '%' 010101 - {0xf8000000ul, 8, 38}, // '&' 11111000 - {0xff400000ul, 11, 39}, // ''' 11111111|010 - {0xfe800000ul, 10, 40}, // '(' 11111110|10 - {0xfec00000ul, 10, 41}, // ')' 11111110|11 - {0xf9000000ul, 8, 42}, // '*' 11111001 - {0xff600000ul, 11, 43}, // '+' 11111111|011 - {0xfa000000ul, 8, 44}, // ',' 11111010 - {0x58000000ul, 6, 45}, // '-' 010110 - {0x5c000000ul, 6, 46}, // '.' 010111 - {0x60000000ul, 6, 47}, // '/' 011000 - {0x00000000ul, 5, 48}, // '0' 00000 - {0x08000000ul, 5, 49}, // '1' 00001 - {0x10000000ul, 5, 50}, // '2' 00010 - {0x64000000ul, 6, 51}, // '3' 011001 - {0x68000000ul, 6, 52}, // '4' 011010 - {0x6c000000ul, 6, 53}, // '5' 011011 - {0x70000000ul, 6, 54}, // '6' 011100 - {0x74000000ul, 6, 55}, // '7' 011101 - {0x78000000ul, 6, 56}, // '8' 011110 - {0x7c000000ul, 6, 57}, // '9' 011111 - {0xb8000000ul, 7, 58}, // ':' 1011100 - {0xfb000000ul, 8, 59}, // ';' 11111011 - {0xfff80000ul, 15, 60}, // '<' 11111111|1111100 - {0x80000000ul, 6, 61}, // '=' 100000 - {0xffb00000ul, 12, 62}, // '>' 11111111|1011 - {0xff000000ul, 10, 63}, // '?' 11111111|00 - {0xffd00000ul, 13, 64}, // '@' 11111111|11010 - {0x84000000ul, 6, 65}, // 'A' 100001 - {0xba000000ul, 7, 66}, // 'B' 1011101 - {0xbc000000ul, 7, 67}, // 'C' 1011110 - {0xbe000000ul, 7, 68}, // 'D' 1011111 - {0xc0000000ul, 7, 69}, // 'E' 1100000 - {0xc2000000ul, 7, 70}, // 'F' 1100001 - {0xc4000000ul, 7, 71}, // 'G' 1100010 - {0xc6000000ul, 7, 72}, // 'H' 1100011 - {0xc8000000ul, 7, 73}, // 'I' 1100100 - {0xca000000ul, 7, 74}, // 'J' 1100101 - {0xcc000000ul, 7, 75}, // 'K' 1100110 - {0xce000000ul, 7, 76}, // 'L' 1100111 - {0xd0000000ul, 7, 77}, // 'M' 1101000 - {0xd2000000ul, 7, 78}, // 'N' 1101001 - {0xd4000000ul, 7, 79}, // 'O' 1101010 - {0xd6000000ul, 7, 80}, // 'P' 1101011 - {0xd8000000ul, 7, 81}, // 'Q' 1101100 - {0xda000000ul, 7, 82}, // 'R' 1101101 - {0xdc000000ul, 7, 83}, // 'S' 1101110 - {0xde000000ul, 7, 84}, // 'T' 1101111 - {0xe0000000ul, 7, 85}, // 'U' 1110000 - {0xe2000000ul, 7, 86}, // 'V' 1110001 - {0xe4000000ul, 7, 87}, // 'W' 1110010 - {0xfc000000ul, 8, 88}, // 'X' 11111100 - {0xe6000000ul, 7, 89}, // 'Y' 1110011 - {0xfd000000ul, 8, 90}, // 'Z' 11111101 - {0xffd80000ul, 13, 91}, // '[' 11111111|11011 - {0xfffe0000ul, 19, 92}, // '\' 11111111|11111110|000 - {0xffe00000ul, 13, 93}, // ']' 11111111|11100 - {0xfff00000ul, 14, 94}, // '^' 11111111|111100 - {0x88000000ul, 6, 95}, // '_' 100010 - {0xfffa0000ul, 15, 96}, // '`' 11111111|1111101 - {0x18000000ul, 5, 97}, // 'a' 00011 - {0x8c000000ul, 6, 98}, // 'b' 100011 - {0x20000000ul, 5, 99}, // 'c' 00100 - {0x90000000ul, 6, 100}, // 'd' 100100 - {0x28000000ul, 5, 101}, // 'e' 00101 - {0x94000000ul, 6, 102}, // 'f' 100101 - {0x98000000ul, 6, 103}, // 'g' 100110 - {0x9c000000ul, 6, 104}, // 'h' 100111 - {0x30000000ul, 5, 105}, // 'i' 00110 - {0xe8000000ul, 7, 106}, // 'j' 1110100 - {0xea000000ul, 7, 107}, // 'k' 1110101 - {0xa0000000ul, 6, 108}, // 'l' 101000 - {0xa4000000ul, 6, 109}, // 'm' 101001 - {0xa8000000ul, 6, 110}, // 'n' 101010 - {0x38000000ul, 5, 111}, // 'o' 00111 - {0xac000000ul, 6, 112}, // 'p' 101011 - {0xec000000ul, 7, 113}, // 'q' 1110110 - {0xb0000000ul, 6, 114}, // 'r' 101100 - {0x40000000ul, 5, 115}, // 's' 01000 - {0x48000000ul, 5, 116}, // 't' 01001 - {0xb4000000ul, 6, 117}, // 'u' 101101 - {0xee000000ul, 7, 118}, // 'v' 1110111 - {0xf0000000ul, 7, 119}, // 'w' 1111000 - {0xf2000000ul, 7, 120}, // 'x' 1111001 - {0xf4000000ul, 7, 121}, // 'y' 1111010 - {0xf6000000ul, 7, 122}, // 'z' 1111011 - {0xfffc0000ul, 15, 123}, // '{' 11111111|1111110 - {0xff800000ul, 11, 124}, // '|' 11111111|100 - {0xfff40000ul, 14, 125}, // '}' 11111111|111101 - {0xffe80000ul, 13, 126}, // '~' 11111111|11101 - {0xffffffc0ul, 28, 127}, // 11111111|11111111|11111111|1100 - {0xfffe6000ul, 20, 128}, // 11111111|11111110|0110 - {0xffff4800ul, 22, 129}, // 11111111|11111111|010010 - {0xfffe7000ul, 20, 130}, // 11111111|11111110|0111 - {0xfffe8000ul, 20, 131}, // 11111111|11111110|1000 - {0xffff4c00ul, 22, 132}, // 11111111|11111111|010011 - {0xffff5000ul, 22, 133}, // 11111111|11111111|010100 - {0xffff5400ul, 22, 134}, // 11111111|11111111|010101 - {0xffffb200ul, 23, 135}, // 11111111|11111111|1011001 - {0xffff5800ul, 22, 136}, // 11111111|11111111|010110 - {0xffffb400ul, 23, 137}, // 11111111|11111111|1011010 - {0xffffb600ul, 23, 138}, // 11111111|11111111|1011011 - {0xffffb800ul, 23, 139}, // 11111111|11111111|1011100 - {0xffffba00ul, 23, 140}, // 11111111|11111111|1011101 - {0xffffbc00ul, 23, 141}, // 11111111|11111111|1011110 - {0xffffeb00ul, 24, 142}, // 11111111|11111111|11101011 - {0xffffbe00ul, 23, 143}, // 11111111|11111111|1011111 - {0xffffec00ul, 24, 144}, // 11111111|11111111|11101100 - {0xffffed00ul, 24, 145}, // 11111111|11111111|11101101 - {0xffff5c00ul, 22, 146}, // 11111111|11111111|010111 - {0xffffc000ul, 23, 147}, // 11111111|11111111|1100000 - {0xffffee00ul, 24, 148}, // 11111111|11111111|11101110 - {0xffffc200ul, 23, 149}, // 11111111|11111111|1100001 - {0xffffc400ul, 23, 150}, // 11111111|11111111|1100010 - {0xffffc600ul, 23, 151}, // 11111111|11111111|1100011 - {0xffffc800ul, 23, 152}, // 11111111|11111111|1100100 - {0xfffee000ul, 21, 153}, // 11111111|11111110|11100 - {0xffff6000ul, 22, 154}, // 11111111|11111111|011000 - {0xffffca00ul, 23, 155}, // 11111111|11111111|1100101 - {0xffff6400ul, 22, 156}, // 11111111|11111111|011001 - {0xffffcc00ul, 23, 157}, // 11111111|11111111|1100110 - {0xffffce00ul, 23, 158}, // 11111111|11111111|1100111 - {0xffffef00ul, 24, 159}, // 11111111|11111111|11101111 - {0xffff6800ul, 22, 160}, // 11111111|11111111|011010 - {0xfffee800ul, 21, 161}, // 11111111|11111110|11101 - {0xfffe9000ul, 20, 162}, // 11111111|11111110|1001 - {0xffff6c00ul, 22, 163}, // 11111111|11111111|011011 - {0xffff7000ul, 22, 164}, // 11111111|11111111|011100 - {0xffffd000ul, 23, 165}, // 11111111|11111111|1101000 - {0xffffd200ul, 23, 166}, // 11111111|11111111|1101001 - {0xfffef000ul, 21, 167}, // 11111111|11111110|11110 - {0xffffd400ul, 23, 168}, // 11111111|11111111|1101010 - {0xffff7400ul, 22, 169}, // 11111111|11111111|011101 - {0xffff7800ul, 22, 170}, // 11111111|11111111|011110 - {0xfffff000ul, 24, 171}, // 11111111|11111111|11110000 - {0xfffef800ul, 21, 172}, // 11111111|11111110|11111 - {0xffff7c00ul, 22, 173}, // 11111111|11111111|011111 - {0xffffd600ul, 23, 174}, // 11111111|11111111|1101011 - {0xffffd800ul, 23, 175}, // 11111111|11111111|1101100 - {0xffff0000ul, 21, 176}, // 11111111|11111111|00000 - {0xffff0800ul, 21, 177}, // 11111111|11111111|00001 - {0xffff8000ul, 22, 178}, // 11111111|11111111|100000 - {0xffff1000ul, 21, 179}, // 11111111|11111111|00010 - {0xffffda00ul, 23, 180}, // 11111111|11111111|1101101 - {0xffff8400ul, 22, 181}, // 11111111|11111111|100001 - {0xffffdc00ul, 23, 182}, // 11111111|11111111|1101110 - {0xffffde00ul, 23, 183}, // 11111111|11111111|1101111 - {0xfffea000ul, 20, 184}, // 11111111|11111110|1010 - {0xffff8800ul, 22, 185}, // 11111111|11111111|100010 - {0xffff8c00ul, 22, 186}, // 11111111|11111111|100011 - {0xffff9000ul, 22, 187}, // 11111111|11111111|100100 - {0xffffe000ul, 23, 188}, // 11111111|11111111|1110000 - {0xffff9400ul, 22, 189}, // 11111111|11111111|100101 - {0xffff9800ul, 22, 190}, // 11111111|11111111|100110 - {0xffffe200ul, 23, 191}, // 11111111|11111111|1110001 - {0xfffff800ul, 26, 192}, // 11111111|11111111|11111000|00 - {0xfffff840ul, 26, 193}, // 11111111|11111111|11111000|01 - {0xfffeb000ul, 20, 194}, // 11111111|11111110|1011 - {0xfffe2000ul, 19, 195}, // 11111111|11111110|001 - {0xffff9c00ul, 22, 196}, // 11111111|11111111|100111 - {0xffffe400ul, 23, 197}, // 11111111|11111111|1110010 - {0xffffa000ul, 22, 198}, // 11111111|11111111|101000 - {0xfffff600ul, 25, 199}, // 11111111|11111111|11110110|0 - {0xfffff880ul, 26, 200}, // 11111111|11111111|11111000|10 - {0xfffff8c0ul, 26, 201}, // 11111111|11111111|11111000|11 - {0xfffff900ul, 26, 202}, // 11111111|11111111|11111001|00 - {0xfffffbc0ul, 27, 203}, // 11111111|11111111|11111011|110 - {0xfffffbe0ul, 27, 204}, // 11111111|11111111|11111011|111 - {0xfffff940ul, 26, 205}, // 11111111|11111111|11111001|01 - {0xfffff100ul, 24, 206}, // 11111111|11111111|11110001 - {0xfffff680ul, 25, 207}, // 11111111|11111111|11110110|1 - {0xfffe4000ul, 19, 208}, // 11111111|11111110|010 - {0xffff1800ul, 21, 209}, // 11111111|11111111|00011 - {0xfffff980ul, 26, 210}, // 11111111|11111111|11111001|10 - {0xfffffc00ul, 27, 211}, // 11111111|11111111|11111100|000 - {0xfffffc20ul, 27, 212}, // 11111111|11111111|11111100|001 - {0xfffff9c0ul, 26, 213}, // 11111111|11111111|11111001|11 - {0xfffffc40ul, 27, 214}, // 11111111|11111111|11111100|010 - {0xfffff200ul, 24, 215}, // 11111111|11111111|11110010 - {0xffff2000ul, 21, 216}, // 11111111|11111111|00100 - {0xffff2800ul, 21, 217}, // 11111111|11111111|00101 - {0xfffffa00ul, 26, 218}, // 11111111|11111111|11111010|00 - {0xfffffa40ul, 26, 219}, // 11111111|11111111|11111010|01 - {0xffffffd0ul, 28, 220}, // 11111111|11111111|11111111|1101 - {0xfffffc60ul, 27, 221}, // 11111111|11111111|11111100|011 - {0xfffffc80ul, 27, 222}, // 11111111|11111111|11111100|100 - {0xfffffca0ul, 27, 223}, // 11111111|11111111|11111100|101 - {0xfffec000ul, 20, 224}, // 11111111|11111110|1100 - {0xfffff300ul, 24, 225}, // 11111111|11111111|11110011 - {0xfffed000ul, 20, 226}, // 11111111|11111110|1101 - {0xffff3000ul, 21, 227}, // 11111111|11111111|00110 - {0xffffa400ul, 22, 228}, // 11111111|11111111|101001 - {0xffff3800ul, 21, 229}, // 11111111|11111111|00111 - {0xffff4000ul, 21, 230}, // 11111111|11111111|01000 - {0xffffe600ul, 23, 231}, // 11111111|11111111|1110011 - {0xffffa800ul, 22, 232}, // 11111111|11111111|101010 - {0xffffac00ul, 22, 233}, // 11111111|11111111|101011 - {0xfffff700ul, 25, 234}, // 11111111|11111111|11110111|0 - {0xfffff780ul, 25, 235}, // 11111111|11111111|11110111|1 - {0xfffff400ul, 24, 236}, // 11111111|11111111|11110100 - {0xfffff500ul, 24, 237}, // 11111111|11111111|11110101 - {0xfffffa80ul, 26, 238}, // 11111111|11111111|11111010|10 - {0xffffe800ul, 23, 239}, // 11111111|11111111|1110100 - {0xfffffac0ul, 26, 240}, // 11111111|11111111|11111010|11 - {0xfffffcc0ul, 27, 241}, // 11111111|11111111|11111100|110 - {0xfffffb00ul, 26, 242}, // 11111111|11111111|11111011|00 - {0xfffffb40ul, 26, 243}, // 11111111|11111111|11111011|01 - {0xfffffce0ul, 27, 244}, // 11111111|11111111|11111100|111 - {0xfffffd00ul, 27, 245}, // 11111111|11111111|11111101|000 - {0xfffffd20ul, 27, 246}, // 11111111|11111111|11111101|001 - {0xfffffd40ul, 27, 247}, // 11111111|11111111|11111101|010 - {0xfffffd60ul, 27, 248}, // 11111111|11111111|11111101|011 - {0xffffffe0ul, 28, 249}, // 11111111|11111111|11111111|1110 - {0xfffffd80ul, 27, 250}, // 11111111|11111111|11111101|100 - {0xfffffda0ul, 27, 251}, // 11111111|11111111|11111101|101 - {0xfffffdc0ul, 27, 252}, // 11111111|11111111|11111101|110 - {0xfffffde0ul, 27, 253}, // 11111111|11111111|11111101|111 - {0xfffffe00ul, 27, 254}, // 11111111|11111111|11111110|000 - {0xfffffb80ul, 26, 255}, // 11111111|11111111|11111011|10 - {0xfffffffcul, 30, 256}, // EOS 11111111|11111111|11111111|111111 - }; - return *kHpackHuffmanCode; -} - -// The "constructor" for a HpackStaticEntry that computes the lengths at -// compile time. -#define STATIC_ENTRY(name, value) \ - { name, SPDY_ARRAYSIZE(name) - 1, value, SPDY_ARRAYSIZE(value) - 1 } - -const std::vector<HpackStaticEntry>& HpackStaticTableVector() { - static const auto* kHpackStaticTable = new std::vector<HpackStaticEntry>{ - STATIC_ENTRY(":authority", ""), // 1 - STATIC_ENTRY(":method", "GET"), // 2 - STATIC_ENTRY(":method", "POST"), // 3 - STATIC_ENTRY(":path", "/"), // 4 - STATIC_ENTRY(":path", "/index.html"), // 5 - STATIC_ENTRY(":scheme", "http"), // 6 - STATIC_ENTRY(":scheme", "https"), // 7 - STATIC_ENTRY(":status", "200"), // 8 - STATIC_ENTRY(":status", "204"), // 9 - STATIC_ENTRY(":status", "206"), // 10 - STATIC_ENTRY(":status", "304"), // 11 - STATIC_ENTRY(":status", "400"), // 12 - STATIC_ENTRY(":status", "404"), // 13 - STATIC_ENTRY(":status", "500"), // 14 - STATIC_ENTRY("accept-charset", ""), // 15 - STATIC_ENTRY("accept-encoding", "gzip, deflate"), // 16 - STATIC_ENTRY("accept-language", ""), // 17 - STATIC_ENTRY("accept-ranges", ""), // 18 - STATIC_ENTRY("accept", ""), // 19 - STATIC_ENTRY("access-control-allow-origin", ""), // 20 - STATIC_ENTRY("age", ""), // 21 - STATIC_ENTRY("allow", ""), // 22 - STATIC_ENTRY("authorization", ""), // 23 - STATIC_ENTRY("cache-control", ""), // 24 - STATIC_ENTRY("content-disposition", ""), // 25 - STATIC_ENTRY("content-encoding", ""), // 26 - STATIC_ENTRY("content-language", ""), // 27 - STATIC_ENTRY("content-length", ""), // 28 - STATIC_ENTRY("content-location", ""), // 29 - STATIC_ENTRY("content-range", ""), // 30 - STATIC_ENTRY("content-type", ""), // 31 - STATIC_ENTRY("cookie", ""), // 32 - STATIC_ENTRY("date", ""), // 33 - STATIC_ENTRY("etag", ""), // 34 - STATIC_ENTRY("expect", ""), // 35 - STATIC_ENTRY("expires", ""), // 36 - STATIC_ENTRY("from", ""), // 37 - STATIC_ENTRY("host", ""), // 38 - STATIC_ENTRY("if-match", ""), // 39 - STATIC_ENTRY("if-modified-since", ""), // 40 - STATIC_ENTRY("if-none-match", ""), // 41 - STATIC_ENTRY("if-range", ""), // 42 - STATIC_ENTRY("if-unmodified-since", ""), // 43 - STATIC_ENTRY("last-modified", ""), // 44 - STATIC_ENTRY("link", ""), // 45 - STATIC_ENTRY("location", ""), // 46 - STATIC_ENTRY("max-forwards", ""), // 47 - STATIC_ENTRY("proxy-authenticate", ""), // 48 - STATIC_ENTRY("proxy-authorization", ""), // 49 - STATIC_ENTRY("range", ""), // 50 - STATIC_ENTRY("referer", ""), // 51 - STATIC_ENTRY("refresh", ""), // 52 - STATIC_ENTRY("retry-after", ""), // 53 - STATIC_ENTRY("server", ""), // 54 - STATIC_ENTRY("set-cookie", ""), // 55 - STATIC_ENTRY("strict-transport-security", ""), // 56 - STATIC_ENTRY("transfer-encoding", ""), // 57 - STATIC_ENTRY("user-agent", ""), // 58 - STATIC_ENTRY("vary", ""), // 59 - STATIC_ENTRY("via", ""), // 60 - STATIC_ENTRY("www-authenticate", ""), // 61 - }; - return *kHpackStaticTable; -} - -#undef STATIC_ENTRY - -const HpackHuffmanTable& ObtainHpackHuffmanTable() { - static const HpackHuffmanTable* const shared_huffman_table = []() { - auto* table = new HpackHuffmanTable(); - CHECK(table->Initialize(HpackHuffmanCodeVector().data(), - HpackHuffmanCodeVector().size())); - CHECK(table->IsInitialized()); - return table; - }(); - return *shared_huffman_table; -} - -const HpackStaticTable& ObtainHpackStaticTable() { - static const HpackStaticTable* const shared_static_table = []() { - auto* table = new HpackStaticTable(); - table->Initialize(HpackStaticTableVector().data(), - HpackStaticTableVector().size()); - CHECK(table->IsInitialized()); - return table; - }(); - return *shared_static_table; -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_constants.h b/net/third_party/spdy/core/hpack/hpack_constants.h deleted file mode 100644 index 860bc608..0000000 --- a/net/third_party/spdy/core/hpack/hpack_constants.h +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_CONSTANTS_H_ -#define NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_CONSTANTS_H_ - -#include <cstddef> -#include <cstdint> -#include <vector> - -#include "net/third_party/spdy/platform/api/spdy_export.h" - -// All section references below are to -// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08 - -namespace spdy { - -// An HpackPrefix signifies |bits| stored in the top |bit_size| bits -// of an octet. -struct HpackPrefix { - uint8_t bits; - size_t bit_size; -}; - -// Represents a symbol and its Huffman code (stored in most-significant bits). -struct HpackHuffmanSymbol { - uint32_t code; - uint8_t length; - uint16_t id; -}; - -// An entry in the static table. Must be a POD in order to avoid static -// initializers, i.e. no user-defined constructors or destructors. -struct HpackStaticEntry { - const char* const name; - const size_t name_len; - const char* const value; - const size_t value_len; -}; - -class HpackHuffmanTable; -class HpackStaticTable; - -// Defined in RFC 7540, 6.5.2. -const uint32_t kDefaultHeaderTableSizeSetting = 4096; - -// RFC 7541, 5.2: Flag for a string literal that is stored unmodified (i.e., -// without Huffman encoding). -const HpackPrefix kStringLiteralIdentityEncoded = {0x0, 1}; - -// RFC 7541, 5.2: Flag for a Huffman-coded string literal. -const HpackPrefix kStringLiteralHuffmanEncoded = {0x1, 1}; - -// RFC 7541, 6.1: Opcode for an indexed header field. -const HpackPrefix kIndexedOpcode = {0b1, 1}; - -// RFC 7541, 6.2.1: Opcode for a literal header field with incremental indexing. -const HpackPrefix kLiteralIncrementalIndexOpcode = {0b01, 2}; - -// RFC 7541, 6.2.2: Opcode for a literal header field without indexing. -const HpackPrefix kLiteralNoIndexOpcode = {0b0000, 4}; - -// RFC 7541, 6.2.3: Opcode for a literal header field which is never indexed. -// Currently unused. -// const HpackPrefix kLiteralNeverIndexOpcode = {0b0001, 4}; - -// RFC 7541, 6.3: Opcode for maximum header table size update. Begins a -// varint-encoded table size with a 5-bit prefix. -const HpackPrefix kHeaderTableSizeUpdateOpcode = {0b001, 3}; - -// Symbol code table from RFC 7541, "Appendix C. Huffman Code". -SPDY_EXPORT_PRIVATE const std::vector<HpackHuffmanSymbol>& -HpackHuffmanCodeVector(); - -// Static table from RFC 7541, "Appendix B. Static Table Definition". -SPDY_EXPORT_PRIVATE const std::vector<HpackStaticEntry>& -HpackStaticTableVector(); - -// Returns a HpackHuffmanTable instance initialized with |kHpackHuffmanCode|. -// The instance is read-only, has static lifetime, and is safe to share amoung -// threads. This function is thread-safe. -SPDY_EXPORT_PRIVATE const HpackHuffmanTable& ObtainHpackHuffmanTable(); - -// Returns a HpackStaticTable instance initialized with |kHpackStaticTable|. -// The instance is read-only, has static lifetime, and is safe to share amoung -// threads. This function is thread-safe. -SPDY_EXPORT_PRIVATE const HpackStaticTable& ObtainHpackStaticTable(); - -// Pseudo-headers start with a colon. (HTTP2 8.1.2.1., HPACK 3.1.) -const char kPseudoHeaderPrefix = ':'; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_CONSTANTS_H_
diff --git a/net/third_party/spdy/core/hpack/hpack_decoder_adapter.cc b/net/third_party/spdy/core/hpack/hpack_decoder_adapter.cc deleted file mode 100644 index bce4b36..0000000 --- a/net/third_party/spdy/core/hpack/hpack_decoder_adapter.cc +++ /dev/null
@@ -1,201 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_decoder_adapter.h" - -#include "base/logging.h" -#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h" -#include "net/third_party/quiche/src/http2/decoder/decode_status.h" -#include "net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h" - -using ::http2::DecodeBuffer; -using ::http2::HpackEntryType; -using ::http2::HpackString; - -namespace spdy { -namespace { -const size_t kMaxDecodeBufferSizeBytes = 32 * 1024; // 32 KB -} // namespace - -HpackDecoderAdapter::HpackDecoderAdapter() - : hpack_decoder_(&listener_adapter_, kMaxDecodeBufferSizeBytes), - max_decode_buffer_size_bytes_(kMaxDecodeBufferSizeBytes), - header_block_started_(false) {} - -HpackDecoderAdapter::~HpackDecoderAdapter() = default; - -void HpackDecoderAdapter::ApplyHeaderTableSizeSetting(size_t size_setting) { - DVLOG(2) << "HpackDecoderAdapter::ApplyHeaderTableSizeSetting"; - hpack_decoder_.ApplyHeaderTableSizeSetting(size_setting); -} - -void HpackDecoderAdapter::HandleControlFrameHeadersStart( - SpdyHeadersHandlerInterface* handler) { - DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersStart"; - DCHECK(!header_block_started_); - listener_adapter_.set_handler(handler); -} - -bool HpackDecoderAdapter::HandleControlFrameHeadersData( - const char* headers_data, - size_t headers_data_length) { - DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersData: len=" - << headers_data_length; - if (!header_block_started_) { - // Initialize the decoding process here rather than in - // HandleControlFrameHeadersStart because that method is not always called. - header_block_started_ = true; - if (!hpack_decoder_.StartDecodingBlock()) { - header_block_started_ = false; - return false; - } - } - - // Sometimes we get a call with headers_data==nullptr and - // headers_data_length==0, in which case we need to avoid creating - // a DecodeBuffer, which would otherwise complain. - if (headers_data_length > 0) { - DCHECK_NE(headers_data, nullptr); - if (headers_data_length > max_decode_buffer_size_bytes_) { - DVLOG(1) << "max_decode_buffer_size_bytes_ < headers_data_length: " - << max_decode_buffer_size_bytes_ << " < " << headers_data_length; - return false; - } - listener_adapter_.AddToTotalHpackBytes(headers_data_length); - http2::DecodeBuffer db(headers_data, headers_data_length); - bool ok = hpack_decoder_.DecodeFragment(&db); - DCHECK(!ok || db.Empty()) << "Remaining=" << db.Remaining(); - return ok; - } - return true; -} - -bool HpackDecoderAdapter::HandleControlFrameHeadersComplete( - size_t* compressed_len) { - DVLOG(2) << "HpackDecoderAdapter::HandleControlFrameHeadersComplete"; - if (compressed_len != nullptr) { - *compressed_len = listener_adapter_.total_hpack_bytes(); - } - if (!hpack_decoder_.EndDecodingBlock()) { - DVLOG(3) << "EndDecodingBlock returned false"; - return false; - } - header_block_started_ = false; - return true; -} - -const SpdyHeaderBlock& HpackDecoderAdapter::decoded_block() const { - return listener_adapter_.decoded_block(); -} - -void HpackDecoderAdapter::SetHeaderTableDebugVisitor( - std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) { - DVLOG(2) << "HpackDecoderAdapter::SetHeaderTableDebugVisitor"; - if (visitor != nullptr) { - listener_adapter_.SetHeaderTableDebugVisitor(std::move(visitor)); - hpack_decoder_.set_tables_debug_listener(&listener_adapter_); - } else { - hpack_decoder_.set_tables_debug_listener(nullptr); - listener_adapter_.SetHeaderTableDebugVisitor(nullptr); - } -} - -void HpackDecoderAdapter::set_max_decode_buffer_size_bytes( - size_t max_decode_buffer_size_bytes) { - DVLOG(2) << "HpackDecoderAdapter::set_max_decode_buffer_size_bytes"; - max_decode_buffer_size_bytes_ = max_decode_buffer_size_bytes; - hpack_decoder_.set_max_string_size_bytes(max_decode_buffer_size_bytes); -} - -size_t HpackDecoderAdapter::EstimateMemoryUsage() const { - return SpdyEstimateMemoryUsage(hpack_decoder_); -} - -HpackDecoderAdapter::ListenerAdapter::ListenerAdapter() : handler_(nullptr) {} -HpackDecoderAdapter::ListenerAdapter::~ListenerAdapter() = default; - -void HpackDecoderAdapter::ListenerAdapter::set_handler( - SpdyHeadersHandlerInterface* handler) { - handler_ = handler; -} - -void HpackDecoderAdapter::ListenerAdapter::SetHeaderTableDebugVisitor( - std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) { - visitor_ = std::move(visitor); -} - -void HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart() { - DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListStart"; - total_hpack_bytes_ = 0; - total_uncompressed_bytes_ = 0; - decoded_block_.clear(); - if (handler_ != nullptr) { - handler_->OnHeaderBlockStart(); - } -} - -void HpackDecoderAdapter::ListenerAdapter::OnHeader(HpackEntryType entry_type, - const HpackString& name, - const HpackString& value) { - DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeader:\n name: " << name - << "\n value: " << value; - total_uncompressed_bytes_ += name.size() + value.size(); - if (handler_ == nullptr) { - DVLOG(3) << "Adding to decoded_block"; - decoded_block_.AppendValueOrAddHeader(name.ToStringPiece(), - value.ToStringPiece()); - } else { - DVLOG(3) << "Passing to handler"; - handler_->OnHeader(name.ToStringPiece(), value.ToStringPiece()); - } -} - -void HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd() { - DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnHeaderListEnd"; - // We don't clear the SpdyHeaderBlock here to allow access to it until the - // next HPACK block is decoded. - if (handler_ != nullptr) { - handler_->OnHeaderBlockEnd(total_uncompressed_bytes_, total_hpack_bytes_); - handler_ = nullptr; - } -} - -void HpackDecoderAdapter::ListenerAdapter::OnHeaderErrorDetected( - SpdyStringPiece error_message) { - VLOG(1) << error_message; -} - -int64_t HpackDecoderAdapter::ListenerAdapter::OnEntryInserted( - const http2::HpackStringPair& sp, - size_t insert_count) { - DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnEntryInserted: " << sp - << ", insert_count=" << insert_count; - if (visitor_ == nullptr) { - return 0; - } - HpackEntry entry(sp.name.ToStringPiece(), sp.value.ToStringPiece(), - /*is_static*/ false, insert_count); - int64_t time_added = visitor_->OnNewEntry(entry); - DVLOG(2) - << "HpackDecoderAdapter::ListenerAdapter::OnEntryInserted: time_added=" - << time_added; - return time_added; -} - -void HpackDecoderAdapter::ListenerAdapter::OnUseEntry( - const http2::HpackStringPair& sp, - size_t insert_count, - int64_t time_added) { - DVLOG(2) << "HpackDecoderAdapter::ListenerAdapter::OnUseEntry: " << sp - << ", insert_count=" << insert_count - << ", time_added=" << time_added; - if (visitor_ != nullptr) { - HpackEntry entry(sp.name.ToStringPiece(), sp.value.ToStringPiece(), - /*is_static*/ false, insert_count); - entry.set_time_added(time_added); - visitor_->OnUseEntry(entry); - } -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_decoder_adapter.h b/net/third_party/spdy/core/hpack/hpack_decoder_adapter.h deleted file mode 100644 index 9cbd7828..0000000 --- a/net/third_party/spdy/core/hpack/hpack_decoder_adapter.h +++ /dev/null
@@ -1,159 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_DECODER_ADAPTER_H_ -#define NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_DECODER_ADAPTER_H_ - -// HpackDecoderAdapter uses http2::HpackDecoder to decode HPACK blocks into -// HTTP/2 header lists as outlined in http://tools.ietf.org/html/rfc7541. - -#include <stddef.h> - -#include <cstdint> -#include <memory> - -#include "base/macros.h" -#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder.h" -#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_listener.h" -#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables.h" -#include "net/third_party/quiche/src/http2/hpack/hpack_string.h" -#include "net/third_party/quiche/src/http2/hpack/http2_hpack_constants.h" -#include "net/third_party/spdy/core/hpack/hpack_header_table.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_headers_handler_interface.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { -namespace test { -class HpackDecoderAdapterPeer; -} // namespace test - -class SPDY_EXPORT_PRIVATE HpackDecoderAdapter { - public: - friend test::HpackDecoderAdapterPeer; - HpackDecoderAdapter(); - HpackDecoderAdapter(const HpackDecoderAdapter&) = delete; - HpackDecoderAdapter& operator=(const HpackDecoderAdapter&) = delete; - ~HpackDecoderAdapter(); - - // Called upon acknowledgement of SETTINGS_HEADER_TABLE_SIZE. - void ApplyHeaderTableSizeSetting(size_t size_setting); - - // If a SpdyHeadersHandlerInterface is provided, the decoder will emit - // headers to it rather than accumulating them in a SpdyHeaderBlock. - // Does not take ownership of the handler, but does use the pointer until - // the current HPACK block is completely decoded. - void HandleControlFrameHeadersStart(SpdyHeadersHandlerInterface* handler); - - // Called as HPACK block fragments arrive. Returns false if an error occurred - // while decoding the block. Does not take ownership of headers_data. - bool HandleControlFrameHeadersData(const char* headers_data, - size_t headers_data_length); - - // Called after a HPACK block has been completely delivered via - // HandleControlFrameHeadersData(). Returns false if an error occurred. - // |compressed_len| if non-null will be set to the size of the encoded - // buffered block that was accumulated in HandleControlFrameHeadersData(), - // to support subsequent calculation of compression percentage. - // Discards the handler supplied at the start of decoding the block. - // TODO(jamessynge): Determine if compressed_len is needed; it is used to - // produce UUMA stat Net.SpdyHpackDecompressionPercentage, but only for - // deprecated SPDY3. - bool HandleControlFrameHeadersComplete(size_t* compressed_len); - - // Accessor for the most recently decoded headers block. Valid until the next - // call to HandleControlFrameHeadersData(). - // TODO(birenroy): Remove this method when all users of HpackDecoder specify - // a SpdyHeadersHandlerInterface. - const SpdyHeaderBlock& decoded_block() const; - - void SetHeaderTableDebugVisitor( - std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor); - - // Set how much encoded data this decoder is willing to buffer. - // TODO(jamessynge): Resolve definition of this value, as it is currently - // too tied to a single implementation. We probably want to limit one or more - // of these: individual name or value strings, header entries, the entire - // header list, or the HPACK block; we probably shouldn't care about the size - // of individual transport buffers. - void set_max_decode_buffer_size_bytes(size_t max_decode_buffer_size_bytes); - - size_t EstimateMemoryUsage() const; - - private: - class SPDY_EXPORT_PRIVATE ListenerAdapter - : public http2::HpackDecoderListener, - public http2::HpackDecoderTablesDebugListener { - public: - ListenerAdapter(); - ~ListenerAdapter() override; - - // If a SpdyHeadersHandlerInterface is provided, the decoder will emit - // headers to it rather than accumulating them in a SpdyHeaderBlock. - // Does not take ownership of the handler, but does use the pointer until - // the current HPACK block is completely decoded. - void set_handler(SpdyHeadersHandlerInterface* handler); - const SpdyHeaderBlock& decoded_block() const { return decoded_block_; } - - void SetHeaderTableDebugVisitor( - std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor); - - // Override the HpackDecoderListener methods: - void OnHeaderListStart() override; - void OnHeader(http2::HpackEntryType entry_type, - const http2::HpackString& name, - const http2::HpackString& value) override; - void OnHeaderListEnd() override; - void OnHeaderErrorDetected(SpdyStringPiece error_message) override; - - // Override the HpackDecoderTablesDebugListener methods: - int64_t OnEntryInserted(const http2::HpackStringPair& entry, - size_t insert_count) override; - void OnUseEntry(const http2::HpackStringPair& entry, - size_t insert_count, - int64_t insert_time) override; - - void AddToTotalHpackBytes(size_t delta) { total_hpack_bytes_ += delta; } - size_t total_hpack_bytes() const { return total_hpack_bytes_; } - - private: - // If the caller doesn't provide a handler, the header list is stored in - // this SpdyHeaderBlock. - SpdyHeaderBlock decoded_block_; - - // If non-NULL, handles decoded headers. Not owned. - SpdyHeadersHandlerInterface* handler_; - - // Total bytes that have been received as input (i.e. HPACK encoded) - // in the current HPACK block. - size_t total_hpack_bytes_; - - // Total bytes of the name and value strings in the current HPACK block. - size_t total_uncompressed_bytes_; - - // visitor_ is used by a QUIC experiment regarding HPACK; remove - // when the experiment is done. - std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor_; - }; - - // Converts calls to HpackDecoderListener into calls to - // SpdyHeadersHandlerInterface. - ListenerAdapter listener_adapter_; - - // The actual decoder. - http2::HpackDecoder hpack_decoder_; - - // How much encoded data this decoder is willing to buffer. - size_t max_decode_buffer_size_bytes_; - - // Flag to keep track of having seen the header block start. Needed at the - // moment because HandleControlFrameHeadersStart won't be called if a handler - // is not being provided by the caller. - bool header_block_started_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_DECODER_ADAPTER_H_
diff --git a/net/third_party/spdy/core/hpack/hpack_decoder_adapter_test.cc b/net/third_party/spdy/core/hpack/hpack_decoder_adapter_test.cc deleted file mode 100644 index 44afb5ad..0000000 --- a/net/third_party/spdy/core/hpack/hpack_decoder_adapter_test.cc +++ /dev/null
@@ -1,1097 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_decoder_adapter.h" - -// Tests of HpackDecoderAdapter. - -#include <stdint.h> - -#include <tuple> -#include <utility> -#include <vector> - -#include "base/logging.h" -#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state.h" -#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables.h" -#include "net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder.h" -#include "net/third_party/quiche/src/http2/test_tools/http2_random.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/hpack/hpack_encoder.h" -#include "net/third_party/spdy/core/hpack/hpack_output_stream.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" -#include "net/third_party/spdy/platform/api/spdy_arraysize.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::http2::HpackEntryType; -using ::http2::HpackString; -using ::http2::HpackStringPair; -using ::http2::test::HpackBlockBuilder; -using ::http2::test::HpackDecoderPeer; -using ::testing::ElementsAre; -using ::testing::Pair; - -namespace http2 { -namespace test { - -class HpackDecoderStatePeer { - public: - static HpackDecoderTables* GetDecoderTables(HpackDecoderState* state) { - return &state->decoder_tables_; - } -}; - -class HpackDecoderPeer { - public: - static HpackDecoderState* GetDecoderState(HpackDecoder* decoder) { - return &decoder->decoder_state_; - } - static HpackDecoderTables* GetDecoderTables(HpackDecoder* decoder) { - return HpackDecoderStatePeer::GetDecoderTables(GetDecoderState(decoder)); - } -}; - -} // namespace test -} // namespace http2 - -namespace spdy { -namespace test { - -class HpackDecoderAdapterPeer { - public: - explicit HpackDecoderAdapterPeer(HpackDecoderAdapter* decoder) - : decoder_(decoder) {} - - void HandleHeaderRepresentation(SpdyStringPiece name, SpdyStringPiece value) { - decoder_->listener_adapter_.OnHeader(HpackEntryType::kIndexedLiteralHeader, - HpackString(name), HpackString(value)); - } - - http2::HpackDecoderTables* GetDecoderTables() { - return HpackDecoderPeer::GetDecoderTables(&decoder_->hpack_decoder_); - } - - const HpackStringPair* GetTableEntry(uint32_t index) { - return GetDecoderTables()->Lookup(index); - } - - size_t current_header_table_size() { - return GetDecoderTables()->current_header_table_size(); - } - - size_t header_table_size_limit() { - return GetDecoderTables()->header_table_size_limit(); - } - - void set_header_table_size_limit(size_t size) { - return GetDecoderTables()->DynamicTableSizeUpdate(size); - } - - private: - HpackDecoderAdapter* decoder_; -}; - -class HpackEncoderPeer { - public: - static void CookieToCrumbs(const HpackEncoder::Representation& cookie, - HpackEncoder::Representations* crumbs_out) { - HpackEncoder::CookieToCrumbs(cookie, crumbs_out); - } -}; - -namespace { - -const bool kNoCheckDecodedSize = false; -const char* kCookieKey = "cookie"; - -// Is HandleControlFrameHeadersStart to be called, and with what value? -enum StartChoice { START_WITH_HANDLER, START_WITHOUT_HANDLER, NO_START }; - -class HpackDecoderAdapterTest - : public ::testing::TestWithParam<std::tuple<StartChoice, bool>> { - protected: - HpackDecoderAdapterTest() : decoder_(), decoder_peer_(&decoder_) {} - - void SetUp() override { - std::tie(start_choice_, randomly_split_input_buffer_) = GetParam(); - } - - void HandleControlFrameHeadersStart() { - bytes_passed_in_ = 0; - switch (start_choice_) { - case START_WITH_HANDLER: - decoder_.HandleControlFrameHeadersStart(&handler_); - break; - case START_WITHOUT_HANDLER: - decoder_.HandleControlFrameHeadersStart(nullptr); - break; - case NO_START: - break; - } - } - - bool HandleControlFrameHeadersData(SpdyStringPiece str) { - VLOG(3) << "HandleControlFrameHeadersData:\n" << SpdyHexDump(str); - bytes_passed_in_ += str.size(); - return decoder_.HandleControlFrameHeadersData(str.data(), str.size()); - } - - bool HandleControlFrameHeadersComplete(size_t* size) { - bool rc = decoder_.HandleControlFrameHeadersComplete(size); - if (size != nullptr) { - EXPECT_EQ(*size, bytes_passed_in_); - } - return rc; - } - - bool DecodeHeaderBlock(SpdyStringPiece str, bool check_decoded_size = true) { - // Don't call this again if HandleControlFrameHeadersData failed previously. - EXPECT_FALSE(decode_has_failed_); - HandleControlFrameHeadersStart(); - if (randomly_split_input_buffer_) { - do { - // Decode some fragment of the remaining bytes. - size_t bytes = str.size(); - if (!str.empty()) { - bytes = random_.Uniform(str.size()) + 1; - } - EXPECT_LE(bytes, str.size()); - if (!HandleControlFrameHeadersData(str.substr(0, bytes))) { - decode_has_failed_ = true; - return false; - } - str.remove_prefix(bytes); - } while (!str.empty()); - } else if (!HandleControlFrameHeadersData(str)) { - decode_has_failed_ = true; - return false; - } - // Want to get out the number of compressed bytes that were decoded, - // so pass in a pointer if no handler. - size_t total_hpack_bytes = 0; - if (start_choice_ == START_WITH_HANDLER) { - if (!HandleControlFrameHeadersComplete(nullptr)) { - decode_has_failed_ = true; - return false; - } - total_hpack_bytes = handler_.compressed_header_bytes_parsed(); - } else { - if (!HandleControlFrameHeadersComplete(&total_hpack_bytes)) { - decode_has_failed_ = true; - return false; - } - } - EXPECT_EQ(total_hpack_bytes, bytes_passed_in_); - if (check_decoded_size && start_choice_ == START_WITH_HANDLER) { - EXPECT_EQ(handler_.header_bytes_parsed(), SizeOfHeaders(decoded_block())); - } - return true; - } - - bool EncodeAndDecodeDynamicTableSizeUpdates(size_t first, size_t second) { - HpackBlockBuilder hbb; - hbb.AppendDynamicTableSizeUpdate(first); - if (second != first) { - hbb.AppendDynamicTableSizeUpdate(second); - } - return DecodeHeaderBlock(hbb.buffer()); - } - - const SpdyHeaderBlock& decoded_block() const { - if (start_choice_ == START_WITH_HANDLER) { - return handler_.decoded_block(); - } else { - return decoder_.decoded_block(); - } - } - - static size_t SizeOfHeaders(const SpdyHeaderBlock& headers) { - size_t size = 0; - for (const auto& kv : headers) { - if (kv.first == kCookieKey) { - HpackEncoder::Representations crumbs; - HpackEncoderPeer::CookieToCrumbs(kv, &crumbs); - for (const auto& crumb : crumbs) { - size += crumb.first.size() + crumb.second.size(); - } - } else { - size += kv.first.size() + kv.second.size(); - } - } - return size; - } - - const SpdyHeaderBlock& DecodeBlockExpectingSuccess(SpdyStringPiece str) { - EXPECT_TRUE(DecodeHeaderBlock(str)); - return decoded_block(); - } - - void expectEntry(size_t index, - size_t size, - const SpdyString& name, - const SpdyString& value) { - const HpackStringPair* entry = decoder_peer_.GetTableEntry(index); - EXPECT_EQ(name, entry->name) << "index " << index; - EXPECT_EQ(value, entry->value); - EXPECT_EQ(size, entry->size()); - } - - SpdyHeaderBlock MakeHeaderBlock( - const std::vector<std::pair<SpdyString, SpdyString>>& headers) { - SpdyHeaderBlock result; - for (const auto& kv : headers) { - result.AppendValueOrAddHeader(kv.first, kv.second); - } - return result; - } - - http2::test::Http2Random random_; - HpackDecoderAdapter decoder_; - test::HpackDecoderAdapterPeer decoder_peer_; - TestHeadersHandler handler_; - StartChoice start_choice_; - bool randomly_split_input_buffer_; - bool decode_has_failed_ = false; - size_t bytes_passed_in_; -}; - -INSTANTIATE_TEST_CASE_P( - NoHandler, - HpackDecoderAdapterTest, - ::testing::Combine(::testing::Values(START_WITHOUT_HANDLER, NO_START), - ::testing::Bool())); - -INSTANTIATE_TEST_CASE_P( - WithHandler, - HpackDecoderAdapterTest, - ::testing::Combine(::testing::Values(START_WITH_HANDLER), - ::testing::Bool())); - -TEST_P(HpackDecoderAdapterTest, - AddHeaderDataWithHandleControlFrameHeadersData) { - // The hpack decode buffer size is limited in size. This test verifies that - // adding encoded data under that limit is accepted, and data that exceeds the - // limit is rejected. - HandleControlFrameHeadersStart(); - const size_t kMaxBufferSizeBytes = 50; - const SpdyString a_value = SpdyString(49, 'x'); - decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes); - HpackBlockBuilder hbb; - hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader, - false, "a", false, a_value); - const SpdyString& s = hbb.buffer(); - EXPECT_GT(s.size(), kMaxBufferSizeBytes); - - // Any one in input buffer must not exceed kMaxBufferSizeBytes. - EXPECT_TRUE(HandleControlFrameHeadersData(s.substr(0, s.size() / 2))); - EXPECT_TRUE(HandleControlFrameHeadersData(s.substr(s.size() / 2))); - - EXPECT_FALSE(HandleControlFrameHeadersData(s)); - SpdyHeaderBlock expected_block = MakeHeaderBlock({{"a", a_value}}); - EXPECT_EQ(expected_block, decoded_block()); -} - -TEST_P(HpackDecoderAdapterTest, NameTooLong) { - // Verify that a name longer than the allowed size generates an error. - const size_t kMaxBufferSizeBytes = 50; - const SpdyString name = SpdyString(2 * kMaxBufferSizeBytes, 'x'); - const SpdyString value = "abc"; - - decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes); - - HpackBlockBuilder hbb; - hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader, - false, name, false, value); - - const size_t fragment_size = (3 * kMaxBufferSizeBytes) / 2; - const SpdyString fragment = hbb.buffer().substr(0, fragment_size); - - HandleControlFrameHeadersStart(); - EXPECT_FALSE(HandleControlFrameHeadersData(fragment)); -} - -TEST_P(HpackDecoderAdapterTest, HeaderTooLongToBuffer) { - // Verify that a header longer than the allowed size generates an error if - // it isn't all in one input buffer. - const SpdyString name = "some-key"; - const SpdyString value = "some-value"; - const size_t kMaxBufferSizeBytes = name.size() + value.size() - 2; - decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes); - - HpackBlockBuilder hbb; - hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader, - false, name, false, value); - const size_t fragment_size = hbb.size() - 1; - const SpdyString fragment = hbb.buffer().substr(0, fragment_size); - - HandleControlFrameHeadersStart(); - EXPECT_FALSE(HandleControlFrameHeadersData(fragment)); -} - -// Decode with incomplete data in buffer. -TEST_P(HpackDecoderAdapterTest, DecodeWithIncompleteData) { - HandleControlFrameHeadersStart(); - - // No need to wait for more data. - EXPECT_TRUE(HandleControlFrameHeadersData("\x82\x85\x82")); - std::vector<std::pair<SpdyString, SpdyString>> expected_headers = { - {":method", "GET"}, {":path", "/index.html"}, {":method", "GET"}}; - - SpdyHeaderBlock expected_block1 = MakeHeaderBlock(expected_headers); - EXPECT_EQ(expected_block1, decoded_block()); - - // Full and partial headers, won't add partial to the headers. - EXPECT_TRUE( - HandleControlFrameHeadersData("\x40\x03goo" - "\x03gar\xbe\x40\x04spam")); - expected_headers.push_back({"goo", "gar"}); - expected_headers.push_back({"goo", "gar"}); - - SpdyHeaderBlock expected_block2 = MakeHeaderBlock(expected_headers); - EXPECT_EQ(expected_block2, decoded_block()); - - // Add the needed data. - EXPECT_TRUE(HandleControlFrameHeadersData("\x04gggs")); - - size_t size = 0; - EXPECT_TRUE(HandleControlFrameHeadersComplete(&size)); - EXPECT_EQ(24u, size); - - expected_headers.push_back({"spam", "gggs"}); - - SpdyHeaderBlock expected_block3 = MakeHeaderBlock(expected_headers); - EXPECT_EQ(expected_block3, decoded_block()); -} - -TEST_P(HpackDecoderAdapterTest, HandleHeaderRepresentation) { - // Make sure the decoder is properly initialized. - HandleControlFrameHeadersStart(); - HandleControlFrameHeadersData(""); - - // All cookie crumbs are joined. - decoder_peer_.HandleHeaderRepresentation("cookie", " part 1"); - decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 "); - decoder_peer_.HandleHeaderRepresentation("cookie", "part3"); - - // Already-delimited headers are passed through. - decoder_peer_.HandleHeaderRepresentation("passed-through", - SpdyString("foo\0baz", 7)); - - // Other headers are joined on \0. Case matters. - decoder_peer_.HandleHeaderRepresentation("joined", "not joined"); - decoder_peer_.HandleHeaderRepresentation("joineD", "value 1"); - decoder_peer_.HandleHeaderRepresentation("joineD", "value 2"); - - // Empty headers remain empty. - decoder_peer_.HandleHeaderRepresentation("empty", ""); - - // Joined empty headers work as expected. - decoder_peer_.HandleHeaderRepresentation("empty-joined", ""); - decoder_peer_.HandleHeaderRepresentation("empty-joined", "foo"); - decoder_peer_.HandleHeaderRepresentation("empty-joined", ""); - decoder_peer_.HandleHeaderRepresentation("empty-joined", ""); - - // Non-contiguous cookie crumb. - decoder_peer_.HandleHeaderRepresentation("cookie", " fin!"); - - // Finish and emit all headers. - decoder_.HandleControlFrameHeadersComplete(nullptr); - - // Resulting decoded headers are in the same order as the inputs. - EXPECT_THAT( - decoded_block(), - ElementsAre(Pair("cookie", " part 1; part 2 ; part3; fin!"), - Pair("passed-through", SpdyStringPiece("foo\0baz", 7)), - Pair("joined", "not joined"), - Pair("joineD", SpdyStringPiece("value 1\0value 2", 15)), - Pair("empty", ""), - Pair("empty-joined", SpdyStringPiece("\0foo\0\0", 6)))); -} - -// Decoding indexed static table field should work. -TEST_P(HpackDecoderAdapterTest, IndexedHeaderStatic) { - // Reference static table entries #2 and #5. - const SpdyHeaderBlock& header_set1 = DecodeBlockExpectingSuccess("\x82\x85"); - SpdyHeaderBlock expected_header_set1; - expected_header_set1[":method"] = "GET"; - expected_header_set1[":path"] = "/index.html"; - EXPECT_EQ(expected_header_set1, header_set1); - - // Reference static table entry #2. - const SpdyHeaderBlock& header_set2 = DecodeBlockExpectingSuccess("\x82"); - SpdyHeaderBlock expected_header_set2; - expected_header_set2[":method"] = "GET"; - EXPECT_EQ(expected_header_set2, header_set2); -} - -TEST_P(HpackDecoderAdapterTest, IndexedHeaderDynamic) { - // First header block: add an entry to header table. - const SpdyHeaderBlock& header_set1 = DecodeBlockExpectingSuccess( - "\x40\x03" - "foo" - "\x03" - "bar"); - SpdyHeaderBlock expected_header_set1; - expected_header_set1["foo"] = "bar"; - EXPECT_EQ(expected_header_set1, header_set1); - - // Second header block: add another entry to header table. - const SpdyHeaderBlock& header_set2 = DecodeBlockExpectingSuccess( - "\xbe\x40\x04" - "spam" - "\x04" - "eggs"); - SpdyHeaderBlock expected_header_set2; - expected_header_set2["foo"] = "bar"; - expected_header_set2["spam"] = "eggs"; - EXPECT_EQ(expected_header_set2, header_set2); - - // Third header block: refer to most recently added entry. - const SpdyHeaderBlock& header_set3 = DecodeBlockExpectingSuccess("\xbe"); - SpdyHeaderBlock expected_header_set3; - expected_header_set3["spam"] = "eggs"; - EXPECT_EQ(expected_header_set3, header_set3); -} - -// Test a too-large indexed header. -TEST_P(HpackDecoderAdapterTest, InvalidIndexedHeader) { - // High-bit set, and a prefix of one more than the number of static entries. - EXPECT_FALSE(DecodeHeaderBlock("\xbe")); -} - -TEST_P(HpackDecoderAdapterTest, ContextUpdateMaximumSize) { - EXPECT_EQ(kDefaultHeaderTableSizeSetting, - decoder_peer_.header_table_size_limit()); - SpdyString input; - { - // Maximum-size update with size 126. Succeeds. - HpackOutputStream output_stream; - output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream.AppendUint32(126); - - output_stream.TakeString(&input); - EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece(input))); - EXPECT_EQ(126u, decoder_peer_.header_table_size_limit()); - } - { - // Maximum-size update with kDefaultHeaderTableSizeSetting. Succeeds. - HpackOutputStream output_stream; - output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream.AppendUint32(kDefaultHeaderTableSizeSetting); - - output_stream.TakeString(&input); - EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece(input))); - EXPECT_EQ(kDefaultHeaderTableSizeSetting, - decoder_peer_.header_table_size_limit()); - } - { - // Maximum-size update with kDefaultHeaderTableSizeSetting + 1. Fails. - HpackOutputStream output_stream; - output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream.AppendUint32(kDefaultHeaderTableSizeSetting + 1); - - output_stream.TakeString(&input); - EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece(input))); - EXPECT_EQ(kDefaultHeaderTableSizeSetting, - decoder_peer_.header_table_size_limit()); - } -} - -// Two HeaderTableSizeUpdates may appear at the beginning of the block -TEST_P(HpackDecoderAdapterTest, TwoTableSizeUpdates) { - SpdyString input; - { - // Should accept two table size updates, update to second one - HpackOutputStream output_stream; - output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream.AppendUint32(0); - output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream.AppendUint32(122); - - output_stream.TakeString(&input); - EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece(input))); - EXPECT_EQ(122u, decoder_peer_.header_table_size_limit()); - } -} - -// Three HeaderTableSizeUpdates should result in an error -TEST_P(HpackDecoderAdapterTest, ThreeTableSizeUpdatesError) { - SpdyString input; - { - // Should reject three table size updates, update to second one - HpackOutputStream output_stream; - output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream.AppendUint32(5); - output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream.AppendUint32(10); - output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream.AppendUint32(15); - - output_stream.TakeString(&input); - - EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece(input))); - EXPECT_EQ(10u, decoder_peer_.header_table_size_limit()); - } -} - -// HeaderTableSizeUpdates may only appear at the beginning of the block -// Any other updates should result in an error -TEST_P(HpackDecoderAdapterTest, TableSizeUpdateSecondError) { - SpdyString input; - { - // Should reject a table size update appearing after a different entry - // The table size should remain as the default - HpackOutputStream output_stream; - output_stream.AppendBytes("\x82\x85"); - output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream.AppendUint32(123); - - output_stream.TakeString(&input); - - EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece(input))); - EXPECT_EQ(kDefaultHeaderTableSizeSetting, - decoder_peer_.header_table_size_limit()); - } -} - -// HeaderTableSizeUpdates may only appear at the beginning of the block -// Any other updates should result in an error -TEST_P(HpackDecoderAdapterTest, TableSizeUpdateFirstThirdError) { - SpdyString input; - { - // Should reject the second table size update - // if a different entry appears after the first update - // The table size should update to the first but not the second - HpackOutputStream output_stream; - output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream.AppendUint32(60); - output_stream.AppendBytes("\x82\x85"); - output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream.AppendUint32(125); - - output_stream.TakeString(&input); - - EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece(input))); - EXPECT_EQ(60u, decoder_peer_.header_table_size_limit()); - } -} - -// Decoding two valid encoded literal headers with no indexing should -// work. -TEST_P(HpackDecoderAdapterTest, LiteralHeaderNoIndexing) { - // First header with indexed name, second header with string literal - // name. - const char input[] = "\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2"; - const SpdyHeaderBlock& header_set = DecodeBlockExpectingSuccess( - SpdyStringPiece(input, SPDY_ARRAYSIZE(input) - 1)); - - SpdyHeaderBlock expected_header_set; - expected_header_set[":path"] = "/sample/path"; - expected_header_set[":path2"] = "/sample/path/2"; - EXPECT_EQ(expected_header_set, header_set); -} - -// Decoding two valid encoded literal headers with incremental -// indexing and string literal names should work. -TEST_P(HpackDecoderAdapterTest, LiteralHeaderIncrementalIndexing) { - const char input[] = "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2"; - const SpdyHeaderBlock& header_set = DecodeBlockExpectingSuccess( - SpdyStringPiece(input, SPDY_ARRAYSIZE(input) - 1)); - - SpdyHeaderBlock expected_header_set; - expected_header_set[":path"] = "/sample/path"; - expected_header_set[":path2"] = "/sample/path/2"; - EXPECT_EQ(expected_header_set, header_set); -} - -TEST_P(HpackDecoderAdapterTest, LiteralHeaderWithIndexingInvalidNameIndex) { - decoder_.ApplyHeaderTableSizeSetting(0); - EXPECT_TRUE(EncodeAndDecodeDynamicTableSizeUpdates(0, 0)); - - // Name is the last static index. Works. - EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece("\x7d\x03ooo"))); - // Name is one beyond the last static index. Fails. - EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece("\x7e\x03ooo"))); -} - -TEST_P(HpackDecoderAdapterTest, LiteralHeaderNoIndexingInvalidNameIndex) { - // Name is the last static index. Works. - EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece("\x0f\x2e\x03ooo"))); - // Name is one beyond the last static index. Fails. - EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece("\x0f\x2f\x03ooo"))); -} - -TEST_P(HpackDecoderAdapterTest, LiteralHeaderNeverIndexedInvalidNameIndex) { - // Name is the last static index. Works. - EXPECT_TRUE(DecodeHeaderBlock(SpdyStringPiece("\x1f\x2e\x03ooo"))); - // Name is one beyond the last static index. Fails. - EXPECT_FALSE(DecodeHeaderBlock(SpdyStringPiece("\x1f\x2f\x03ooo"))); -} - -TEST_P(HpackDecoderAdapterTest, TruncatedIndex) { - // Indexed Header, varint for index requires multiple bytes, - // but only one provided. - EXPECT_FALSE(DecodeHeaderBlock("\xff")); -} - -TEST_P(HpackDecoderAdapterTest, TruncatedHuffmanLiteral) { - // Literal value, Huffman encoded, but with the last byte missing (i.e. - // drop the final ff shown below). - // - // 41 | == Literal indexed == - // | Indexed name (idx = 1) - // | :authority - // 8c | Literal value (len = 12) - // | Huffman encoded: - // f1e3 c2e5 f23a 6ba0 ab90 f4ff | .....:k..... - // | Decoded: - // | www.example.com - // | -> :authority: www.example.com - - SpdyString first = SpdyHexDecode("418cf1e3c2e5f23a6ba0ab90f4ff"); - EXPECT_TRUE(DecodeHeaderBlock(first)); - first.pop_back(); - EXPECT_FALSE(DecodeHeaderBlock(first)); -} - -TEST_P(HpackDecoderAdapterTest, HuffmanEOSError) { - // Literal value, Huffman encoded, but with an additional ff byte at the end - // of the string, i.e. an EOS that is longer than permitted. - // - // 41 | == Literal indexed == - // | Indexed name (idx = 1) - // | :authority - // 8d | Literal value (len = 13) - // | Huffman encoded: - // f1e3 c2e5 f23a 6ba0 ab90 f4ff | .....:k..... - // | Decoded: - // | www.example.com - // | -> :authority: www.example.com - - SpdyString first = SpdyHexDecode("418cf1e3c2e5f23a6ba0ab90f4ff"); - EXPECT_TRUE(DecodeHeaderBlock(first)); - first = SpdyHexDecode("418df1e3c2e5f23a6ba0ab90f4ffff"); - EXPECT_FALSE(DecodeHeaderBlock(first)); -} - -// Round-tripping the header set from RFC 7541 C.3.1 should work. -// http://httpwg.org/specs/rfc7541.html#rfc.section.C.3.1 -TEST_P(HpackDecoderAdapterTest, BasicC31) { - HpackEncoder encoder(ObtainHpackHuffmanTable()); - - SpdyHeaderBlock expected_header_set; - expected_header_set[":method"] = "GET"; - expected_header_set[":scheme"] = "http"; - expected_header_set[":path"] = "/"; - expected_header_set[":authority"] = "www.example.com"; - - SpdyString encoded_header_set; - EXPECT_TRUE( - encoder.EncodeHeaderSet(expected_header_set, &encoded_header_set)); - - EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set)); - EXPECT_EQ(expected_header_set, decoded_block()); -} - -// RFC 7541, Section C.4: Request Examples with Huffman Coding -// http://httpwg.org/specs/rfc7541.html#rfc.section.C.4 -TEST_P(HpackDecoderAdapterTest, SectionC4RequestHuffmanExamples) { - // TODO(jamessynge): Use http2/hpack/tools/hpack_example.h to parse the - // example directly, instead of having it as a comment. - // - // 82 | == Indexed - Add == - // | idx = 2 - // | -> :method: GET - // 86 | == Indexed - Add == - // | idx = 6 - // | -> :scheme: http - // 84 | == Indexed - Add == - // | idx = 4 - // | -> :path: / - // 41 | == Literal indexed == - // | Indexed name (idx = 1) - // | :authority - // 8c | Literal value (len = 12) - // | Huffman encoded: - // f1e3 c2e5 f23a 6ba0 ab90 f4ff | .....:k..... - // | Decoded: - // | www.example.com - // | -> :authority: www.example.com - SpdyString first = SpdyHexDecode("828684418cf1e3c2e5f23a6ba0ab90f4ff"); - const SpdyHeaderBlock& first_header_set = DecodeBlockExpectingSuccess(first); - - EXPECT_THAT(first_header_set, - ElementsAre( - // clang-format off - Pair(":method", "GET"), - Pair(":scheme", "http"), - Pair(":path", "/"), - Pair(":authority", "www.example.com"))); - // clang-format on - - expectEntry(62, 57, ":authority", "www.example.com"); - EXPECT_EQ(57u, decoder_peer_.current_header_table_size()); - - // 82 | == Indexed - Add == - // | idx = 2 - // | -> :method: GET - // 86 | == Indexed - Add == - // | idx = 6 - // | -> :scheme: http - // 84 | == Indexed - Add == - // | idx = 4 - // | -> :path: / - // be | == Indexed - Add == - // | idx = 62 - // | -> :authority: www.example.com - // 58 | == Literal indexed == - // | Indexed name (idx = 24) - // | cache-control - // 86 | Literal value (len = 8) - // | Huffman encoded: - // a8eb 1064 9cbf | ...d.. - // | Decoded: - // | no-cache - // | -> cache-control: no-cache - - SpdyString second = SpdyHexDecode("828684be5886a8eb10649cbf"); - const SpdyHeaderBlock& second_header_set = - DecodeBlockExpectingSuccess(second); - - EXPECT_THAT(second_header_set, - ElementsAre( - // clang-format off - Pair(":method", "GET"), - Pair(":scheme", "http"), - Pair(":path", "/"), - Pair(":authority", "www.example.com"), - Pair("cache-control", "no-cache"))); - // clang-format on - - expectEntry(62, 53, "cache-control", "no-cache"); - expectEntry(63, 57, ":authority", "www.example.com"); - EXPECT_EQ(110u, decoder_peer_.current_header_table_size()); - - // 82 | == Indexed - Add == - // | idx = 2 - // | -> :method: GET - // 87 | == Indexed - Add == - // | idx = 7 - // | -> :scheme: https - // 85 | == Indexed - Add == - // | idx = 5 - // | -> :path: /index.html - // bf | == Indexed - Add == - // | idx = 63 - // | -> :authority: www.example.com - // 40 | == Literal indexed == - // 88 | Literal name (len = 10) - // | Huffman encoded: - // 25a8 49e9 5ba9 7d7f | %.I.[.}. - // | Decoded: - // | custom-key - // 89 | Literal value (len = 12) - // | Huffman encoded: - // 25a8 49e9 5bb8 e8b4 bf | %.I.[.... - // | Decoded: - // | custom-value - // | -> custom-key: custom-value - SpdyString third = - SpdyHexDecode("828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf"); - const SpdyHeaderBlock& third_header_set = DecodeBlockExpectingSuccess(third); - - EXPECT_THAT( - third_header_set, - ElementsAre( - // clang-format off - Pair(":method", "GET"), - Pair(":scheme", "https"), - Pair(":path", "/index.html"), - Pair(":authority", "www.example.com"), - Pair("custom-key", "custom-value"))); - // clang-format on - - expectEntry(62, 54, "custom-key", "custom-value"); - expectEntry(63, 53, "cache-control", "no-cache"); - expectEntry(64, 57, ":authority", "www.example.com"); - EXPECT_EQ(164u, decoder_peer_.current_header_table_size()); -} - -// RFC 7541, Section C.6: Response Examples with Huffman Coding -// http://httpwg.org/specs/rfc7541.html#rfc.section.C.6 -TEST_P(HpackDecoderAdapterTest, SectionC6ResponseHuffmanExamples) { - // The example is based on a maximum dynamic table size of 256, - // which allows for testing dynamic table evictions. - decoder_peer_.set_header_table_size_limit(256); - - // 48 | == Literal indexed == - // | Indexed name (idx = 8) - // | :status - // 82 | Literal value (len = 3) - // | Huffman encoded: - // 6402 | d. - // | Decoded: - // | 302 - // | -> :status: 302 - // 58 | == Literal indexed == - // | Indexed name (idx = 24) - // | cache-control - // 85 | Literal value (len = 7) - // | Huffman encoded: - // aec3 771a 4b | ..w.K - // | Decoded: - // | private - // | -> cache-control: private - // 61 | == Literal indexed == - // | Indexed name (idx = 33) - // | date - // 96 | Literal value (len = 29) - // | Huffman encoded: - // d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f - // e082 a62d 1bff | ...-.. - // | Decoded: - // | Mon, 21 Oct 2013 20:13:21 - // | GMT - // | -> date: Mon, 21 Oct 2013 - // | 20:13:21 GMT - // 6e | == Literal indexed == - // | Indexed name (idx = 46) - // | location - // 91 | Literal value (len = 23) - // | Huffman encoded: - // 9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 | .)...c.........C - // d3 | . - // | Decoded: - // | https://www.example.com - // | -> location: https://www.e - // | xample.com - - SpdyString first = SpdyHexDecode( - "488264025885aec3771a4b6196d07abe" - "941054d444a8200595040b8166e082a6" - "2d1bff6e919d29ad171863c78f0b97c8" - "e9ae82ae43d3"); - const SpdyHeaderBlock& first_header_set = DecodeBlockExpectingSuccess(first); - - EXPECT_THAT(first_header_set, - ElementsAre( - // clang-format off - Pair(":status", "302"), - Pair("cache-control", "private"), - Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), - Pair("location", "https://www.example.com"))); - // clang-format on - - expectEntry(62, 63, "location", "https://www.example.com"); - expectEntry(63, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT"); - expectEntry(64, 52, "cache-control", "private"); - expectEntry(65, 42, ":status", "302"); - EXPECT_EQ(222u, decoder_peer_.current_header_table_size()); - - // 48 | == Literal indexed == - // | Indexed name (idx = 8) - // | :status - // 83 | Literal value (len = 3) - // | Huffman encoded: - // 640e ff | d.. - // | Decoded: - // | 307 - // | - evict: :status: 302 - // | -> :status: 307 - // c1 | == Indexed - Add == - // | idx = 65 - // | -> cache-control: private - // c0 | == Indexed - Add == - // | idx = 64 - // | -> date: Mon, 21 Oct 2013 - // | 20:13:21 GMT - // bf | == Indexed - Add == - // | idx = 63 - // | -> location: - // | https://www.example.com - SpdyString second = SpdyHexDecode("4883640effc1c0bf"); - const SpdyHeaderBlock& second_header_set = - DecodeBlockExpectingSuccess(second); - - EXPECT_THAT(second_header_set, - ElementsAre( - // clang-format off - Pair(":status", "307"), - Pair("cache-control", "private"), - Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), - Pair("location", "https://www.example.com"))); - // clang-format on - - expectEntry(62, 42, ":status", "307"); - expectEntry(63, 63, "location", "https://www.example.com"); - expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT"); - expectEntry(65, 52, "cache-control", "private"); - EXPECT_EQ(222u, decoder_peer_.current_header_table_size()); - - // 88 | == Indexed - Add == - // | idx = 8 - // | -> :status: 200 - // c1 | == Indexed - Add == - // | idx = 65 - // | -> cache-control: private - // 61 | == Literal indexed == - // | Indexed name (idx = 33) - // | date - // 96 | Literal value (len = 22) - // | Huffman encoded: - // d07a be94 1054 d444 a820 0595 040b 8166 | .z...T.D. .....f - // e084 a62d 1bff | ...-.. - // | Decoded: - // | Mon, 21 Oct 2013 20:13:22 - // | GMT - // | - evict: cache-control: - // | private - // | -> date: Mon, 21 Oct 2013 - // | 20:13:22 GMT - // c0 | == Indexed - Add == - // | idx = 64 - // | -> location: - // | https://www.example.com - // 5a | == Literal indexed == - // | Indexed name (idx = 26) - // | content-encoding - // 83 | Literal value (len = 3) - // | Huffman encoded: - // 9bd9 ab | ... - // | Decoded: - // | gzip - // | - evict: date: Mon, 21 Oct - // | 2013 20:13:21 GMT - // | -> content-encoding: gzip - // 77 | == Literal indexed == - // | Indexed name (idx = 55) - // | set-cookie - // ad | Literal value (len = 45) - // | Huffman encoded: - // 94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 | .........5...[9` - // d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 | ..'..6r..'..)... - // 3160 65c0 03ed 4ee5 b106 3d50 07 | 1`e...N...=P. - // | Decoded: - // | foo=ASDJKHQKBZXOQWEOPIUAXQ - // | WEOIU; max-age=3600; versi - // | on=1 - // | - evict: location: - // | https://www.example.com - // | - evict: :status: 307 - // | -> set-cookie: foo=ASDJKHQ - // | KBZXOQWEOPIUAXQWEOIU; - // | max-age=3600; version=1 - SpdyString third = SpdyHexDecode( - "88c16196d07abe941054d444a8200595" - "040b8166e084a62d1bffc05a839bd9ab" - "77ad94e7821dd7f2e6c7b335dfdfcd5b" - "3960d5af27087f3672c1ab270fb5291f" - "9587316065c003ed4ee5b1063d5007"); - const SpdyHeaderBlock& third_header_set = DecodeBlockExpectingSuccess(third); - - EXPECT_THAT(third_header_set, - ElementsAre( - // clang-format off - Pair(":status", "200"), - Pair("cache-control", "private"), - Pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"), - Pair("location", "https://www.example.com"), - Pair("content-encoding", "gzip"), - Pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" - " max-age=3600; version=1"))); - // clang-format on - - expectEntry(62, 98, "set-cookie", - "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" - " max-age=3600; version=1"); - expectEntry(63, 52, "content-encoding", "gzip"); - expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT"); - EXPECT_EQ(215u, decoder_peer_.current_header_table_size()); -} - -// Regression test: Found that entries with dynamic indexed names and literal -// values caused "use after free" MSAN failures if the name was evicted as it -// was being re-used. -TEST_P(HpackDecoderAdapterTest, ReuseNameOfEvictedEntry) { - // Each entry is measured as 32 bytes plus the sum of the lengths of the name - // and the value. Set the size big enough for at most one entry, and a fairly - // small one at that (31 ASCII characters). - decoder_.ApplyHeaderTableSizeSetting(63); - - HpackBlockBuilder hbb; - hbb.AppendDynamicTableSizeUpdate(0); - hbb.AppendDynamicTableSizeUpdate(63); - - const SpdyStringPiece name("some-name"); - const SpdyStringPiece value1("some-value"); - const SpdyStringPiece value2("another-value"); - const SpdyStringPiece value3("yet-another-value"); - - // Add an entry that will become the first in the dynamic table, entry 62. - hbb.AppendLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader, false, - name, false, value1); - - // Confirm that entry has been added by re-using it. - hbb.AppendIndexedHeader(62); - - // Add another entry referring to the name of the first. This will evict the - // first. - hbb.AppendNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader, 62, - false, value2); - - // Confirm that entry has been added by re-using it. - hbb.AppendIndexedHeader(62); - - // Add another entry referring to the name of the second. This will evict the - // second. - hbb.AppendNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader, 62, - false, value3); - - // Confirm that entry has been added by re-using it. - hbb.AppendIndexedHeader(62); - - // Can't have DecodeHeaderBlock do the default check for size of the decoded - // data because SpdyHeaderBlock will join multiple headers with the same - // name into a single entry, thus we won't see repeated occurrences of the - // name, instead seeing separators between values. - EXPECT_TRUE(DecodeHeaderBlock(hbb.buffer(), kNoCheckDecodedSize)); - - SpdyHeaderBlock expected_header_set; - expected_header_set.AppendValueOrAddHeader(name, value1); - expected_header_set.AppendValueOrAddHeader(name, value1); - expected_header_set.AppendValueOrAddHeader(name, value2); - expected_header_set.AppendValueOrAddHeader(name, value2); - expected_header_set.AppendValueOrAddHeader(name, value3); - expected_header_set.AppendValueOrAddHeader(name, value3); - - // SpdyHeaderBlock stores these 6 strings as '\0' separated values. - // Make sure that is what happened. - SpdyString joined_values = expected_header_set[name].as_string(); - EXPECT_EQ(joined_values.size(), - 2 * value1.size() + 2 * value2.size() + 2 * value3.size() + 5); - - EXPECT_EQ(expected_header_set, decoded_block()); - - if (start_choice_ == START_WITH_HANDLER) { - EXPECT_EQ(handler_.header_bytes_parsed(), - 6 * name.size() + 2 * value1.size() + 2 * value2.size() + - 2 * value3.size()); - } -} - -// Regression test for https://crbug.com/747395. -TEST_P(HpackDecoderAdapterTest, Cookies) { - SpdyHeaderBlock expected_header_set; - expected_header_set["cookie"] = "foo; bar"; - - EXPECT_TRUE(DecodeHeaderBlock(SpdyHexDecode("608294e76003626172"))); - EXPECT_EQ(expected_header_set, decoded_block()); -} - -} // namespace -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_encoder.cc b/net/third_party/spdy/core/hpack/hpack_encoder.cc deleted file mode 100644 index fbf94a5..0000000 --- a/net/third_party/spdy/core/hpack/hpack_encoder.cc +++ /dev/null
@@ -1,365 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_encoder.h" - -#include <algorithm> -#include <limits> - -#include "base/logging.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/hpack/hpack_header_table.h" -#include "net/third_party/spdy/core/hpack/hpack_huffman_table.h" -#include "net/third_party/spdy/core/hpack/hpack_output_stream.h" -#include "net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h" -#include "net/third_party/spdy/platform/api/spdy_ptr_util.h" - -namespace spdy { - -class HpackEncoder::RepresentationIterator { - public: - // |pseudo_headers| and |regular_headers| must outlive the iterator. - RepresentationIterator(const Representations& pseudo_headers, - const Representations& regular_headers) - : pseudo_begin_(pseudo_headers.begin()), - pseudo_end_(pseudo_headers.end()), - regular_begin_(regular_headers.begin()), - regular_end_(regular_headers.end()) {} - - // |headers| must outlive the iterator. - explicit RepresentationIterator(const Representations& headers) - : pseudo_begin_(headers.begin()), - pseudo_end_(headers.end()), - regular_begin_(headers.end()), - regular_end_(headers.end()) {} - - bool HasNext() { - return pseudo_begin_ != pseudo_end_ || regular_begin_ != regular_end_; - } - - const Representation Next() { - if (pseudo_begin_ != pseudo_end_) { - return *pseudo_begin_++; - } else { - return *regular_begin_++; - } - } - - private: - Representations::const_iterator pseudo_begin_; - Representations::const_iterator pseudo_end_; - Representations::const_iterator regular_begin_; - Representations::const_iterator regular_end_; -}; - -namespace { - -// The default header listener. -void NoOpListener(SpdyStringPiece /*name*/, SpdyStringPiece /*value*/) {} - -// The default HPACK indexing policy. -bool DefaultPolicy(SpdyStringPiece name, SpdyStringPiece /* value */) { - if (name.empty()) { - return false; - } - // :authority is always present and rarely changes, and has moderate - // length, therefore it makes a lot of sense to index (insert in the - // dynamic table). - if (name[0] == kPseudoHeaderPrefix) { - return name == ":authority"; - } - return true; -} - -} // namespace - -HpackEncoder::HpackEncoder(const HpackHuffmanTable& table) - : output_stream_(), - huffman_table_(table), - min_table_size_setting_received_(std::numeric_limits<size_t>::max()), - listener_(NoOpListener), - should_index_(DefaultPolicy), - enable_compression_(true), - should_emit_table_size_(false) {} - -HpackEncoder::~HpackEncoder() = default; - -bool HpackEncoder::EncodeHeaderSet(const SpdyHeaderBlock& header_set, - SpdyString* output) { - // Separate header set into pseudo-headers and regular headers. - Representations pseudo_headers; - Representations regular_headers; - bool found_cookie = false; - for (const auto& header : header_set) { - if (!found_cookie && header.first == "cookie") { - // Note that there can only be one "cookie" header, because header_set is - // a map. - found_cookie = true; - CookieToCrumbs(header, ®ular_headers); - } else if (!header.first.empty() && - header.first[0] == kPseudoHeaderPrefix) { - DecomposeRepresentation(header, &pseudo_headers); - } else { - DecomposeRepresentation(header, ®ular_headers); - } - } - - { - RepresentationIterator iter(pseudo_headers, regular_headers); - EncodeRepresentations(&iter, output); - } - return true; -} - -void HpackEncoder::ApplyHeaderTableSizeSetting(size_t size_setting) { - if (size_setting == header_table_.settings_size_bound()) { - return; - } - if (size_setting < header_table_.settings_size_bound()) { - min_table_size_setting_received_ = - std::min(size_setting, min_table_size_setting_received_); - } - header_table_.SetSettingsHeaderTableSize(size_setting); - should_emit_table_size_ = true; -} - -size_t HpackEncoder::EstimateMemoryUsage() const { - // |huffman_table_| is a singleton. It's accounted for in spdy_session_pool.cc - return SpdyEstimateMemoryUsage(header_table_) + - SpdyEstimateMemoryUsage(output_stream_); -} - -void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter, - SpdyString* output) { - MaybeEmitTableSize(); - while (iter->HasNext()) { - const auto header = iter->Next(); - listener_(header.first, header.second); - if (enable_compression_) { - const HpackEntry* entry = - header_table_.GetByNameAndValue(header.first, header.second); - if (entry != nullptr) { - EmitIndex(entry); - } else if (should_index_(header.first, header.second)) { - EmitIndexedLiteral(header); - } else { - EmitNonIndexedLiteral(header); - } - } else { - EmitNonIndexedLiteral(header); - } - } - - output_stream_.TakeString(output); -} - -void HpackEncoder::EmitIndex(const HpackEntry* entry) { - DVLOG(2) << "Emitting index " << header_table_.IndexOf(entry); - output_stream_.AppendPrefix(kIndexedOpcode); - output_stream_.AppendUint32(header_table_.IndexOf(entry)); -} - -void HpackEncoder::EmitIndexedLiteral(const Representation& representation) { - DVLOG(2) << "Emitting indexed literal: (" << representation.first << ", " - << representation.second << ")"; - output_stream_.AppendPrefix(kLiteralIncrementalIndexOpcode); - EmitLiteral(representation); - header_table_.TryAddEntry(representation.first, representation.second); -} - -void HpackEncoder::EmitNonIndexedLiteral(const Representation& representation) { - DVLOG(2) << "Emitting nonindexed literal: (" << representation.first << ", " - << representation.second << ")"; - output_stream_.AppendPrefix(kLiteralNoIndexOpcode); - output_stream_.AppendUint32(0); - EmitString(representation.first); - EmitString(representation.second); -} - -void HpackEncoder::EmitLiteral(const Representation& representation) { - const HpackEntry* name_entry = header_table_.GetByName(representation.first); - if (name_entry != nullptr) { - output_stream_.AppendUint32(header_table_.IndexOf(name_entry)); - } else { - output_stream_.AppendUint32(0); - EmitString(representation.first); - } - EmitString(representation.second); -} - -void HpackEncoder::EmitString(SpdyStringPiece str) { - size_t encoded_size = - enable_compression_ ? huffman_table_.EncodedSize(str) : str.size(); - if (encoded_size < str.size()) { - DVLOG(2) << "Emitted Huffman-encoded string of length " << encoded_size; - output_stream_.AppendPrefix(kStringLiteralHuffmanEncoded); - output_stream_.AppendUint32(encoded_size); - huffman_table_.EncodeString(str, &output_stream_); - } else { - DVLOG(2) << "Emitted literal string of length " << str.size(); - output_stream_.AppendPrefix(kStringLiteralIdentityEncoded); - output_stream_.AppendUint32(str.size()); - output_stream_.AppendBytes(str); - } -} - -void HpackEncoder::MaybeEmitTableSize() { - if (!should_emit_table_size_) { - return; - } - const size_t current_size = CurrentHeaderTableSizeSetting(); - DVLOG(1) << "MaybeEmitTableSize current_size=" << current_size; - DVLOG(1) << "MaybeEmitTableSize min_table_size_setting_received_=" - << min_table_size_setting_received_; - if (min_table_size_setting_received_ < current_size) { - output_stream_.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream_.AppendUint32(min_table_size_setting_received_); - } - output_stream_.AppendPrefix(kHeaderTableSizeUpdateOpcode); - output_stream_.AppendUint32(current_size); - min_table_size_setting_received_ = std::numeric_limits<size_t>::max(); - should_emit_table_size_ = false; -} - -// static -void HpackEncoder::CookieToCrumbs(const Representation& cookie, - Representations* out) { - // See Section 8.1.2.5. "Compressing the Cookie Header Field" in the HTTP/2 - // specification at https://tools.ietf.org/html/draft-ietf-httpbis-http2-14. - // Cookie values are split into individually-encoded HPACK representations. - SpdyStringPiece cookie_value = cookie.second; - // Consume leading and trailing whitespace if present. - SpdyStringPiece::size_type first = cookie_value.find_first_not_of(" \t"); - SpdyStringPiece::size_type last = cookie_value.find_last_not_of(" \t"); - if (first == SpdyStringPiece::npos) { - cookie_value = SpdyStringPiece(); - } else { - cookie_value = cookie_value.substr(first, (last - first) + 1); - } - for (size_t pos = 0;;) { - size_t end = cookie_value.find(";", pos); - - if (end == SpdyStringPiece::npos) { - out->push_back(std::make_pair(cookie.first, cookie_value.substr(pos))); - break; - } - out->push_back( - std::make_pair(cookie.first, cookie_value.substr(pos, end - pos))); - - // Consume next space if present. - pos = end + 1; - if (pos != cookie_value.size() && cookie_value[pos] == ' ') { - pos++; - } - } -} - -// static -void HpackEncoder::DecomposeRepresentation(const Representation& header_field, - Representations* out) { - size_t pos = 0; - size_t end = 0; - while (end != SpdyStringPiece::npos) { - end = header_field.second.find('\0', pos); - out->push_back(std::make_pair( - header_field.first, - header_field.second.substr( - pos, end == SpdyStringPiece::npos ? end : end - pos))); - pos = end + 1; - } -} - -// static -void HpackEncoder::GatherRepresentation(const Representation& header_field, - Representations* out) { - out->push_back(std::make_pair(header_field.first, header_field.second)); -} - -// Iteratively encodes a SpdyHeaderBlock. -class HpackEncoder::Encoderator : public ProgressiveEncoder { - public: - Encoderator(const SpdyHeaderBlock& header_set, HpackEncoder* encoder); - - // Encoderator is neither copyable nor movable. - Encoderator(const Encoderator&) = delete; - Encoderator& operator=(const Encoderator&) = delete; - - // Returns true iff more remains to encode. - bool HasNext() const override { return has_next_; } - - // Encodes up to max_encoded_bytes of the current header block into the - // given output string. - void Next(size_t max_encoded_bytes, SpdyString* output) override; - - private: - HpackEncoder* encoder_; - std::unique_ptr<RepresentationIterator> header_it_; - Representations pseudo_headers_; - Representations regular_headers_; - bool has_next_; -}; - -HpackEncoder::Encoderator::Encoderator(const SpdyHeaderBlock& header_set, - HpackEncoder* encoder) - : encoder_(encoder), has_next_(true) { - // Separate header set into pseudo-headers and regular headers. - const bool use_compression = encoder_->enable_compression_; - bool found_cookie = false; - for (const auto& header : header_set) { - if (!found_cookie && header.first == "cookie") { - // Note that there can only be one "cookie" header, because header_set - // is a map. - found_cookie = true; - CookieToCrumbs(header, ®ular_headers_); - } else if (!header.first.empty() && - header.first[0] == kPseudoHeaderPrefix) { - use_compression ? DecomposeRepresentation(header, &pseudo_headers_) - : GatherRepresentation(header, &pseudo_headers_); - } else { - use_compression ? DecomposeRepresentation(header, ®ular_headers_) - : GatherRepresentation(header, ®ular_headers_); - } - } - header_it_ = - SpdyMakeUnique<RepresentationIterator>(pseudo_headers_, regular_headers_); - - encoder_->MaybeEmitTableSize(); -} - -void HpackEncoder::Encoderator::Next(size_t max_encoded_bytes, - SpdyString* output) { - SPDY_BUG_IF(!has_next_) - << "Encoderator::Next called with nothing left to encode."; - const bool use_compression = encoder_->enable_compression_; - - // Encode up to max_encoded_bytes of headers. - while (header_it_->HasNext() && - encoder_->output_stream_.size() <= max_encoded_bytes) { - const Representation header = header_it_->Next(); - encoder_->listener_(header.first, header.second); - if (use_compression) { - const HpackEntry* entry = encoder_->header_table_.GetByNameAndValue( - header.first, header.second); - if (entry != nullptr) { - encoder_->EmitIndex(entry); - } else if (encoder_->should_index_(header.first, header.second)) { - encoder_->EmitIndexedLiteral(header); - } else { - encoder_->EmitNonIndexedLiteral(header); - } - } else { - encoder_->EmitNonIndexedLiteral(header); - } - } - - has_next_ = encoder_->output_stream_.size() > max_encoded_bytes; - encoder_->output_stream_.BoundedTakeString(max_encoded_bytes, output); -} - -std::unique_ptr<HpackEncoder::ProgressiveEncoder> HpackEncoder::EncodeHeaderSet( - const SpdyHeaderBlock& header_set) { - return SpdyMakeUnique<Encoderator>(header_set, this); -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_encoder.h b/net/third_party/spdy/core/hpack/hpack_encoder.h deleted file mode 100644 index 1843ea5..0000000 --- a/net/third_party/spdy/core/hpack/hpack_encoder.h +++ /dev/null
@@ -1,152 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_ENCODER_H_ -#define NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_ENCODER_H_ - -#include <stddef.h> - -#include <functional> -#include <map> -#include <memory> -#include <utility> -#include <vector> - -#include "base/macros.h" -#include "net/third_party/spdy/core/hpack/hpack_header_table.h" -#include "net/third_party/spdy/core/hpack/hpack_output_stream.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -// An HpackEncoder encodes header sets as outlined in -// http://tools.ietf.org/html/rfc7541. - -namespace spdy { - -class HpackHuffmanTable; - -namespace test { -class HpackEncoderPeer; -} // namespace test - -class SPDY_EXPORT_PRIVATE HpackEncoder { - public: - using Representation = std::pair<SpdyStringPiece, SpdyStringPiece>; - using Representations = std::vector<Representation>; - - // Callers may provide a HeaderListener to be informed of header name-value - // pairs processed by this encoder. - using HeaderListener = std::function<void(SpdyStringPiece, SpdyStringPiece)>; - - // An indexing policy should return true if the provided header name-value - // pair should be inserted into the HPACK dynamic table. - using IndexingPolicy = std::function<bool(SpdyStringPiece, SpdyStringPiece)>; - - // |table| is an initialized HPACK Huffman table, having an - // externally-managed lifetime which spans beyond HpackEncoder. - explicit HpackEncoder(const HpackHuffmanTable& table); - HpackEncoder(const HpackEncoder&) = delete; - HpackEncoder& operator=(const HpackEncoder&) = delete; - ~HpackEncoder(); - - // Encodes the given header set into the given string. Returns - // whether or not the encoding was successful. - bool EncodeHeaderSet(const SpdyHeaderBlock& header_set, SpdyString* output); - - class SPDY_EXPORT_PRIVATE ProgressiveEncoder { - public: - virtual ~ProgressiveEncoder() {} - - // Returns true iff more remains to encode. - virtual bool HasNext() const = 0; - - // Encodes up to max_encoded_bytes of the current header block into the - // given output string. - virtual void Next(size_t max_encoded_bytes, SpdyString* output) = 0; - }; - - // Returns a ProgressiveEncoder which must be outlived by both the given - // SpdyHeaderBlock and this object. - std::unique_ptr<ProgressiveEncoder> EncodeHeaderSet( - const SpdyHeaderBlock& header_set); - - // Called upon a change to SETTINGS_HEADER_TABLE_SIZE. Specifically, this - // is to be called after receiving (and sending an acknowledgement for) a - // SETTINGS_HEADER_TABLE_SIZE update from the remote decoding endpoint. - void ApplyHeaderTableSizeSetting(size_t size_setting); - - size_t CurrentHeaderTableSizeSetting() const { - return header_table_.settings_size_bound(); - } - - // This HpackEncoder will use |policy| to determine whether to insert header - // name-value pairs into the dynamic table. - void SetIndexingPolicy(IndexingPolicy policy) { should_index_ = policy; } - - // |listener| will be invoked for each header name-value pair processed by - // this encoder. - void SetHeaderListener(HeaderListener listener) { listener_ = listener; } - - void SetHeaderTableDebugVisitor( - std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) { - header_table_.set_debug_visitor(std::move(visitor)); - } - - void DisableCompression() { enable_compression_ = false; } - - // Returns the estimate of dynamically allocated memory in bytes. - size_t EstimateMemoryUsage() const; - - private: - friend class test::HpackEncoderPeer; - - class RepresentationIterator; - class Encoderator; - - // Encodes a sequence of header name-value pairs as a single header block. - void EncodeRepresentations(RepresentationIterator* iter, SpdyString* output); - - // Emits a static/dynamic indexed representation (Section 7.1). - void EmitIndex(const HpackEntry* entry); - - // Emits a literal representation (Section 7.2). - void EmitIndexedLiteral(const Representation& representation); - void EmitNonIndexedLiteral(const Representation& representation); - void EmitLiteral(const Representation& representation); - - // Emits a Huffman or identity string (whichever is smaller). - void EmitString(SpdyStringPiece str); - - // Emits the current dynamic table size if the table size was recently - // updated and we have not yet emitted it (Section 6.3). - void MaybeEmitTableSize(); - - // Crumbles a cookie header into ";" delimited crumbs. - static void CookieToCrumbs(const Representation& cookie, - Representations* crumbs_out); - - // Crumbles other header field values at \0 delimiters. - static void DecomposeRepresentation(const Representation& header_field, - Representations* out); - - // Gathers headers without crumbling. Used when compression is not enabled. - static void GatherRepresentation(const Representation& header_field, - Representations* out); - - HpackHeaderTable header_table_; - HpackOutputStream output_stream_; - - const HpackHuffmanTable& huffman_table_; - size_t min_table_size_setting_received_; - HeaderListener listener_; - IndexingPolicy should_index_; - bool enable_compression_; - bool should_emit_table_size_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_ENCODER_H_
diff --git a/net/third_party/spdy/core/hpack/hpack_encoder_test.cc b/net/third_party/spdy/core/hpack/hpack_encoder_test.cc deleted file mode 100644 index a8c6915..0000000 --- a/net/third_party/spdy/core/hpack/hpack_encoder_test.cc +++ /dev/null
@@ -1,586 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_encoder.h" - -#include <cstdint> -#include <map> - -#include "net/third_party/quiche/src/http2/test_tools/http2_random.h" -#include "net/third_party/spdy/core/hpack/hpack_huffman_table.h" -#include "net/third_party/spdy/platform/api/spdy_unsafe_arena.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -namespace test { - -class HpackHeaderTablePeer { - public: - explicit HpackHeaderTablePeer(HpackHeaderTable* table) : table_(table) {} - - HpackHeaderTable::EntryTable* dynamic_entries() { - return &table_->dynamic_entries_; - } - - private: - HpackHeaderTable* table_; -}; - -class HpackEncoderPeer { - public: - typedef HpackEncoder::Representation Representation; - typedef HpackEncoder::Representations Representations; - - explicit HpackEncoderPeer(HpackEncoder* encoder) : encoder_(encoder) {} - - bool compression_enabled() const { return encoder_->enable_compression_; } - HpackHeaderTable* table() { return &encoder_->header_table_; } - HpackHeaderTablePeer table_peer() { return HpackHeaderTablePeer(table()); } - const HpackHuffmanTable& huffman_table() const { - return encoder_->huffman_table_; - } - void EmitString(SpdyStringPiece str) { encoder_->EmitString(str); } - void TakeString(SpdyString* out) { encoder_->output_stream_.TakeString(out); } - static void CookieToCrumbs(SpdyStringPiece cookie, - std::vector<SpdyStringPiece>* out) { - Representations tmp; - HpackEncoder::CookieToCrumbs(std::make_pair("", cookie), &tmp); - - out->clear(); - for (size_t i = 0; i != tmp.size(); ++i) { - out->push_back(tmp[i].second); - } - } - static void DecomposeRepresentation(SpdyStringPiece value, - std::vector<SpdyStringPiece>* out) { - Representations tmp; - HpackEncoder::DecomposeRepresentation(std::make_pair("foobar", value), - &tmp); - - out->clear(); - for (size_t i = 0; i != tmp.size(); ++i) { - out->push_back(tmp[i].second); - } - } - - // TODO(dahollings): Remove or clean up these methods when deprecating - // non-incremental encoding path. - static bool EncodeHeaderSet(HpackEncoder* encoder, - const SpdyHeaderBlock& header_set, - SpdyString* output, - bool use_incremental) { - if (use_incremental) { - return EncodeIncremental(encoder, header_set, output); - } else { - return encoder->EncodeHeaderSet(header_set, output); - } - } - - static bool EncodeIncremental(HpackEncoder* encoder, - const SpdyHeaderBlock& header_set, - SpdyString* output) { - std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoderator = - encoder->EncodeHeaderSet(header_set); - SpdyString output_buffer; - http2::test::Http2Random random; - encoderator->Next(random.UniformInRange(0, 16), &output_buffer); - while (encoderator->HasNext()) { - SpdyString second_buffer; - encoderator->Next(random.UniformInRange(0, 16), &second_buffer); - output_buffer.append(second_buffer); - } - *output = std::move(output_buffer); - return true; - } - - private: - HpackEncoder* encoder_; -}; - -} // namespace test - -namespace { - -using testing::ElementsAre; -using testing::Pair; - -class HpackEncoderTest : public ::testing::TestWithParam<bool> { - protected: - typedef test::HpackEncoderPeer::Representations Representations; - - HpackEncoderTest() - : encoder_(ObtainHpackHuffmanTable()), - peer_(&encoder_), - static_(peer_.table()->GetByIndex(1)), - headers_storage_(1024 /* block size */) {} - - void SetUp() override { - use_incremental_ = GetParam(); - - // Populate dynamic entries into the table fixture. For simplicity each - // entry has name.size() + value.size() == 10. - key_1_ = peer_.table()->TryAddEntry("key1", "value1"); - key_2_ = peer_.table()->TryAddEntry("key2", "value2"); - cookie_a_ = peer_.table()->TryAddEntry("cookie", "a=bb"); - cookie_c_ = peer_.table()->TryAddEntry("cookie", "c=dd"); - - // No further insertions may occur without evictions. - peer_.table()->SetMaxSize(peer_.table()->size()); - } - - void SaveHeaders(SpdyStringPiece name, SpdyStringPiece value) { - SpdyStringPiece n(headers_storage_.Memdup(name.data(), name.size()), - name.size()); - SpdyStringPiece v(headers_storage_.Memdup(value.data(), value.size()), - value.size()); - headers_observed_.push_back(std::make_pair(n, v)); - } - - void ExpectIndex(size_t index) { - expected_.AppendPrefix(kIndexedOpcode); - expected_.AppendUint32(index); - } - void ExpectIndexedLiteral(const HpackEntry* key_entry, - SpdyStringPiece value) { - expected_.AppendPrefix(kLiteralIncrementalIndexOpcode); - expected_.AppendUint32(IndexOf(key_entry)); - ExpectString(&expected_, value); - } - void ExpectIndexedLiteral(SpdyStringPiece name, SpdyStringPiece value) { - expected_.AppendPrefix(kLiteralIncrementalIndexOpcode); - expected_.AppendUint32(0); - ExpectString(&expected_, name); - ExpectString(&expected_, value); - } - void ExpectNonIndexedLiteral(SpdyStringPiece name, SpdyStringPiece value) { - expected_.AppendPrefix(kLiteralNoIndexOpcode); - expected_.AppendUint32(0); - ExpectString(&expected_, name); - ExpectString(&expected_, value); - } - void ExpectString(HpackOutputStream* stream, SpdyStringPiece str) { - const HpackHuffmanTable& huffman_table = peer_.huffman_table(); - size_t encoded_size = peer_.compression_enabled() - ? huffman_table.EncodedSize(str) - : str.size(); - if (encoded_size < str.size()) { - expected_.AppendPrefix(kStringLiteralHuffmanEncoded); - expected_.AppendUint32(encoded_size); - huffman_table.EncodeString(str, stream); - } else { - expected_.AppendPrefix(kStringLiteralIdentityEncoded); - expected_.AppendUint32(str.size()); - expected_.AppendBytes(str); - } - } - void ExpectHeaderTableSizeUpdate(uint32_t size) { - expected_.AppendPrefix(kHeaderTableSizeUpdateOpcode); - expected_.AppendUint32(size); - } - void CompareWithExpectedEncoding(const SpdyHeaderBlock& header_set) { - SpdyString expected_out, actual_out; - expected_.TakeString(&expected_out); - EXPECT_TRUE(test::HpackEncoderPeer::EncodeHeaderSet( - &encoder_, header_set, &actual_out, use_incremental_)); - EXPECT_EQ(expected_out, actual_out); - } - size_t IndexOf(const HpackEntry* entry) { - return peer_.table()->IndexOf(entry); - } - - HpackEncoder encoder_; - test::HpackEncoderPeer peer_; - - const HpackEntry* static_; - const HpackEntry* key_1_; - const HpackEntry* key_2_; - const HpackEntry* cookie_a_; - const HpackEntry* cookie_c_; - - SpdyUnsafeArena headers_storage_; - std::vector<std::pair<SpdyStringPiece, SpdyStringPiece>> headers_observed_; - - HpackOutputStream expected_; - bool use_incremental_; -}; - -INSTANTIATE_TEST_CASE_P(HpackEncoderTests, HpackEncoderTest, ::testing::Bool()); - -TEST_P(HpackEncoderTest, SingleDynamicIndex) { - encoder_.SetHeaderListener( - [this](SpdyStringPiece name, SpdyStringPiece value) { - this->SaveHeaders(name, value); - }); - - ExpectIndex(IndexOf(key_2_)); - - SpdyHeaderBlock headers; - headers[key_2_->name()] = key_2_->value(); - CompareWithExpectedEncoding(headers); - EXPECT_THAT(headers_observed_, - ElementsAre(Pair(key_2_->name(), key_2_->value()))); -} - -TEST_P(HpackEncoderTest, SingleStaticIndex) { - ExpectIndex(IndexOf(static_)); - - SpdyHeaderBlock headers; - headers[static_->name()] = static_->value(); - CompareWithExpectedEncoding(headers); -} - -TEST_P(HpackEncoderTest, SingleStaticIndexTooLarge) { - peer_.table()->SetMaxSize(1); // Also evicts all fixtures. - ExpectIndex(IndexOf(static_)); - - SpdyHeaderBlock headers; - headers[static_->name()] = static_->value(); - CompareWithExpectedEncoding(headers); - - EXPECT_EQ(0u, peer_.table_peer().dynamic_entries()->size()); -} - -TEST_P(HpackEncoderTest, SingleLiteralWithIndexName) { - ExpectIndexedLiteral(key_2_, "value3"); - - SpdyHeaderBlock headers; - headers[key_2_->name()] = "value3"; - CompareWithExpectedEncoding(headers); - - // A new entry was inserted and added to the reference set. - HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); - EXPECT_EQ(new_entry->name(), key_2_->name()); - EXPECT_EQ(new_entry->value(), "value3"); -} - -TEST_P(HpackEncoderTest, SingleLiteralWithLiteralName) { - ExpectIndexedLiteral("key3", "value3"); - - SpdyHeaderBlock headers; - headers["key3"] = "value3"; - CompareWithExpectedEncoding(headers); - - HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); - EXPECT_EQ(new_entry->name(), "key3"); - EXPECT_EQ(new_entry->value(), "value3"); -} - -TEST_P(HpackEncoderTest, SingleLiteralTooLarge) { - peer_.table()->SetMaxSize(1); // Also evicts all fixtures. - - ExpectIndexedLiteral("key3", "value3"); - - // A header overflowing the header table is still emitted. - // The header table is empty. - SpdyHeaderBlock headers; - headers["key3"] = "value3"; - CompareWithExpectedEncoding(headers); - - EXPECT_EQ(0u, peer_.table_peer().dynamic_entries()->size()); -} - -TEST_P(HpackEncoderTest, EmitThanEvict) { - // |key_1_| is toggled and placed into the reference set, - // and then immediately evicted by "key3". - ExpectIndex(IndexOf(key_1_)); - ExpectIndexedLiteral("key3", "value3"); - - SpdyHeaderBlock headers; - headers[key_1_->name()] = key_1_->value(); - headers["key3"] = "value3"; - CompareWithExpectedEncoding(headers); -} - -TEST_P(HpackEncoderTest, CookieHeaderIsCrumbled) { - ExpectIndex(IndexOf(cookie_a_)); - ExpectIndex(IndexOf(cookie_c_)); - ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "e=ff"); - - SpdyHeaderBlock headers; - headers["cookie"] = "a=bb; c=dd; e=ff"; - CompareWithExpectedEncoding(headers); -} - -TEST_P(HpackEncoderTest, StringsDynamicallySelectHuffmanCoding) { - // Compactable string. Uses Huffman coding. - peer_.EmitString("feedbeef"); - expected_.AppendPrefix(kStringLiteralHuffmanEncoded); - expected_.AppendUint32(6); - expected_.AppendBytes("\x94\xA5\x92\x32\x96_"); - - // Non-compactable. Uses identity coding. - peer_.EmitString("@@@@@@"); - expected_.AppendPrefix(kStringLiteralIdentityEncoded); - expected_.AppendUint32(6); - expected_.AppendBytes("@@@@@@"); - - SpdyString expected_out, actual_out; - expected_.TakeString(&expected_out); - peer_.TakeString(&actual_out); - EXPECT_EQ(expected_out, actual_out); -} - -TEST_P(HpackEncoderTest, EncodingWithoutCompression) { - encoder_.SetHeaderListener( - [this](SpdyStringPiece name, SpdyStringPiece value) { - this->SaveHeaders(name, value); - }); - encoder_.DisableCompression(); - - ExpectNonIndexedLiteral(":path", "/index.html"); - ExpectNonIndexedLiteral("cookie", "foo=bar"); - ExpectNonIndexedLiteral("cookie", "baz=bing"); - ExpectNonIndexedLiteral("hello", "goodbye"); - - SpdyHeaderBlock headers; - headers[":path"] = "/index.html"; - headers["cookie"] = "foo=bar; baz=bing"; - headers["hello"] = "goodbye"; - - CompareWithExpectedEncoding(headers); - - EXPECT_THAT( - headers_observed_, - ElementsAre(Pair(":path", "/index.html"), Pair("cookie", "foo=bar"), - Pair("cookie", "baz=bing"), Pair("hello", "goodbye"))); -} - -TEST_P(HpackEncoderTest, MultipleEncodingPasses) { - encoder_.SetHeaderListener( - [this](SpdyStringPiece name, SpdyStringPiece value) { - this->SaveHeaders(name, value); - }); - - // Pass 1. - { - SpdyHeaderBlock headers; - headers["key1"] = "value1"; - headers["cookie"] = "a=bb"; - - ExpectIndex(IndexOf(key_1_)); - ExpectIndex(IndexOf(cookie_a_)); - CompareWithExpectedEncoding(headers); - } - // Header table is: - // 65: key1: value1 - // 64: key2: value2 - // 63: cookie: a=bb - // 62: cookie: c=dd - // Pass 2. - { - SpdyHeaderBlock headers; - headers["key2"] = "value2"; - headers["cookie"] = "c=dd; e=ff"; - - // "key2: value2" - ExpectIndex(64); - // "cookie: c=dd" - ExpectIndex(62); - // This cookie evicts |key1| from the dynamic table. - ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "e=ff"); - - CompareWithExpectedEncoding(headers); - } - // Header table is: - // 65: key2: value2 - // 64: cookie: a=bb - // 63: cookie: c=dd - // 62: cookie: e=ff - // Pass 3. - { - SpdyHeaderBlock headers; - headers["key2"] = "value2"; - headers["cookie"] = "a=bb; b=cc; c=dd"; - - // "key2: value2" - ExpectIndex(65); - // "cookie: a=bb" - ExpectIndex(64); - // This cookie evicts |key2| from the dynamic table. - ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "b=cc"); - // "cookie: c=dd" - ExpectIndex(64); - - CompareWithExpectedEncoding(headers); - } - - // clang-format off - EXPECT_THAT(headers_observed_, - ElementsAre(Pair("key1", "value1"), - Pair("cookie", "a=bb"), - Pair("key2", "value2"), - Pair("cookie", "c=dd"), - Pair("cookie", "e=ff"), - Pair("key2", "value2"), - Pair("cookie", "a=bb"), - Pair("cookie", "b=cc"), - Pair("cookie", "c=dd"))); - // clang-format on -} - -TEST_P(HpackEncoderTest, PseudoHeadersFirst) { - SpdyHeaderBlock headers; - // A pseudo-header that should not be indexed. - headers[":path"] = "/spam/eggs.html"; - // A pseudo-header to be indexed. - headers[":authority"] = "www.example.com"; - // A regular header which precedes ":" alphabetically, should still be encoded - // after pseudo-headers. - headers["-foo"] = "bar"; - headers["foo"] = "bar"; - headers["cookie"] = "c=dd"; - - // Headers are indexed in the order in which they were added. - // This entry pushes "cookie: a=bb" back to 63. - ExpectNonIndexedLiteral(":path", "/spam/eggs.html"); - ExpectIndexedLiteral(peer_.table()->GetByName(":authority"), - "www.example.com"); - ExpectIndexedLiteral("-foo", "bar"); - ExpectIndexedLiteral("foo", "bar"); - ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "c=dd"); - CompareWithExpectedEncoding(headers); -} - -TEST_P(HpackEncoderTest, CookieToCrumbs) { - test::HpackEncoderPeer peer(nullptr); - std::vector<SpdyStringPiece> out; - - // Leading and trailing whitespace is consumed. A space after ';' is consumed. - // All other spaces remain. ';' at beginning and end of string produce empty - // crumbs. - // See section 8.1.3.4 "Compressing the Cookie Header Field" in the HTTP/2 - // specification at http://tools.ietf.org/html/draft-ietf-httpbis-http2-11 - peer.CookieToCrumbs(" foo=1;bar=2 ; bar=3; bing=4; ", &out); - EXPECT_THAT(out, ElementsAre("foo=1", "bar=2 ", "bar=3", " bing=4", "")); - - peer.CookieToCrumbs(";;foo = bar ;; ;baz =bing", &out); - EXPECT_THAT(out, ElementsAre("", "", "foo = bar ", "", "", "baz =bing")); - - peer.CookieToCrumbs("baz=bing; foo=bar; baz=bing", &out); - EXPECT_THAT(out, ElementsAre("baz=bing", "foo=bar", "baz=bing")); - - peer.CookieToCrumbs("baz=bing", &out); - EXPECT_THAT(out, ElementsAre("baz=bing")); - - peer.CookieToCrumbs("", &out); - EXPECT_THAT(out, ElementsAre("")); - - peer.CookieToCrumbs("foo;bar; baz;baz;bing;", &out); - EXPECT_THAT(out, ElementsAre("foo", "bar", "baz", "baz", "bing", "")); - - peer.CookieToCrumbs(" \t foo=1;bar=2 ; bar=3;\t ", &out); - EXPECT_THAT(out, ElementsAre("foo=1", "bar=2 ", "bar=3", "")); - - peer.CookieToCrumbs(" \t foo=1;bar=2 ; bar=3 \t ", &out); - EXPECT_THAT(out, ElementsAre("foo=1", "bar=2 ", "bar=3")); -} - -TEST_P(HpackEncoderTest, DecomposeRepresentation) { - test::HpackEncoderPeer peer(nullptr); - std::vector<SpdyStringPiece> out; - - peer.DecomposeRepresentation("", &out); - EXPECT_THAT(out, ElementsAre("")); - - peer.DecomposeRepresentation("foobar", &out); - EXPECT_THAT(out, ElementsAre("foobar")); - - peer.DecomposeRepresentation(SpdyStringPiece("foo\0bar", 7), &out); - EXPECT_THAT(out, ElementsAre("foo", "bar")); - - peer.DecomposeRepresentation(SpdyStringPiece("\0foo\0bar", 8), &out); - EXPECT_THAT(out, ElementsAre("", "foo", "bar")); - - peer.DecomposeRepresentation(SpdyStringPiece("foo\0bar\0", 8), &out); - EXPECT_THAT(out, ElementsAre("foo", "bar", "")); - - peer.DecomposeRepresentation(SpdyStringPiece("\0foo\0bar\0", 9), &out); - EXPECT_THAT(out, ElementsAre("", "foo", "bar", "")); -} - -// Test that encoded headers do not have \0-delimited multiple values, as this -// became disallowed in HTTP/2 draft-14. -TEST_P(HpackEncoderTest, CrumbleNullByteDelimitedValue) { - SpdyHeaderBlock headers; - // A header field to be crumbled: "spam: foo\0bar". - headers["spam"] = SpdyString("foo\0bar", 7); - - ExpectIndexedLiteral("spam", "foo"); - expected_.AppendPrefix(kLiteralIncrementalIndexOpcode); - expected_.AppendUint32(62); - expected_.AppendPrefix(kStringLiteralIdentityEncoded); - expected_.AppendUint32(3); - expected_.AppendBytes("bar"); - CompareWithExpectedEncoding(headers); -} - -TEST_P(HpackEncoderTest, HeaderTableSizeUpdate) { - encoder_.ApplyHeaderTableSizeSetting(1024); - ExpectHeaderTableSizeUpdate(1024); - ExpectIndexedLiteral("key3", "value3"); - - SpdyHeaderBlock headers; - headers["key3"] = "value3"; - CompareWithExpectedEncoding(headers); - - HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); - EXPECT_EQ(new_entry->name(), "key3"); - EXPECT_EQ(new_entry->value(), "value3"); -} - -TEST_P(HpackEncoderTest, HeaderTableSizeUpdateWithMin) { - const size_t starting_size = peer_.table()->settings_size_bound(); - encoder_.ApplyHeaderTableSizeSetting(starting_size - 2); - encoder_.ApplyHeaderTableSizeSetting(starting_size - 1); - // We must encode the low watermark, so the peer knows to evict entries - // if necessary. - ExpectHeaderTableSizeUpdate(starting_size - 2); - ExpectHeaderTableSizeUpdate(starting_size - 1); - ExpectIndexedLiteral("key3", "value3"); - - SpdyHeaderBlock headers; - headers["key3"] = "value3"; - CompareWithExpectedEncoding(headers); - - HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); - EXPECT_EQ(new_entry->name(), "key3"); - EXPECT_EQ(new_entry->value(), "value3"); -} - -TEST_P(HpackEncoderTest, HeaderTableSizeUpdateWithExistingSize) { - encoder_.ApplyHeaderTableSizeSetting(peer_.table()->settings_size_bound()); - // No encoded size update. - ExpectIndexedLiteral("key3", "value3"); - - SpdyHeaderBlock headers; - headers["key3"] = "value3"; - CompareWithExpectedEncoding(headers); - - HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); - EXPECT_EQ(new_entry->name(), "key3"); - EXPECT_EQ(new_entry->value(), "value3"); -} - -TEST_P(HpackEncoderTest, HeaderTableSizeUpdatesWithGreaterSize) { - const size_t starting_size = peer_.table()->settings_size_bound(); - encoder_.ApplyHeaderTableSizeSetting(starting_size + 1); - encoder_.ApplyHeaderTableSizeSetting(starting_size + 2); - // Only a single size update to the final size. - ExpectHeaderTableSizeUpdate(starting_size + 2); - ExpectIndexedLiteral("key3", "value3"); - - SpdyHeaderBlock headers; - headers["key3"] = "value3"; - CompareWithExpectedEncoding(headers); - - HpackEntry* new_entry = &peer_.table_peer().dynamic_entries()->front(); - EXPECT_EQ(new_entry->name(), "key3"); - EXPECT_EQ(new_entry->value(), "value3"); -} - -} // namespace - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_entry.cc b/net/third_party/spdy/core/hpack/hpack_entry.cc deleted file mode 100644 index bebde49..0000000 --- a/net/third_party/spdy/core/hpack/hpack_entry.cc +++ /dev/null
@@ -1,89 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_entry.h" - -#include "base/logging.h" -#include "net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h" -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" - -namespace spdy { - -const size_t HpackEntry::kSizeOverhead = 32; - -HpackEntry::HpackEntry(SpdyStringPiece name, - SpdyStringPiece value, - bool is_static, - size_t insertion_index) - : name_(name.data(), name.size()), - value_(value.data(), value.size()), - name_ref_(name_), - value_ref_(value_), - insertion_index_(insertion_index), - type_(is_static ? STATIC : DYNAMIC), - time_added_(0) {} - -HpackEntry::HpackEntry(SpdyStringPiece name, SpdyStringPiece value) - : name_ref_(name), - value_ref_(value), - insertion_index_(0), - type_(LOOKUP), - time_added_(0) {} - -HpackEntry::HpackEntry() : insertion_index_(0), type_(LOOKUP), time_added_(0) {} - -HpackEntry::HpackEntry(const HpackEntry& other) - : insertion_index_(other.insertion_index_), - type_(other.type_), - time_added_(0) { - if (type_ == LOOKUP) { - name_ref_ = other.name_ref_; - value_ref_ = other.value_ref_; - } else { - name_ = other.name_; - value_ = other.value_; - name_ref_ = SpdyStringPiece(name_.data(), name_.size()); - value_ref_ = SpdyStringPiece(value_.data(), value_.size()); - } -} - -HpackEntry& HpackEntry::operator=(const HpackEntry& other) { - insertion_index_ = other.insertion_index_; - type_ = other.type_; - if (type_ == LOOKUP) { - name_.clear(); - value_.clear(); - name_ref_ = other.name_ref_; - value_ref_ = other.value_ref_; - return *this; - } - name_ = other.name_; - value_ = other.value_; - name_ref_ = SpdyStringPiece(name_.data(), name_.size()); - value_ref_ = SpdyStringPiece(value_.data(), value_.size()); - return *this; -} - -HpackEntry::~HpackEntry() = default; - -// static -size_t HpackEntry::Size(SpdyStringPiece name, SpdyStringPiece value) { - return name.size() + value.size() + kSizeOverhead; -} -size_t HpackEntry::Size() const { - return Size(name(), value()); -} - -SpdyString HpackEntry::GetDebugString() const { - return SpdyStrCat( - "{ name: \"", name_ref_, "\", value: \"", value_ref_, - "\", index: ", insertion_index_, " ", - (IsStatic() ? " static" : (IsLookup() ? " lookup" : " dynamic")), " }"); -} - -size_t HpackEntry::EstimateMemoryUsage() const { - return SpdyEstimateMemoryUsage(name_) + SpdyEstimateMemoryUsage(value_); -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_entry.h b/net/third_party/spdy/core/hpack/hpack_entry.h deleted file mode 100644 index 9829b91d..0000000 --- a/net/third_party/spdy/core/hpack/hpack_entry.h +++ /dev/null
@@ -1,110 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_ENTRY_H_ -#define NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_ENTRY_H_ - -#include <cstddef> -#include <cstdint> - -#include "base/macros.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -// All section references below are to -// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08 - -namespace spdy { - -// A structure for an entry in the static table (3.3.1) -// and the header table (3.3.2). -class SPDY_EXPORT_PRIVATE HpackEntry { - public: - // The constant amount added to name().size() and value().size() to - // get the size of an HpackEntry as defined in 5.1. - static const size_t kSizeOverhead; - - // Creates an entry. Preconditions: - // - |is_static| captures whether this entry is a member of the static - // or dynamic header table. - // - |insertion_index| is this entry's index in the total set of entries ever - // inserted into the header table (including static entries). - // - // The combination of |is_static| and |insertion_index| allows an - // HpackEntryTable to determine the index of an HpackEntry in O(1) time. - // Copies |name| and |value|. - HpackEntry(SpdyStringPiece name, - SpdyStringPiece value, - bool is_static, - size_t insertion_index); - - // Create a 'lookup' entry (only) suitable for querying a HpackEntrySet. The - // instance InsertionIndex() always returns 0 and IsLookup() returns true. - // The memory backing |name| and |value| must outlive this object. - HpackEntry(SpdyStringPiece name, SpdyStringPiece value); - - HpackEntry(const HpackEntry& other); - HpackEntry& operator=(const HpackEntry& other); - - // Creates an entry with empty name and value. Only defined so that - // entries can be stored in STL containers. - HpackEntry(); - - ~HpackEntry(); - - SpdyStringPiece name() const { return name_ref_; } - SpdyStringPiece value() const { return value_ref_; } - - // Returns whether this entry is a member of the static (as opposed to - // dynamic) table. - bool IsStatic() const { return type_ == STATIC; } - - // Returns whether this entry is a lookup-only entry. - bool IsLookup() const { return type_ == LOOKUP; } - - // Used to compute the entry's index in the header table. - size_t InsertionIndex() const { return insertion_index_; } - - // Returns the size of an entry as defined in 5.1. - static size_t Size(SpdyStringPiece name, SpdyStringPiece value); - size_t Size() const; - - SpdyString GetDebugString() const; - - int64_t time_added() const { return time_added_; } - void set_time_added(int64_t now) { time_added_ = now; } - - // Returns the estimate of dynamically allocated memory in bytes. - size_t EstimateMemoryUsage() const; - - private: - enum EntryType { - LOOKUP, - DYNAMIC, - STATIC, - }; - - // These members are not used for LOOKUP entries. - SpdyString name_; - SpdyString value_; - - // These members are always valid. For DYNAMIC and STATIC entries, they - // always point to |name_| and |value_|. - SpdyStringPiece name_ref_; - SpdyStringPiece value_ref_; - - // The entry's index in the total set of entries ever inserted into the header - // table. - size_t insertion_index_; - - EntryType type_; - - // For HpackHeaderTable::DebugVisitorInterface - int64_t time_added_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_ENTRY_H_
diff --git a/net/third_party/spdy/core/hpack/hpack_entry_test.cc b/net/third_party/spdy/core/hpack/hpack_entry_test.cc deleted file mode 100644 index b8357ce..0000000 --- a/net/third_party/spdy/core/hpack/hpack_entry_test.cc +++ /dev/null
@@ -1,122 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_entry.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -namespace { - -class HpackEntryTest : public ::testing::Test { - protected: - HpackEntryTest() - : name_("header-name"), - value_("header value"), - total_insertions_(0), - table_size_(0) {} - - // These builders maintain the same external table invariants that a "real" - // table (ie HpackHeaderTable) would. - HpackEntry StaticEntry() { - return HpackEntry(name_, value_, true, total_insertions_++); - } - HpackEntry DynamicEntry() { - ++table_size_; - size_t index = total_insertions_++; - return HpackEntry(name_, value_, false, index); - } - void DropEntry() { --table_size_; } - - size_t IndexOf(const HpackEntry& entry) const { - if (entry.IsStatic()) { - return 1 + entry.InsertionIndex() + table_size_; - } else { - return total_insertions_ - entry.InsertionIndex(); - } - } - - size_t Size() { - return name_.size() + value_.size() + HpackEntry::kSizeOverhead; - } - - SpdyString name_, value_; - - private: - // Referenced by HpackEntry instances. - size_t total_insertions_; - size_t table_size_; -}; - -TEST_F(HpackEntryTest, StaticConstructor) { - HpackEntry entry(StaticEntry()); - - EXPECT_EQ(name_, entry.name()); - EXPECT_EQ(value_, entry.value()); - EXPECT_TRUE(entry.IsStatic()); - EXPECT_EQ(1u, IndexOf(entry)); - EXPECT_EQ(Size(), entry.Size()); -} - -TEST_F(HpackEntryTest, DynamicConstructor) { - HpackEntry entry(DynamicEntry()); - - EXPECT_EQ(name_, entry.name()); - EXPECT_EQ(value_, entry.value()); - EXPECT_FALSE(entry.IsStatic()); - EXPECT_EQ(1u, IndexOf(entry)); - EXPECT_EQ(Size(), entry.Size()); -} - -TEST_F(HpackEntryTest, LookupConstructor) { - HpackEntry entry(name_, value_); - - EXPECT_EQ(name_, entry.name()); - EXPECT_EQ(value_, entry.value()); - EXPECT_FALSE(entry.IsStatic()); - EXPECT_EQ(0u, IndexOf(entry)); - EXPECT_EQ(Size(), entry.Size()); -} - -TEST_F(HpackEntryTest, DefaultConstructor) { - HpackEntry entry; - - EXPECT_TRUE(entry.name().empty()); - EXPECT_TRUE(entry.value().empty()); - EXPECT_EQ(HpackEntry::kSizeOverhead, entry.Size()); -} - -TEST_F(HpackEntryTest, IndexUpdate) { - HpackEntry static1(StaticEntry()); - HpackEntry static2(StaticEntry()); - - EXPECT_EQ(1u, IndexOf(static1)); - EXPECT_EQ(2u, IndexOf(static2)); - - HpackEntry dynamic1(DynamicEntry()); - HpackEntry dynamic2(DynamicEntry()); - - EXPECT_EQ(1u, IndexOf(dynamic2)); - EXPECT_EQ(2u, IndexOf(dynamic1)); - EXPECT_EQ(3u, IndexOf(static1)); - EXPECT_EQ(4u, IndexOf(static2)); - - DropEntry(); // Drops |dynamic1|. - - EXPECT_EQ(1u, IndexOf(dynamic2)); - EXPECT_EQ(2u, IndexOf(static1)); - EXPECT_EQ(3u, IndexOf(static2)); - - HpackEntry dynamic3(DynamicEntry()); - - EXPECT_EQ(1u, IndexOf(dynamic3)); - EXPECT_EQ(2u, IndexOf(dynamic2)); - EXPECT_EQ(3u, IndexOf(static1)); - EXPECT_EQ(4u, IndexOf(static2)); -} - -} // namespace - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_header_table.cc b/net/third_party/spdy/core/hpack/hpack_header_table.cc deleted file mode 100644 index 543e05c3..0000000 --- a/net/third_party/spdy/core/hpack/hpack_header_table.cc +++ /dev/null
@@ -1,274 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_header_table.h" - -#include <algorithm> - -#include "base/logging.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/hpack/hpack_static_table.h" -#include "net/third_party/spdy/platform/api/spdy_containers.h" -#include "net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h" - -namespace spdy { - -size_t HpackHeaderTable::EntryHasher::operator()( - const HpackEntry* entry) const { - return SpdyHashStringPair(entry->name(), entry->value()); -} - -bool HpackHeaderTable::EntriesEq::operator()(const HpackEntry* lhs, - const HpackEntry* rhs) const { - if (lhs == nullptr) { - return rhs == nullptr; - } - if (rhs == nullptr) { - return false; - } - return lhs->name() == rhs->name() && lhs->value() == rhs->value(); -} - -HpackHeaderTable::HpackHeaderTable() - : static_entries_(ObtainHpackStaticTable().GetStaticEntries()), - static_index_(ObtainHpackStaticTable().GetStaticIndex()), - static_name_index_(ObtainHpackStaticTable().GetStaticNameIndex()), - settings_size_bound_(kDefaultHeaderTableSizeSetting), - size_(0), - max_size_(kDefaultHeaderTableSizeSetting), - total_insertions_(static_entries_.size()) {} - -HpackHeaderTable::~HpackHeaderTable() = default; - -const HpackEntry* HpackHeaderTable::GetByIndex(size_t index) { - if (index == 0) { - return nullptr; - } - index -= 1; - if (index < static_entries_.size()) { - return &static_entries_[index]; - } - index -= static_entries_.size(); - if (index < dynamic_entries_.size()) { - const HpackEntry* result = &dynamic_entries_[index]; - if (debug_visitor_ != nullptr) { - debug_visitor_->OnUseEntry(*result); - } - return result; - } - return nullptr; -} - -const HpackEntry* HpackHeaderTable::GetByName(SpdyStringPiece name) { - { - auto it = static_name_index_.find(name); - if (it != static_name_index_.end()) { - return it->second; - } - } - { - NameToEntryMap::const_iterator it = dynamic_name_index_.find(name); - if (it != dynamic_name_index_.end()) { - const HpackEntry* result = it->second; - if (debug_visitor_ != nullptr) { - debug_visitor_->OnUseEntry(*result); - } - return result; - } - } - return nullptr; -} - -const HpackEntry* HpackHeaderTable::GetByNameAndValue(SpdyStringPiece name, - SpdyStringPiece value) { - HpackEntry query(name, value); - { - auto it = static_index_.find(&query); - if (it != static_index_.end()) { - return *it; - } - } - { - auto it = dynamic_index_.find(&query); - if (it != dynamic_index_.end()) { - const HpackEntry* result = *it; - if (debug_visitor_ != nullptr) { - debug_visitor_->OnUseEntry(*result); - } - return result; - } - } - return nullptr; -} - -size_t HpackHeaderTable::IndexOf(const HpackEntry* entry) const { - if (entry->IsLookup()) { - return 0; - } else if (entry->IsStatic()) { - return 1 + entry->InsertionIndex(); - } else { - return total_insertions_ - entry->InsertionIndex() + static_entries_.size(); - } -} - -void HpackHeaderTable::SetMaxSize(size_t max_size) { - CHECK_LE(max_size, settings_size_bound_); - - max_size_ = max_size; - if (size_ > max_size_) { - Evict(EvictionCountToReclaim(size_ - max_size_)); - CHECK_LE(size_, max_size_); - } -} - -void HpackHeaderTable::SetSettingsHeaderTableSize(size_t settings_size) { - settings_size_bound_ = settings_size; - SetMaxSize(settings_size_bound_); -} - -void HpackHeaderTable::EvictionSet(SpdyStringPiece name, - SpdyStringPiece value, - EntryTable::iterator* begin_out, - EntryTable::iterator* end_out) { - size_t eviction_count = EvictionCountForEntry(name, value); - *begin_out = dynamic_entries_.end() - eviction_count; - *end_out = dynamic_entries_.end(); -} - -size_t HpackHeaderTable::EvictionCountForEntry(SpdyStringPiece name, - SpdyStringPiece value) const { - size_t available_size = max_size_ - size_; - size_t entry_size = HpackEntry::Size(name, value); - - if (entry_size <= available_size) { - // No evictions are required. - return 0; - } - return EvictionCountToReclaim(entry_size - available_size); -} - -size_t HpackHeaderTable::EvictionCountToReclaim(size_t reclaim_size) const { - size_t count = 0; - for (auto it = dynamic_entries_.rbegin(); - it != dynamic_entries_.rend() && reclaim_size != 0; ++it, ++count) { - reclaim_size -= std::min(reclaim_size, it->Size()); - } - return count; -} - -void HpackHeaderTable::Evict(size_t count) { - for (size_t i = 0; i != count; ++i) { - CHECK(!dynamic_entries_.empty()); - HpackEntry* entry = &dynamic_entries_.back(); - - size_ -= entry->Size(); - auto it = dynamic_index_.find(entry); - DCHECK(it != dynamic_index_.end()); - // Only remove an entry from the index if its insertion index matches; - // otherwise, the index refers to another entry with the same name and - // value. - if ((*it)->InsertionIndex() == entry->InsertionIndex()) { - dynamic_index_.erase(it); - } - auto name_it = dynamic_name_index_.find(entry->name()); - DCHECK(name_it != dynamic_name_index_.end()); - // Only remove an entry from the literal index if its insertion index - /// matches; otherwise, the index refers to another entry with the same - // name. - if (name_it->second->InsertionIndex() == entry->InsertionIndex()) { - dynamic_name_index_.erase(name_it); - } - dynamic_entries_.pop_back(); - } -} - -const HpackEntry* HpackHeaderTable::TryAddEntry(SpdyStringPiece name, - SpdyStringPiece value) { - Evict(EvictionCountForEntry(name, value)); - - size_t entry_size = HpackEntry::Size(name, value); - if (entry_size > (max_size_ - size_)) { - // Entire table has been emptied, but there's still insufficient room. - DCHECK(dynamic_entries_.empty()); - DCHECK_EQ(0u, size_); - return nullptr; - } - dynamic_entries_.push_front(HpackEntry(name, value, - false, // is_static - total_insertions_)); - HpackEntry* new_entry = &dynamic_entries_.front(); - auto index_result = dynamic_index_.insert(new_entry); - if (!index_result.second) { - // An entry with the same name and value already exists in the dynamic - // index. We should replace it with the newly added entry. - DVLOG(1) << "Found existing entry: " - << (*index_result.first)->GetDebugString() - << " replacing with: " << new_entry->GetDebugString(); - DCHECK_GT(new_entry->InsertionIndex(), - (*index_result.first)->InsertionIndex()); - dynamic_index_.erase(index_result.first); - CHECK(dynamic_index_.insert(new_entry).second); - } - - auto name_result = - dynamic_name_index_.insert(std::make_pair(new_entry->name(), new_entry)); - if (!name_result.second) { - // An entry with the same name already exists in the dynamic index. We - // should replace it with the newly added entry. - DVLOG(1) << "Found existing entry: " - << name_result.first->second->GetDebugString() - << " replacing with: " << new_entry->GetDebugString(); - DCHECK_GT(new_entry->InsertionIndex(), - name_result.first->second->InsertionIndex()); - dynamic_name_index_.erase(name_result.first); - auto insert_result = dynamic_name_index_.insert( - std::make_pair(new_entry->name(), new_entry)); - CHECK(insert_result.second); - } - - size_ += entry_size; - ++total_insertions_; - if (debug_visitor_ != nullptr) { - // Call |debug_visitor_->OnNewEntry()| to get the current time. - HpackEntry& entry = dynamic_entries_.front(); - entry.set_time_added(debug_visitor_->OnNewEntry(entry)); - DVLOG(2) << "HpackHeaderTable::OnNewEntry: name=" << entry.name() - << ", value=" << entry.value() - << ", insert_index=" << entry.InsertionIndex() - << ", time_added=" << entry.time_added(); - } - - return &dynamic_entries_.front(); -} - -void HpackHeaderTable::DebugLogTableState() const { - DVLOG(2) << "Dynamic table:"; - for (auto it = dynamic_entries_.begin(); it != dynamic_entries_.end(); ++it) { - DVLOG(2) << " " << it->GetDebugString(); - } - DVLOG(2) << "Full Static Index:"; - for (const auto* entry : static_index_) { - DVLOG(2) << " " << entry->GetDebugString(); - } - DVLOG(2) << "Full Static Name Index:"; - for (const auto it : static_name_index_) { - DVLOG(2) << " " << it.first << ": " << it.second->GetDebugString(); - } - DVLOG(2) << "Full Dynamic Index:"; - for (const auto* entry : dynamic_index_) { - DVLOG(2) << " " << entry->GetDebugString(); - } - DVLOG(2) << "Full Dynamic Name Index:"; - for (const auto it : dynamic_name_index_) { - DVLOG(2) << " " << it.first << ": " << it.second->GetDebugString(); - } -} - -size_t HpackHeaderTable::EstimateMemoryUsage() const { - return SpdyEstimateMemoryUsage(dynamic_entries_) + - SpdyEstimateMemoryUsage(dynamic_index_) + - SpdyEstimateMemoryUsage(dynamic_name_index_); -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_header_table.h b/net/third_party/spdy/core/hpack/hpack_header_table.h deleted file mode 100644 index 44366ea..0000000 --- a/net/third_party/spdy/core/hpack/hpack_header_table.h +++ /dev/null
@@ -1,180 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_HEADER_TABLE_H_ -#define NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_HEADER_TABLE_H_ - -#include <cstddef> -#include <cstdint> -#include <deque> -#include <memory> - -#include "base/macros.h" -#include "net/third_party/spdy/core/hpack/hpack_entry.h" -#include "net/third_party/spdy/platform/api/spdy_containers.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_macros.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -// All section references below are to http://tools.ietf.org/html/rfc7541. - -namespace spdy { - -namespace test { -class HpackHeaderTablePeer; -} // namespace test - -// A data structure for the static table (2.3.1) and the dynamic table (2.3.2). -class SPDY_EXPORT_PRIVATE HpackHeaderTable { - public: - friend class test::HpackHeaderTablePeer; - - // Debug visitor my be used to extract debug/internal information - // about the HpackHeaderTable as it operates. - // - // Most HpackHeaderTable implementations do not need to bother with - // this interface at all. - class DebugVisitorInterface { - public: - virtual ~DebugVisitorInterface() {} - - // |OnNewEntry()| and |OnUseEntry()| can be used together to - // gather data about the distribution of time intervals between - // creation and reference of entries in the dynamic table. The - // data is desired to sanity check a proposed extension to HPACK - // for QUIC that would eliminate inter-stream head of line - // blocking (due to standard HPACK). The visitor should return - // the current time from |OnNewEntry()|, which will be passed - // to |OnUseEntry()| each time that particular entry is used to - // emit an indexed representation. - virtual int64_t OnNewEntry(const HpackEntry& entry) = 0; - virtual void OnUseEntry(const HpackEntry& entry) = 0; - }; - - // HpackHeaderTable takes advantage of the deque property that references - // remain valid, so long as insertions & deletions are at the head & tail. - // This precludes the use of base::circular_deque. - // - // If this changes (we want to change to circular_deque or we start to drop - // entries from the middle of the table), this should to be a std::list, in - // which case |*_index_| can be trivially extended to map to list iterators. - using EntryTable = std::deque<HpackEntry>; - - struct SPDY_EXPORT_PRIVATE EntryHasher { - size_t operator()(const HpackEntry* entry) const; - }; - struct SPDY_EXPORT_PRIVATE EntriesEq { - bool operator()(const HpackEntry* lhs, const HpackEntry* rhs) const; - }; - using UnorderedEntrySet = SpdyHashSet<HpackEntry*, EntryHasher, EntriesEq>; - using NameToEntryMap = - SpdyHashMap<SpdyStringPiece, const HpackEntry*, SpdyStringPieceHash>; - - HpackHeaderTable(); - HpackHeaderTable(const HpackHeaderTable&) = delete; - HpackHeaderTable& operator=(const HpackHeaderTable&) = delete; - - ~HpackHeaderTable(); - - // Last-acknowledged value of SETTINGS_HEADER_TABLE_SIZE. - size_t settings_size_bound() const { return settings_size_bound_; } - - // Current and maximum estimated byte size of the table, as described in - // 4.1. Notably, this is /not/ the number of entries in the table. - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - - // Returns the entry matching the index, or NULL. - const HpackEntry* GetByIndex(size_t index); - - // Returns the lowest-value entry having |name|, or NULL. - const HpackEntry* GetByName(SpdyStringPiece name); - - // Returns the lowest-index matching entry, or NULL. - const HpackEntry* GetByNameAndValue(SpdyStringPiece name, - SpdyStringPiece value); - - // Returns the index of an entry within this header table. - size_t IndexOf(const HpackEntry* entry) const; - - // Sets the maximum size of the header table, evicting entries if - // necessary as described in 5.2. - void SetMaxSize(size_t max_size); - - // Sets the SETTINGS_HEADER_TABLE_SIZE bound of the table. Will call - // SetMaxSize() as needed to preserve max_size() <= settings_size_bound(). - void SetSettingsHeaderTableSize(size_t settings_size); - - // Determine the set of entries which would be evicted by the insertion - // of |name| & |value| into the table, as per section 4.4. No eviction - // actually occurs. The set is returned via range [begin_out, end_out). - void EvictionSet(SpdyStringPiece name, - SpdyStringPiece value, - EntryTable::iterator* begin_out, - EntryTable::iterator* end_out); - - // Adds an entry for the representation, evicting entries as needed. |name| - // and |value| must not be owned by an entry which could be evicted. The - // added HpackEntry is returned, or NULL is returned if all entries were - // evicted and the empty table is of insufficent size for the representation. - const HpackEntry* TryAddEntry(SpdyStringPiece name, SpdyStringPiece value); - - void DebugLogTableState() const SPDY_UNUSED; - - void set_debug_visitor(std::unique_ptr<DebugVisitorInterface> visitor) { - debug_visitor_ = std::move(visitor); - } - - // Returns the estimate of dynamically allocated memory in bytes. - size_t EstimateMemoryUsage() const; - - private: - // Returns number of evictions required to enter |name| & |value|. - size_t EvictionCountForEntry(SpdyStringPiece name, - SpdyStringPiece value) const; - - // Returns number of evictions required to reclaim |reclaim_size| table size. - size_t EvictionCountToReclaim(size_t reclaim_size) const; - - // Evicts |count| oldest entries from the table. - void Evict(size_t count); - - // |static_entries_|, |static_index_|, and |static_name_index_| are owned by - // HpackStaticTable singleton. - - // Tracks HpackEntries by index. - const EntryTable& static_entries_; - EntryTable dynamic_entries_; - - // Tracks the unique HpackEntry for a given header name and value. - const UnorderedEntrySet& static_index_; - - // Tracks the first static entry for each name in the static table. - const NameToEntryMap& static_name_index_; - - // Tracks the most recently inserted HpackEntry for a given header name and - // value. - UnorderedEntrySet dynamic_index_; - - // Tracks the most recently inserted HpackEntry for a given header name. - NameToEntryMap dynamic_name_index_; - - // Last acknowledged value for SETTINGS_HEADER_TABLE_SIZE. - size_t settings_size_bound_; - - // Estimated current and maximum byte size of the table. - // |max_size_| <= |settings_size_bound_| - size_t size_; - size_t max_size_; - - // Total number of table insertions which have occurred. Referenced by - // IndexOf() for determination of an HpackEntry's table index. - size_t total_insertions_; - - std::unique_ptr<DebugVisitorInterface> debug_visitor_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_HEADER_TABLE_H_
diff --git a/net/third_party/spdy/core/hpack/hpack_header_table_test.cc b/net/third_party/spdy/core/hpack/hpack_header_table_test.cc deleted file mode 100644 index 8cb2e4e..0000000 --- a/net/third_party/spdy/core/hpack/hpack_header_table_test.cc +++ /dev/null
@@ -1,446 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_header_table.h" - -#include <algorithm> -#include <cstdint> -#include <set> -#include <vector> - -#include "base/macros.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/hpack/hpack_entry.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -using std::distance; - -namespace test { - -class HpackHeaderTablePeer { - public: - explicit HpackHeaderTablePeer(HpackHeaderTable* table) : table_(table) {} - - const HpackHeaderTable::EntryTable& dynamic_entries() { - return table_->dynamic_entries_; - } - const HpackHeaderTable::EntryTable& static_entries() { - return table_->static_entries_; - } - size_t index_size() { - return table_->static_index_.size() + table_->dynamic_index_.size(); - } - std::vector<HpackEntry*> EvictionSet(SpdyStringPiece name, - SpdyStringPiece value) { - HpackHeaderTable::EntryTable::iterator begin, end; - table_->EvictionSet(name, value, &begin, &end); - std::vector<HpackEntry*> result; - for (; begin != end; ++begin) { - result.push_back(&(*begin)); - } - return result; - } - size_t total_insertions() { return table_->total_insertions_; } - size_t dynamic_entries_count() { return table_->dynamic_entries_.size(); } - size_t EvictionCountForEntry(SpdyStringPiece name, SpdyStringPiece value) { - return table_->EvictionCountForEntry(name, value); - } - size_t EvictionCountToReclaim(size_t reclaim_size) { - return table_->EvictionCountToReclaim(reclaim_size); - } - void Evict(size_t count) { return table_->Evict(count); } - - void AddDynamicEntry(SpdyStringPiece name, SpdyStringPiece value) { - table_->dynamic_entries_.push_back( - HpackEntry(name, value, false, table_->total_insertions_++)); - } - - private: - HpackHeaderTable* table_; -}; - -} // namespace test - -namespace { - -class HpackHeaderTableTest : public ::testing::Test { - protected: - typedef std::vector<HpackEntry> HpackEntryVector; - - HpackHeaderTableTest() : table_(), peer_(&table_) {} - - // Returns an entry whose Size() is equal to the given one. - static HpackEntry MakeEntryOfSize(uint32_t size) { - EXPECT_GE(size, HpackEntry::kSizeOverhead); - SpdyString name((size - HpackEntry::kSizeOverhead) / 2, 'n'); - SpdyString value(size - HpackEntry::kSizeOverhead - name.size(), 'v'); - HpackEntry entry(name, value, false, 0); - EXPECT_EQ(size, entry.Size()); - return entry; - } - - // Returns a vector of entries whose total size is equal to the given - // one. - static HpackEntryVector MakeEntriesOfTotalSize(uint32_t total_size) { - EXPECT_GE(total_size, HpackEntry::kSizeOverhead); - uint32_t entry_size = HpackEntry::kSizeOverhead; - uint32_t remaining_size = total_size; - HpackEntryVector entries; - while (remaining_size > 0) { - EXPECT_LE(entry_size, remaining_size); - entries.push_back(MakeEntryOfSize(entry_size)); - remaining_size -= entry_size; - entry_size = std::min(remaining_size, entry_size + 32); - } - return entries; - } - - // Adds the given vector of entries to the given header table, - // expecting no eviction to happen. - void AddEntriesExpectNoEviction(const HpackEntryVector& entries) { - for (auto it = entries.begin(); it != entries.end(); ++it) { - HpackHeaderTable::EntryTable::iterator begin, end; - - table_.EvictionSet(it->name(), it->value(), &begin, &end); - EXPECT_EQ(0, distance(begin, end)); - - const HpackEntry* entry = table_.TryAddEntry(it->name(), it->value()); - EXPECT_NE(entry, static_cast<HpackEntry*>(nullptr)); - } - - for (size_t i = 0; i != entries.size(); ++i) { - // Static table has 61 entries, dynamic entries follow those. - size_t index = 61 + entries.size() - i; - const HpackEntry* entry = table_.GetByIndex(index); - EXPECT_EQ(entries[i].name(), entry->name()); - EXPECT_EQ(entries[i].value(), entry->value()); - EXPECT_EQ(index, table_.IndexOf(entry)); - } - } - - HpackEntry DynamicEntry(const SpdyString& name, const SpdyString& value) { - peer_.AddDynamicEntry(name, value); - return peer_.dynamic_entries().back(); - } - - HpackHeaderTable table_; - test::HpackHeaderTablePeer peer_; -}; - -TEST_F(HpackHeaderTableTest, StaticTableInitialization) { - EXPECT_EQ(0u, table_.size()); - EXPECT_EQ(kDefaultHeaderTableSizeSetting, table_.max_size()); - EXPECT_EQ(kDefaultHeaderTableSizeSetting, table_.settings_size_bound()); - - EXPECT_EQ(0u, peer_.dynamic_entries_count()); - EXPECT_EQ(peer_.static_entries().size(), peer_.total_insertions()); - - // Static entries have been populated and inserted into the table & index. - EXPECT_NE(0u, peer_.static_entries().size()); - EXPECT_EQ(peer_.index_size(), peer_.static_entries().size()); - for (size_t i = 0; i != peer_.static_entries().size(); ++i) { - const HpackEntry* entry = &peer_.static_entries()[i]; - - EXPECT_TRUE(entry->IsStatic()); - EXPECT_EQ(entry, table_.GetByIndex(i + 1)); - EXPECT_EQ(entry, table_.GetByNameAndValue(entry->name(), entry->value())); - } -} - -TEST_F(HpackHeaderTableTest, BasicDynamicEntryInsertionAndEviction) { - size_t static_count = peer_.total_insertions(); - const HpackEntry* first_static_entry = table_.GetByIndex(1); - - EXPECT_EQ(1u, table_.IndexOf(first_static_entry)); - - const HpackEntry* entry = table_.TryAddEntry("header-key", "Header Value"); - EXPECT_EQ("header-key", entry->name()); - EXPECT_EQ("Header Value", entry->value()); - EXPECT_FALSE(entry->IsStatic()); - - // Table counts were updated appropriately. - EXPECT_EQ(entry->Size(), table_.size()); - EXPECT_EQ(1u, peer_.dynamic_entries_count()); - EXPECT_EQ(peer_.dynamic_entries().size(), peer_.dynamic_entries_count()); - EXPECT_EQ(static_count + 1, peer_.total_insertions()); - EXPECT_EQ(static_count + 1, peer_.index_size()); - - // Index() of entries reflects the insertion. - EXPECT_EQ(1u, table_.IndexOf(first_static_entry)); - // Static table has 61 entries. - EXPECT_EQ(62u, table_.IndexOf(entry)); - EXPECT_EQ(first_static_entry, table_.GetByIndex(1)); - EXPECT_EQ(entry, table_.GetByIndex(62)); - - // Evict |entry|. Table counts are again updated appropriately. - peer_.Evict(1); - EXPECT_EQ(0u, table_.size()); - EXPECT_EQ(0u, peer_.dynamic_entries_count()); - EXPECT_EQ(peer_.dynamic_entries().size(), peer_.dynamic_entries_count()); - EXPECT_EQ(static_count + 1, peer_.total_insertions()); - EXPECT_EQ(static_count, peer_.index_size()); - - // Index() of |first_static_entry| reflects the eviction. - EXPECT_EQ(1u, table_.IndexOf(first_static_entry)); - EXPECT_EQ(first_static_entry, table_.GetByIndex(1)); -} - -TEST_F(HpackHeaderTableTest, EntryIndexing) { - const HpackEntry* first_static_entry = table_.GetByIndex(1); - - // Static entries are queryable by name & value. - EXPECT_EQ(first_static_entry, table_.GetByName(first_static_entry->name())); - EXPECT_EQ(first_static_entry, - table_.GetByNameAndValue(first_static_entry->name(), - first_static_entry->value())); - - // Create a mix of entries which duplicate names, and names & values of both - // dynamic and static entries. - const HpackEntry* entry1 = table_.TryAddEntry(first_static_entry->name(), - first_static_entry->value()); - const HpackEntry* entry2 = - table_.TryAddEntry(first_static_entry->name(), "Value Four"); - const HpackEntry* entry3 = table_.TryAddEntry("key-1", "Value One"); - const HpackEntry* entry4 = table_.TryAddEntry("key-2", "Value Three"); - const HpackEntry* entry5 = table_.TryAddEntry("key-1", "Value Two"); - const HpackEntry* entry6 = table_.TryAddEntry("key-2", "Value Three"); - const HpackEntry* entry7 = table_.TryAddEntry("key-2", "Value Four"); - - // Entries are queryable under their current index. - EXPECT_EQ(entry7, table_.GetByIndex(62)); - EXPECT_EQ(entry6, table_.GetByIndex(63)); - EXPECT_EQ(entry5, table_.GetByIndex(64)); - EXPECT_EQ(entry4, table_.GetByIndex(65)); - EXPECT_EQ(entry3, table_.GetByIndex(66)); - EXPECT_EQ(entry2, table_.GetByIndex(67)); - EXPECT_EQ(entry1, table_.GetByIndex(68)); - EXPECT_EQ(first_static_entry, table_.GetByIndex(1)); - - // Querying by name returns the most recently added matching entry. - EXPECT_EQ(entry5, table_.GetByName("key-1")); - EXPECT_EQ(entry7, table_.GetByName("key-2")); - EXPECT_EQ(entry2->name(), - table_.GetByName(first_static_entry->name())->name()); - EXPECT_EQ(nullptr, table_.GetByName("not-present")); - - // Querying by name & value returns the lowest-index matching entry among - // static entries, and the highest-index one among dynamic entries. - EXPECT_EQ(entry3, table_.GetByNameAndValue("key-1", "Value One")); - EXPECT_EQ(entry5, table_.GetByNameAndValue("key-1", "Value Two")); - EXPECT_EQ(entry6, table_.GetByNameAndValue("key-2", "Value Three")); - EXPECT_EQ(entry7, table_.GetByNameAndValue("key-2", "Value Four")); - EXPECT_EQ(first_static_entry, - table_.GetByNameAndValue(first_static_entry->name(), - first_static_entry->value())); - EXPECT_EQ(entry2, - table_.GetByNameAndValue(first_static_entry->name(), "Value Four")); - EXPECT_EQ(nullptr, table_.GetByNameAndValue("key-1", "Not Present")); - EXPECT_EQ(nullptr, table_.GetByNameAndValue("not-present", "Value One")); - - // Evict |entry1|. Queries for its name & value now return the static entry. - // |entry2| remains queryable. - peer_.Evict(1); - EXPECT_EQ(first_static_entry, - table_.GetByNameAndValue(first_static_entry->name(), - first_static_entry->value())); - EXPECT_EQ(entry2, - table_.GetByNameAndValue(first_static_entry->name(), "Value Four")); - - // Evict |entry2|. Queries by its name & value are not found. - peer_.Evict(1); - EXPECT_EQ(nullptr, - table_.GetByNameAndValue(first_static_entry->name(), "Value Four")); -} - -TEST_F(HpackHeaderTableTest, SetSizes) { - SpdyString key = "key", value = "value"; - const HpackEntry* entry1 = table_.TryAddEntry(key, value); - const HpackEntry* entry2 = table_.TryAddEntry(key, value); - const HpackEntry* entry3 = table_.TryAddEntry(key, value); - - // Set exactly large enough. No Evictions. - size_t max_size = entry1->Size() + entry2->Size() + entry3->Size(); - table_.SetMaxSize(max_size); - EXPECT_EQ(3u, peer_.dynamic_entries().size()); - - // Set just too small. One eviction. - max_size = entry1->Size() + entry2->Size() + entry3->Size() - 1; - table_.SetMaxSize(max_size); - EXPECT_EQ(2u, peer_.dynamic_entries().size()); - - // Changing SETTINGS_HEADER_TABLE_SIZE. - EXPECT_EQ(kDefaultHeaderTableSizeSetting, table_.settings_size_bound()); - // In production, the size passed to SetSettingsHeaderTableSize is never - // larger than table_.settings_size_bound(). - table_.SetSettingsHeaderTableSize(kDefaultHeaderTableSizeSetting * 3 + 1); - EXPECT_EQ(kDefaultHeaderTableSizeSetting * 3 + 1, table_.max_size()); - - // SETTINGS_HEADER_TABLE_SIZE upper-bounds |table_.max_size()|, - // and will force evictions. - max_size = entry3->Size() - 1; - table_.SetSettingsHeaderTableSize(max_size); - EXPECT_EQ(max_size, table_.max_size()); - EXPECT_EQ(max_size, table_.settings_size_bound()); - EXPECT_EQ(0u, peer_.dynamic_entries().size()); -} - -TEST_F(HpackHeaderTableTest, EvictionCountForEntry) { - SpdyString key = "key", value = "value"; - const HpackEntry* entry1 = table_.TryAddEntry(key, value); - const HpackEntry* entry2 = table_.TryAddEntry(key, value); - size_t entry3_size = HpackEntry::Size(key, value); - - // Just enough capacity for third entry. - table_.SetMaxSize(entry1->Size() + entry2->Size() + entry3_size); - EXPECT_EQ(0u, peer_.EvictionCountForEntry(key, value)); - EXPECT_EQ(1u, peer_.EvictionCountForEntry(key, value + "x")); - - // No extra capacity. Third entry would force evictions. - table_.SetMaxSize(entry1->Size() + entry2->Size()); - EXPECT_EQ(1u, peer_.EvictionCountForEntry(key, value)); - EXPECT_EQ(2u, peer_.EvictionCountForEntry(key, value + "x")); -} - -TEST_F(HpackHeaderTableTest, EvictionCountToReclaim) { - SpdyString key = "key", value = "value"; - const HpackEntry* entry1 = table_.TryAddEntry(key, value); - const HpackEntry* entry2 = table_.TryAddEntry(key, value); - - EXPECT_EQ(1u, peer_.EvictionCountToReclaim(1)); - EXPECT_EQ(1u, peer_.EvictionCountToReclaim(entry1->Size())); - EXPECT_EQ(2u, peer_.EvictionCountToReclaim(entry1->Size() + 1)); - EXPECT_EQ(2u, peer_.EvictionCountToReclaim(entry1->Size() + entry2->Size())); -} - -// Fill a header table with entries. Make sure the entries are in -// reverse order in the header table. -TEST_F(HpackHeaderTableTest, TryAddEntryBasic) { - EXPECT_EQ(0u, table_.size()); - EXPECT_EQ(table_.settings_size_bound(), table_.max_size()); - - HpackEntryVector entries = MakeEntriesOfTotalSize(table_.max_size()); - - // Most of the checks are in AddEntriesExpectNoEviction(). - AddEntriesExpectNoEviction(entries); - EXPECT_EQ(table_.max_size(), table_.size()); - EXPECT_EQ(table_.settings_size_bound(), table_.size()); -} - -// Fill a header table with entries, and then ramp the table's max -// size down to evict an entry one at a time. Make sure the eviction -// happens as expected. -TEST_F(HpackHeaderTableTest, SetMaxSize) { - HpackEntryVector entries = - MakeEntriesOfTotalSize(kDefaultHeaderTableSizeSetting / 2); - AddEntriesExpectNoEviction(entries); - - for (auto it = entries.begin(); it != entries.end(); ++it) { - size_t expected_count = distance(it, entries.end()); - EXPECT_EQ(expected_count, peer_.dynamic_entries().size()); - - table_.SetMaxSize(table_.size() + 1); - EXPECT_EQ(expected_count, peer_.dynamic_entries().size()); - - table_.SetMaxSize(table_.size()); - EXPECT_EQ(expected_count, peer_.dynamic_entries().size()); - - --expected_count; - table_.SetMaxSize(table_.size() - 1); - EXPECT_EQ(expected_count, peer_.dynamic_entries().size()); - } - EXPECT_EQ(0u, table_.size()); -} - -// Fill a header table with entries, and then add an entry just big -// enough to cause eviction of all but one entry. Make sure the -// eviction happens as expected and the long entry is inserted into -// the table. -TEST_F(HpackHeaderTableTest, TryAddEntryEviction) { - HpackEntryVector entries = MakeEntriesOfTotalSize(table_.max_size()); - AddEntriesExpectNoEviction(entries); - - const HpackEntry* survivor_entry = table_.GetByIndex(61 + 1); - HpackEntry long_entry = - MakeEntryOfSize(table_.max_size() - survivor_entry->Size()); - - // All dynamic entries but the first are to be evicted. - EXPECT_EQ(peer_.dynamic_entries().size() - 1, - peer_.EvictionSet(long_entry.name(), long_entry.value()).size()); - - const HpackEntry* new_entry = - table_.TryAddEntry(long_entry.name(), long_entry.value()); - EXPECT_EQ(62u, table_.IndexOf(new_entry)); - EXPECT_EQ(2u, peer_.dynamic_entries().size()); - EXPECT_EQ(table_.GetByIndex(63), survivor_entry); - EXPECT_EQ(table_.GetByIndex(62), new_entry); -} - -// Fill a header table with entries, and then add an entry bigger than -// the entire table. Make sure no entry remains in the table. -TEST_F(HpackHeaderTableTest, TryAddTooLargeEntry) { - HpackEntryVector entries = MakeEntriesOfTotalSize(table_.max_size()); - AddEntriesExpectNoEviction(entries); - - const HpackEntry long_entry = MakeEntryOfSize(table_.max_size() + 1); - - // All entries are to be evicted. - EXPECT_EQ(peer_.dynamic_entries().size(), - peer_.EvictionSet(long_entry.name(), long_entry.value()).size()); - - const HpackEntry* new_entry = - table_.TryAddEntry(long_entry.name(), long_entry.value()); - EXPECT_EQ(new_entry, static_cast<HpackEntry*>(nullptr)); - EXPECT_EQ(0u, peer_.dynamic_entries().size()); -} - -TEST_F(HpackHeaderTableTest, EntryNamesDiffer) { - HpackEntry entry1("header", "value"); - HpackEntry entry2("HEADER", "value"); - - HpackHeaderTable::EntryHasher hasher; - EXPECT_NE(hasher(&entry1), hasher(&entry2)); - - HpackHeaderTable::EntriesEq eq; - EXPECT_FALSE(eq(&entry1, &entry2)); -} - -TEST_F(HpackHeaderTableTest, EntryValuesDiffer) { - HpackEntry entry1("header", "value"); - HpackEntry entry2("header", "VALUE"); - - HpackHeaderTable::EntryHasher hasher; - EXPECT_NE(hasher(&entry1), hasher(&entry2)); - - HpackHeaderTable::EntriesEq eq; - EXPECT_FALSE(eq(&entry1, &entry2)); -} - -TEST_F(HpackHeaderTableTest, EntriesEqual) { - HpackEntry entry1(DynamicEntry("name", "value")); - HpackEntry entry2(DynamicEntry("name", "value")); - - HpackHeaderTable::EntryHasher hasher; - EXPECT_EQ(hasher(&entry1), hasher(&entry2)); - - HpackHeaderTable::EntriesEq eq; - EXPECT_TRUE(eq(&entry1, &entry2)); -} - -TEST_F(HpackHeaderTableTest, StaticAndDynamicEntriesEqual) { - HpackEntry entry1("name", "value"); - HpackEntry entry2(DynamicEntry("name", "value")); - - HpackHeaderTable::EntryHasher hasher; - EXPECT_EQ(hasher(&entry1), hasher(&entry2)); - - HpackHeaderTable::EntriesEq eq; - EXPECT_TRUE(eq(&entry1, &entry2)); -} - -} // namespace - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_huffman_table.cc b/net/third_party/spdy/core/hpack/hpack_huffman_table.cc deleted file mode 100644 index 81afac0b..0000000 --- a/net/third_party/spdy/core/hpack/hpack_huffman_table.cc +++ /dev/null
@@ -1,151 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_huffman_table.h" - -#include <algorithm> -#include <cmath> -#include <limits> -#include <memory> - -#include "base/logging.h" -#include "net/third_party/spdy/core/hpack/hpack_output_stream.h" -#include "net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h" - -namespace spdy { - -namespace { - -bool SymbolLengthAndIdCompare(const HpackHuffmanSymbol& a, - const HpackHuffmanSymbol& b) { - if (a.length == b.length) { - return a.id < b.id; - } - return a.length < b.length; -} -bool SymbolIdCompare(const HpackHuffmanSymbol& a, const HpackHuffmanSymbol& b) { - return a.id < b.id; -} - -} // namespace - -HpackHuffmanTable::HpackHuffmanTable() : pad_bits_(0), failed_symbol_id_(0) {} - -HpackHuffmanTable::~HpackHuffmanTable() = default; - -bool HpackHuffmanTable::Initialize(const HpackHuffmanSymbol* input_symbols, - size_t symbol_count) { - CHECK(!IsInitialized()); - DCHECK_LE(symbol_count, std::numeric_limits<uint16_t>::max()); - - std::vector<Symbol> symbols(symbol_count); - // Validate symbol id sequence, and copy into |symbols|. - for (uint16_t i = 0; i < symbol_count; i++) { - if (i != input_symbols[i].id) { - failed_symbol_id_ = i; - return false; - } - symbols[i] = input_symbols[i]; - } - // Order on length and ID ascending, to verify symbol codes are canonical. - std::sort(symbols.begin(), symbols.end(), SymbolLengthAndIdCompare); - if (symbols[0].code != 0) { - failed_symbol_id_ = 0; - return false; - } - for (size_t i = 1; i != symbols.size(); i++) { - unsigned code_shift = 32 - symbols[i - 1].length; - uint32_t code = symbols[i - 1].code + (1 << code_shift); - - if (code != symbols[i].code) { - failed_symbol_id_ = symbols[i].id; - return false; - } - if (code < symbols[i - 1].code) { - // An integer overflow occurred. This implies the input - // lengths do not represent a valid Huffman code. - failed_symbol_id_ = symbols[i].id; - return false; - } - } - if (symbols.back().length < 8) { - // At least one code (such as an EOS symbol) must be 8 bits or longer. - // Without this, some inputs will not be encodable in a whole number - // of bytes. - return false; - } - pad_bits_ = static_cast<uint8_t>(symbols.back().code >> 24); - - // Order on symbol ID ascending. - std::sort(symbols.begin(), symbols.end(), SymbolIdCompare); - BuildEncodeTable(symbols); - return true; -} - -void HpackHuffmanTable::BuildEncodeTable(const std::vector<Symbol>& symbols) { - for (size_t i = 0; i != symbols.size(); i++) { - const Symbol& symbol = symbols[i]; - CHECK_EQ(i, symbol.id); - code_by_id_.push_back(symbol.code); - length_by_id_.push_back(symbol.length); - } -} - -bool HpackHuffmanTable::IsInitialized() const { - return !code_by_id_.empty(); -} - -void HpackHuffmanTable::EncodeString(SpdyStringPiece in, - HpackOutputStream* out) const { - size_t bit_remnant = 0; - for (size_t i = 0; i != in.size(); i++) { - uint16_t symbol_id = static_cast<uint8_t>(in[i]); - CHECK_GT(code_by_id_.size(), symbol_id); - - // Load, and shift code to low bits. - unsigned length = length_by_id_[symbol_id]; - uint32_t code = code_by_id_[symbol_id] >> (32 - length); - - bit_remnant = (bit_remnant + length) % 8; - - if (length > 24) { - out->AppendBits(static_cast<uint8_t>(code >> 24), length - 24); - length = 24; - } - if (length > 16) { - out->AppendBits(static_cast<uint8_t>(code >> 16), length - 16); - length = 16; - } - if (length > 8) { - out->AppendBits(static_cast<uint8_t>(code >> 8), length - 8); - length = 8; - } - out->AppendBits(static_cast<uint8_t>(code), length); - } - if (bit_remnant != 0) { - // Pad current byte as required. - out->AppendBits(pad_bits_ >> bit_remnant, 8 - bit_remnant); - } -} - -size_t HpackHuffmanTable::EncodedSize(SpdyStringPiece in) const { - size_t bit_count = 0; - for (size_t i = 0; i != in.size(); i++) { - uint16_t symbol_id = static_cast<uint8_t>(in[i]); - CHECK_GT(code_by_id_.size(), symbol_id); - - bit_count += length_by_id_[symbol_id]; - } - if (bit_count % 8 != 0) { - bit_count += 8 - bit_count % 8; - } - return bit_count / 8; -} - -size_t HpackHuffmanTable::EstimateMemoryUsage() const { - return SpdyEstimateMemoryUsage(code_by_id_) + - SpdyEstimateMemoryUsage(length_by_id_); -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_huffman_table.h b/net/third_party/spdy/core/hpack/hpack_huffman_table.h deleted file mode 100644 index d0ce178..0000000 --- a/net/third_party/spdy/core/hpack/hpack_huffman_table.h +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_HUFFMAN_TABLE_H_ -#define NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_HUFFMAN_TABLE_H_ - -#include <cstddef> -#include <cstdint> -#include <vector> - -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { - -namespace test { -class HpackHuffmanTablePeer; -} // namespace test - -class HpackOutputStream; - -// HpackHuffmanTable encodes string literals using a constructed canonical -// Huffman code. Once initialized, an instance is read only and may be accessed -// only through its const interface. -class SPDY_EXPORT_PRIVATE HpackHuffmanTable { - public: - friend class test::HpackHuffmanTablePeer; - - typedef HpackHuffmanSymbol Symbol; - - HpackHuffmanTable(); - ~HpackHuffmanTable(); - - // Prepares HpackHuffmanTable to encode the canonical Huffman code as - // determined by the given symbols. Must be called exactly once. - // Returns false if the input symbols define an invalid coding, and true - // otherwise. Symbols must be presented in ascending ID order with no gaps, - // and |symbol_count| must fit in a uint16_t. - bool Initialize(const Symbol* input_symbols, size_t symbol_count); - - // Returns whether Initialize() has been successfully called. - bool IsInitialized() const; - - // Encodes the input string to the output stream using the table's Huffman - // context. - void EncodeString(SpdyStringPiece in, HpackOutputStream* out) const; - - // Returns the encoded size of the input string. - size_t EncodedSize(SpdyStringPiece in) const; - - // Returns the estimate of dynamically allocated memory in bytes. - size_t EstimateMemoryUsage() const; - - private: - // Expects symbols ordered on ID ascending. - void BuildEncodeTable(const std::vector<Symbol>& symbols); - - // Symbol code and code length, in ascending symbol ID order. - // Codes are stored in the most-significant bits of the word. - std::vector<uint32_t> code_by_id_; - std::vector<uint8_t> length_by_id_; - - // The first 8 bits of the longest code. Applied when generating padding bits. - uint8_t pad_bits_; - - // If initialization fails, preserve the symbol ID which failed validation - // for examination in tests. - uint16_t failed_symbol_id_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_HUFFMAN_TABLE_H_
diff --git a/net/third_party/spdy/core/hpack/hpack_huffman_table_test.cc b/net/third_party/spdy/core/hpack/hpack_huffman_table_test.cc deleted file mode 100644 index 35757546..0000000 --- a/net/third_party/spdy/core/hpack/hpack_huffman_table_test.cc +++ /dev/null
@@ -1,309 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_huffman_table.h" - -#include <utility> - -#include "base/macros.h" -#include "net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/hpack/hpack_output_stream.h" -#include "net/third_party/spdy/platform/api/spdy_arraysize.h" -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -namespace test { - -class HpackHuffmanTablePeer { - public: - explicit HpackHuffmanTablePeer(const HpackHuffmanTable& table) - : table_(table) {} - - const std::vector<uint32_t>& code_by_id() const { return table_.code_by_id_; } - const std::vector<uint8_t>& length_by_id() const { - return table_.length_by_id_; - } - uint8_t pad_bits() const { return table_.pad_bits_; } - uint16_t failed_symbol_id() const { return table_.failed_symbol_id_; } - - private: - const HpackHuffmanTable& table_; -}; - -namespace { - -// Tests of the ability to encode some canonical Huffman code, -// not just the one defined in the RFC 7541. -class GenericHuffmanTableTest : public ::testing::Test { - protected: - GenericHuffmanTableTest() : table_(), peer_(table_) {} - - SpdyString EncodeString(SpdyStringPiece input) { - SpdyString result; - HpackOutputStream output_stream; - table_.EncodeString(input, &output_stream); - - output_stream.TakeString(&result); - // Verify EncodedSize() agrees with EncodeString(). - EXPECT_EQ(result.size(), table_.EncodedSize(input)); - return result; - } - - HpackHuffmanTable table_; - HpackHuffmanTablePeer peer_; -}; - -TEST_F(GenericHuffmanTableTest, InitializeEdgeCases) { - { - // Verify eight symbols can be encoded with 3 bits per symbol. - HpackHuffmanSymbol code[] = {{0b00000000000000000000000000000000, 3, 0}, - {0b00100000000000000000000000000000, 3, 1}, - {0b01000000000000000000000000000000, 3, 2}, - {0b01100000000000000000000000000000, 3, 3}, - {0b10000000000000000000000000000000, 3, 4}, - {0b10100000000000000000000000000000, 3, 5}, - {0b11000000000000000000000000000000, 3, 6}, - {0b11100000000000000000000000000000, 8, 7}}; - HpackHuffmanTable table; - EXPECT_TRUE(table.Initialize(code, SPDY_ARRAYSIZE(code))); - } - { - // But using 2 bits with one symbol overflows the code. - HpackHuffmanSymbol code[] = { - {0b01000000000000000000000000000000, 3, 0}, - {0b01100000000000000000000000000000, 3, 1}, - {0b00000000000000000000000000000000, 2, 2}, - {0b10000000000000000000000000000000, 3, 3}, - {0b10100000000000000000000000000000, 3, 4}, - {0b11000000000000000000000000000000, 3, 5}, - {0b11100000000000000000000000000000, 3, 6}, - {0b00000000000000000000000000000000, 8, 7}}; // Overflow. - HpackHuffmanTable table; - EXPECT_FALSE(table.Initialize(code, SPDY_ARRAYSIZE(code))); - EXPECT_EQ(7, HpackHuffmanTablePeer(table).failed_symbol_id()); - } - { - // Verify four symbols can be encoded with incremental bits per symbol. - HpackHuffmanSymbol code[] = {{0b00000000000000000000000000000000, 1, 0}, - {0b10000000000000000000000000000000, 2, 1}, - {0b11000000000000000000000000000000, 3, 2}, - {0b11100000000000000000000000000000, 8, 3}}; - HpackHuffmanTable table; - EXPECT_TRUE(table.Initialize(code, SPDY_ARRAYSIZE(code))); - } - { - // But repeating a length overflows the code. - HpackHuffmanSymbol code[] = { - {0b00000000000000000000000000000000, 1, 0}, - {0b10000000000000000000000000000000, 2, 1}, - {0b11000000000000000000000000000000, 2, 2}, - {0b00000000000000000000000000000000, 8, 3}}; // Overflow. - HpackHuffmanTable table; - EXPECT_FALSE(table.Initialize(code, SPDY_ARRAYSIZE(code))); - EXPECT_EQ(3, HpackHuffmanTablePeer(table).failed_symbol_id()); - } - { - // Symbol IDs must be assigned sequentially with no gaps. - HpackHuffmanSymbol code[] = { - {0b00000000000000000000000000000000, 1, 0}, - {0b10000000000000000000000000000000, 2, 1}, - {0b11000000000000000000000000000000, 3, 1}, // Repeat. - {0b11100000000000000000000000000000, 8, 3}}; - HpackHuffmanTable table; - EXPECT_FALSE(table.Initialize(code, SPDY_ARRAYSIZE(code))); - EXPECT_EQ(2, HpackHuffmanTablePeer(table).failed_symbol_id()); - } - { - // Canonical codes must begin with zero. - HpackHuffmanSymbol code[] = {{0b10000000000000000000000000000000, 4, 0}, - {0b10010000000000000000000000000000, 4, 1}, - {0b10100000000000000000000000000000, 4, 2}, - {0b10110000000000000000000000000000, 8, 3}}; - HpackHuffmanTable table; - EXPECT_FALSE(table.Initialize(code, SPDY_ARRAYSIZE(code))); - EXPECT_EQ(0, HpackHuffmanTablePeer(table).failed_symbol_id()); - } - { - // Codes must match the expected canonical sequence. - HpackHuffmanSymbol code[] = { - {0b00000000000000000000000000000000, 2, 0}, - {0b01000000000000000000000000000000, 2, 1}, - {0b11000000000000000000000000000000, 2, 2}, // Code not canonical. - {0b10000000000000000000000000000000, 8, 3}}; - HpackHuffmanTable table; - EXPECT_FALSE(table.Initialize(code, SPDY_ARRAYSIZE(code))); - EXPECT_EQ(2, HpackHuffmanTablePeer(table).failed_symbol_id()); - } - { - // At least one code must have a length of 8 bits (to ensure pad-ability). - HpackHuffmanSymbol code[] = {{0b00000000000000000000000000000000, 1, 0}, - {0b10000000000000000000000000000000, 2, 1}, - {0b11000000000000000000000000000000, 3, 2}, - {0b11100000000000000000000000000000, 7, 3}}; - HpackHuffmanTable table; - EXPECT_FALSE(table.Initialize(code, SPDY_ARRAYSIZE(code))); - } -} - -TEST_F(GenericHuffmanTableTest, ValidateInternalsWithSmallCode) { - HpackHuffmanSymbol code[] = { - {0b01100000000000000000000000000000, 4, 0}, // 3rd. - {0b01110000000000000000000000000000, 4, 1}, // 4th. - {0b00000000000000000000000000000000, 2, 2}, // 1st assigned code. - {0b01000000000000000000000000000000, 3, 3}, // 2nd. - {0b10000000000000000000000000000000, 5, 4}, // 5th. - {0b10001000000000000000000000000000, 5, 5}, // 6th. - {0b10011000000000000000000000000000, 8, 6}, // 8th. - {0b10010000000000000000000000000000, 5, 7}}; // 7th. - EXPECT_TRUE(table_.Initialize(code, SPDY_ARRAYSIZE(code))); - - ASSERT_EQ(SPDY_ARRAYSIZE(code), peer_.code_by_id().size()); - ASSERT_EQ(SPDY_ARRAYSIZE(code), peer_.length_by_id().size()); - for (size_t i = 0; i < SPDY_ARRAYSIZE(code); ++i) { - EXPECT_EQ(code[i].code, peer_.code_by_id()[i]); - EXPECT_EQ(code[i].length, peer_.length_by_id()[i]); - } - - EXPECT_EQ(0b10011000, peer_.pad_bits()); - - char input_storage[] = {2, 3, 2, 7, 4}; - SpdyStringPiece input(input_storage, SPDY_ARRAYSIZE(input_storage)); - // By symbol: (2) 00 (3) 010 (2) 00 (7) 10010 (4) 10000 (6 as pad) 1001100. - char expect_storage[] = {0b00010001, 0b00101000, 0b01001100}; - SpdyStringPiece expect(expect_storage, SPDY_ARRAYSIZE(expect_storage)); - EXPECT_EQ(expect, EncodeString(input)); -} - -// Tests of the ability to encode the HPACK Huffman Code, defined in: -// https://httpwg.github.io/specs/rfc7541.html#huffman.code -class HpackHuffmanTableTest : public GenericHuffmanTableTest { - protected: - void SetUp() override { - EXPECT_TRUE(table_.Initialize(HpackHuffmanCodeVector().data(), - HpackHuffmanCodeVector().size())); - EXPECT_TRUE(table_.IsInitialized()); - } - - // Use http2::HpackHuffmanDecoder for roundtrip tests. - void DecodeString(const SpdyString& encoded, SpdyString* out) { - http2::HpackHuffmanDecoder decoder; - out->clear(); - EXPECT_TRUE(decoder.Decode(encoded, out)); - } -}; - -TEST_F(HpackHuffmanTableTest, InitializeHpackCode) { - EXPECT_EQ(peer_.pad_bits(), 0b11111111); // First 8 bits of EOS. -} - -TEST_F(HpackHuffmanTableTest, SpecRequestExamples) { - SpdyString buffer; - SpdyString test_table[] = { - SpdyHexDecode("f1e3c2e5f23a6ba0ab90f4ff"), - "www.example.com", - SpdyHexDecode("a8eb10649cbf"), - "no-cache", - SpdyHexDecode("25a849e95ba97d7f"), - "custom-key", - SpdyHexDecode("25a849e95bb8e8b4bf"), - "custom-value", - }; - // Round-trip each test example. - for (size_t i = 0; i != SPDY_ARRAYSIZE(test_table); i += 2) { - const SpdyString& encodedFixture(test_table[i]); - const SpdyString& decodedFixture(test_table[i + 1]); - DecodeString(encodedFixture, &buffer); - EXPECT_EQ(decodedFixture, buffer); - buffer = EncodeString(decodedFixture); - EXPECT_EQ(encodedFixture, buffer); - } -} - -TEST_F(HpackHuffmanTableTest, SpecResponseExamples) { - SpdyString buffer; - SpdyString test_table[] = { - SpdyHexDecode("6402"), - "302", - SpdyHexDecode("aec3771a4b"), - "private", - SpdyHexDecode("d07abe941054d444a8200595040b8166" - "e082a62d1bff"), - "Mon, 21 Oct 2013 20:13:21 GMT", - SpdyHexDecode("9d29ad171863c78f0b97c8e9ae82ae43" - "d3"), - "https://www.example.com", - SpdyHexDecode("94e7821dd7f2e6c7b335dfdfcd5b3960" - "d5af27087f3672c1ab270fb5291f9587" - "316065c003ed4ee5b1063d5007"), - "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", - }; - // Round-trip each test example. - for (size_t i = 0; i != SPDY_ARRAYSIZE(test_table); i += 2) { - const SpdyString& encodedFixture(test_table[i]); - const SpdyString& decodedFixture(test_table[i + 1]); - DecodeString(encodedFixture, &buffer); - EXPECT_EQ(decodedFixture, buffer); - buffer = EncodeString(decodedFixture); - EXPECT_EQ(encodedFixture, buffer); - } -} - -TEST_F(HpackHuffmanTableTest, RoundTripIndividualSymbols) { - for (size_t i = 0; i != 256; i++) { - char c = static_cast<char>(i); - char storage[3] = {c, c, c}; - SpdyStringPiece input(storage, SPDY_ARRAYSIZE(storage)); - SpdyString buffer_in = EncodeString(input); - SpdyString buffer_out; - DecodeString(buffer_in, &buffer_out); - EXPECT_EQ(input, buffer_out); - } -} - -TEST_F(HpackHuffmanTableTest, RoundTripSymbolSequence) { - char storage[512]; - for (size_t i = 0; i != 256; i++) { - storage[i] = static_cast<char>(i); - storage[511 - i] = static_cast<char>(i); - } - SpdyStringPiece input(storage, SPDY_ARRAYSIZE(storage)); - SpdyString buffer_in = EncodeString(input); - SpdyString buffer_out; - DecodeString(buffer_in, &buffer_out); - EXPECT_EQ(input, buffer_out); -} - -TEST_F(HpackHuffmanTableTest, EncodedSizeAgreesWithEncodeString) { - SpdyString test_table[] = { - "", - "Mon, 21 Oct 2013 20:13:21 GMT", - "https://www.example.com", - "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", - SpdyString(1, '\0'), - SpdyString("foo\0bar", 7), - SpdyString(256, '\0'), - }; - for (size_t i = 0; i != 256; ++i) { - // Expand last |test_table| entry to cover all codes. - test_table[SPDY_ARRAYSIZE(test_table) - 1][i] = static_cast<char>(i); - } - - HpackOutputStream output_stream; - SpdyString encoding; - for (size_t i = 0; i != SPDY_ARRAYSIZE(test_table); ++i) { - table_.EncodeString(test_table[i], &output_stream); - output_stream.TakeString(&encoding); - EXPECT_EQ(encoding.size(), table_.EncodedSize(test_table[i])); - } -} - -} // namespace - -} // namespace test - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_output_stream.cc b/net/third_party/spdy/core/hpack/hpack_output_stream.cc deleted file mode 100644 index d578cc9..0000000 --- a/net/third_party/spdy/core/hpack/hpack_output_stream.cc +++ /dev/null
@@ -1,97 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_output_stream.h" - -#include <utility> - -#include "base/logging.h" -#include "net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h" - -namespace spdy { - -HpackOutputStream::HpackOutputStream() : bit_offset_(0) {} - -HpackOutputStream::~HpackOutputStream() = default; - -void HpackOutputStream::AppendBits(uint8_t bits, size_t bit_size) { - DCHECK_GT(bit_size, 0u); - DCHECK_LE(bit_size, 8u); - DCHECK_EQ(bits >> bit_size, 0); - size_t new_bit_offset = bit_offset_ + bit_size; - if (bit_offset_ == 0) { - // Buffer ends on a byte boundary. - DCHECK_LE(bit_size, 8u); - buffer_.append(1, bits << (8 - bit_size)); - } else if (new_bit_offset <= 8) { - // Buffer does not end on a byte boundary but the given bits fit - // in the remainder of the last byte. - buffer_.back() |= bits << (8 - new_bit_offset); - } else { - // Buffer does not end on a byte boundary and the given bits do - // not fit in the remainder of the last byte. - buffer_.back() |= bits >> (new_bit_offset - 8); - buffer_.append(1, bits << (16 - new_bit_offset)); - } - bit_offset_ = new_bit_offset % 8; -} - -void HpackOutputStream::AppendPrefix(HpackPrefix prefix) { - AppendBits(prefix.bits, prefix.bit_size); -} - -void HpackOutputStream::AppendBytes(SpdyStringPiece buffer) { - DCHECK_EQ(bit_offset_, 0u); - buffer_.append(buffer.data(), buffer.size()); -} - -void HpackOutputStream::AppendUint32(uint32_t I) { - // The algorithm below is adapted from the pseudocode in 6.1. - size_t N = 8 - bit_offset_; - uint8_t max_first_byte = static_cast<uint8_t>((1 << N) - 1); - if (I < max_first_byte) { - AppendBits(static_cast<uint8_t>(I), N); - } else { - AppendBits(max_first_byte, N); - I -= max_first_byte; - while ((I & ~0x7f) != 0) { - buffer_.append(1, (I & 0x7f) | 0x80); - I >>= 7; - } - AppendBits(static_cast<uint8_t>(I), 8); - } -} - -void HpackOutputStream::TakeString(SpdyString* output) { - // This must hold, since all public functions cause the buffer to - // end on a byte boundary. - DCHECK_EQ(bit_offset_, 0u); - buffer_.swap(*output); - buffer_.clear(); - bit_offset_ = 0; -} - -void HpackOutputStream::BoundedTakeString(size_t max_size, SpdyString* output) { - if (buffer_.size() > max_size) { - // Save off overflow bytes to temporary string (causes a copy). - SpdyString overflow(buffer_.data() + max_size, buffer_.size() - max_size); - - // Resize buffer down to the given limit. - buffer_.resize(max_size); - - // Give buffer to output string. - *output = std::move(buffer_); - - // Reset to contain overflow. - buffer_ = std::move(overflow); - } else { - TakeString(output); - } -} - -size_t HpackOutputStream::EstimateMemoryUsage() const { - return SpdyEstimateMemoryUsage(buffer_); -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_output_stream.h b/net/third_party/spdy/core/hpack/hpack_output_stream.h deleted file mode 100644 index 309da2b..0000000 --- a/net/third_party/spdy/core/hpack/hpack_output_stream.h +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_OUTPUT_STREAM_H_ -#define NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_OUTPUT_STREAM_H_ - -#include <cstdint> -#include <map> - -#include "base/macros.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -// All section references below are to -// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08 - -namespace spdy { - -// An HpackOutputStream handles all the low-level details of encoding -// header fields. -class SPDY_EXPORT_PRIVATE HpackOutputStream { - public: - HpackOutputStream(); - HpackOutputStream(const HpackOutputStream&) = delete; - HpackOutputStream& operator=(const HpackOutputStream&) = delete; - ~HpackOutputStream(); - - // Appends the lower |bit_size| bits of |bits| to the internal buffer. - // - // |bit_size| must be > 0 and <= 8. |bits| must not have any bits - // set other than the lower |bit_size| bits. - void AppendBits(uint8_t bits, size_t bit_size); - - // Simply forwards to AppendBits(prefix.bits, prefix.bit-size). - void AppendPrefix(HpackPrefix prefix); - - // Directly appends |buffer|. - void AppendBytes(SpdyStringPiece buffer); - - // Appends the given integer using the representation described in - // 6.1. If the internal buffer ends on a byte boundary, the prefix - // length N is taken to be 8; otherwise, it is taken to be the - // number of bits to the next byte boundary. - // - // It is guaranteed that the internal buffer will end on a byte - // boundary after this function is called. - void AppendUint32(uint32_t I); - - // Swaps the internal buffer with |output|, then resets state. - void TakeString(SpdyString* output); - - // Gives up to |max_size| bytes of the internal buffer to |output|. Resets - // internal state with the overflow. - void BoundedTakeString(size_t max_size, SpdyString* output); - - // Size in bytes of stream's internal buffer. - size_t size() const { return buffer_.size(); } - - // Returns the estimate of dynamically allocated memory in bytes. - size_t EstimateMemoryUsage() const; - - private: - // The internal bit buffer. - SpdyString buffer_; - - // If 0, the buffer ends on a byte boundary. If non-zero, the buffer - // ends on the nth most significant bit. Guaranteed to be < 8. - size_t bit_offset_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_OUTPUT_STREAM_H_
diff --git a/net/third_party/spdy/core/hpack/hpack_output_stream_test.cc b/net/third_party/spdy/core/hpack/hpack_output_stream_test.cc deleted file mode 100644 index 18d65ef..0000000 --- a/net/third_party/spdy/core/hpack/hpack_output_stream_test.cc +++ /dev/null
@@ -1,276 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_output_stream.h" - -#include <cstddef> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -namespace { - -// Make sure that AppendBits() appends bits starting from the most -// significant bit, and that it can handle crossing a byte boundary. -TEST(HpackOutputStreamTest, AppendBits) { - HpackOutputStream output_stream; - SpdyString expected_str; - - output_stream.AppendBits(0x1, 1); - expected_str.append(1, 0x00); - expected_str.back() |= (0x1 << 7); - - output_stream.AppendBits(0x0, 1); - - output_stream.AppendBits(0x3, 2); - *expected_str.rbegin() |= (0x3 << 4); - - output_stream.AppendBits(0x0, 2); - - // Byte-crossing append. - output_stream.AppendBits(0x7, 3); - *expected_str.rbegin() |= (0x7 >> 1); - expected_str.append(1, 0x00); - expected_str.back() |= (0x7 << 7); - - output_stream.AppendBits(0x0, 7); - - SpdyString str; - output_stream.TakeString(&str); - EXPECT_EQ(expected_str, str); -} - -// Utility function to return I as a string encoded with an N-bit -// prefix. -SpdyString EncodeUint32(uint8_t N, uint32_t I) { - HpackOutputStream output_stream; - if (N < 8) { - output_stream.AppendBits(0x00, 8 - N); - } - output_stream.AppendUint32(I); - SpdyString str; - output_stream.TakeString(&str); - return str; -} - -// The {Number}ByteIntegersEightBitPrefix tests below test that -// certain integers are encoded correctly with an 8-bit prefix in -// exactly {Number} bytes. - -TEST(HpackOutputStreamTest, OneByteIntegersEightBitPrefix) { - // Minimum. - EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(8, 0x00)); - EXPECT_EQ("\x7f", EncodeUint32(8, 0x7f)); - // Maximum. - EXPECT_EQ("\xfe", EncodeUint32(8, 0xfe)); -} - -TEST(HpackOutputStreamTest, TwoByteIntegersEightBitPrefix) { - // Minimum. - EXPECT_EQ(SpdyString("\xff\x00", 2), EncodeUint32(8, 0xff)); - EXPECT_EQ("\xff\x01", EncodeUint32(8, 0x0100)); - // Maximum. - EXPECT_EQ("\xff\x7f", EncodeUint32(8, 0x017e)); -} - -TEST(HpackOutputStreamTest, ThreeByteIntegersEightBitPrefix) { - // Minimum. - EXPECT_EQ("\xff\x80\x01", EncodeUint32(8, 0x017f)); - EXPECT_EQ("\xff\x80\x1e", EncodeUint32(8, 0x0fff)); - // Maximum. - EXPECT_EQ("\xff\xff\x7f", EncodeUint32(8, 0x40fe)); -} - -TEST(HpackOutputStreamTest, FourByteIntegersEightBitPrefix) { - // Minimum. - EXPECT_EQ("\xff\x80\x80\x01", EncodeUint32(8, 0x40ff)); - EXPECT_EQ("\xff\x80\xfe\x03", EncodeUint32(8, 0xffff)); - // Maximum. - EXPECT_EQ("\xff\xff\xff\x7f", EncodeUint32(8, 0x002000fe)); -} - -TEST(HpackOutputStreamTest, FiveByteIntegersEightBitPrefix) { - // Minimum. - EXPECT_EQ("\xff\x80\x80\x80\x01", EncodeUint32(8, 0x002000ff)); - EXPECT_EQ("\xff\x80\xfe\xff\x07", EncodeUint32(8, 0x00ffffff)); - // Maximum. - EXPECT_EQ("\xff\xff\xff\xff\x7f", EncodeUint32(8, 0x100000fe)); -} - -TEST(HpackOutputStreamTest, SixByteIntegersEightBitPrefix) { - // Minimum. - EXPECT_EQ("\xff\x80\x80\x80\x80\x01", EncodeUint32(8, 0x100000ff)); - // Maximum. - EXPECT_EQ("\xff\x80\xfe\xff\xff\x0f", EncodeUint32(8, 0xffffffff)); -} - -// The {Number}ByteIntegersOneToSevenBitPrefix tests below test that -// certain integers are encoded correctly with an N-bit prefix in -// exactly {Number} bytes for N in {1, 2, ..., 7}. - -TEST(HpackOutputStreamTest, OneByteIntegersOneToSevenBitPrefixes) { - // Minimums. - EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(7, 0x00)); - EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(6, 0x00)); - EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(5, 0x00)); - EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(4, 0x00)); - EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(3, 0x00)); - EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(2, 0x00)); - EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(1, 0x00)); - - // Maximums. - EXPECT_EQ("\x7e", EncodeUint32(7, 0x7e)); - EXPECT_EQ("\x3e", EncodeUint32(6, 0x3e)); - EXPECT_EQ("\x1e", EncodeUint32(5, 0x1e)); - EXPECT_EQ("\x0e", EncodeUint32(4, 0x0e)); - EXPECT_EQ("\x06", EncodeUint32(3, 0x06)); - EXPECT_EQ("\x02", EncodeUint32(2, 0x02)); - EXPECT_EQ(SpdyString("\x00", 1), EncodeUint32(1, 0x00)); -} - -TEST(HpackOutputStreamTest, TwoByteIntegersOneToSevenBitPrefixes) { - // Minimums. - EXPECT_EQ(SpdyString("\x7f\x00", 2), EncodeUint32(7, 0x7f)); - EXPECT_EQ(SpdyString("\x3f\x00", 2), EncodeUint32(6, 0x3f)); - EXPECT_EQ(SpdyString("\x1f\x00", 2), EncodeUint32(5, 0x1f)); - EXPECT_EQ(SpdyString("\x0f\x00", 2), EncodeUint32(4, 0x0f)); - EXPECT_EQ(SpdyString("\x07\x00", 2), EncodeUint32(3, 0x07)); - EXPECT_EQ(SpdyString("\x03\x00", 2), EncodeUint32(2, 0x03)); - EXPECT_EQ(SpdyString("\x01\x00", 2), EncodeUint32(1, 0x01)); - - // Maximums. - EXPECT_EQ("\x7f\x7f", EncodeUint32(7, 0xfe)); - EXPECT_EQ("\x3f\x7f", EncodeUint32(6, 0xbe)); - EXPECT_EQ("\x1f\x7f", EncodeUint32(5, 0x9e)); - EXPECT_EQ("\x0f\x7f", EncodeUint32(4, 0x8e)); - EXPECT_EQ("\x07\x7f", EncodeUint32(3, 0x86)); - EXPECT_EQ("\x03\x7f", EncodeUint32(2, 0x82)); - EXPECT_EQ("\x01\x7f", EncodeUint32(1, 0x80)); -} - -TEST(HpackOutputStreamTest, ThreeByteIntegersOneToSevenBitPrefixes) { - // Minimums. - EXPECT_EQ("\x7f\x80\x01", EncodeUint32(7, 0xff)); - EXPECT_EQ("\x3f\x80\x01", EncodeUint32(6, 0xbf)); - EXPECT_EQ("\x1f\x80\x01", EncodeUint32(5, 0x9f)); - EXPECT_EQ("\x0f\x80\x01", EncodeUint32(4, 0x8f)); - EXPECT_EQ("\x07\x80\x01", EncodeUint32(3, 0x87)); - EXPECT_EQ("\x03\x80\x01", EncodeUint32(2, 0x83)); - EXPECT_EQ("\x01\x80\x01", EncodeUint32(1, 0x81)); - - // Maximums. - EXPECT_EQ("\x7f\xff\x7f", EncodeUint32(7, 0x407e)); - EXPECT_EQ("\x3f\xff\x7f", EncodeUint32(6, 0x403e)); - EXPECT_EQ("\x1f\xff\x7f", EncodeUint32(5, 0x401e)); - EXPECT_EQ("\x0f\xff\x7f", EncodeUint32(4, 0x400e)); - EXPECT_EQ("\x07\xff\x7f", EncodeUint32(3, 0x4006)); - EXPECT_EQ("\x03\xff\x7f", EncodeUint32(2, 0x4002)); - EXPECT_EQ("\x01\xff\x7f", EncodeUint32(1, 0x4000)); -} - -TEST(HpackOutputStreamTest, FourByteIntegersOneToSevenBitPrefixes) { - // Minimums. - EXPECT_EQ("\x7f\x80\x80\x01", EncodeUint32(7, 0x407f)); - EXPECT_EQ("\x3f\x80\x80\x01", EncodeUint32(6, 0x403f)); - EXPECT_EQ("\x1f\x80\x80\x01", EncodeUint32(5, 0x401f)); - EXPECT_EQ("\x0f\x80\x80\x01", EncodeUint32(4, 0x400f)); - EXPECT_EQ("\x07\x80\x80\x01", EncodeUint32(3, 0x4007)); - EXPECT_EQ("\x03\x80\x80\x01", EncodeUint32(2, 0x4003)); - EXPECT_EQ("\x01\x80\x80\x01", EncodeUint32(1, 0x4001)); - - // Maximums. - EXPECT_EQ("\x7f\xff\xff\x7f", EncodeUint32(7, 0x20007e)); - EXPECT_EQ("\x3f\xff\xff\x7f", EncodeUint32(6, 0x20003e)); - EXPECT_EQ("\x1f\xff\xff\x7f", EncodeUint32(5, 0x20001e)); - EXPECT_EQ("\x0f\xff\xff\x7f", EncodeUint32(4, 0x20000e)); - EXPECT_EQ("\x07\xff\xff\x7f", EncodeUint32(3, 0x200006)); - EXPECT_EQ("\x03\xff\xff\x7f", EncodeUint32(2, 0x200002)); - EXPECT_EQ("\x01\xff\xff\x7f", EncodeUint32(1, 0x200000)); -} - -TEST(HpackOutputStreamTest, FiveByteIntegersOneToSevenBitPrefixes) { - // Minimums. - EXPECT_EQ("\x7f\x80\x80\x80\x01", EncodeUint32(7, 0x20007f)); - EXPECT_EQ("\x3f\x80\x80\x80\x01", EncodeUint32(6, 0x20003f)); - EXPECT_EQ("\x1f\x80\x80\x80\x01", EncodeUint32(5, 0x20001f)); - EXPECT_EQ("\x0f\x80\x80\x80\x01", EncodeUint32(4, 0x20000f)); - EXPECT_EQ("\x07\x80\x80\x80\x01", EncodeUint32(3, 0x200007)); - EXPECT_EQ("\x03\x80\x80\x80\x01", EncodeUint32(2, 0x200003)); - EXPECT_EQ("\x01\x80\x80\x80\x01", EncodeUint32(1, 0x200001)); - - // Maximums. - EXPECT_EQ("\x7f\xff\xff\xff\x7f", EncodeUint32(7, 0x1000007e)); - EXPECT_EQ("\x3f\xff\xff\xff\x7f", EncodeUint32(6, 0x1000003e)); - EXPECT_EQ("\x1f\xff\xff\xff\x7f", EncodeUint32(5, 0x1000001e)); - EXPECT_EQ("\x0f\xff\xff\xff\x7f", EncodeUint32(4, 0x1000000e)); - EXPECT_EQ("\x07\xff\xff\xff\x7f", EncodeUint32(3, 0x10000006)); - EXPECT_EQ("\x03\xff\xff\xff\x7f", EncodeUint32(2, 0x10000002)); - EXPECT_EQ("\x01\xff\xff\xff\x7f", EncodeUint32(1, 0x10000000)); -} - -TEST(HpackOutputStreamTest, SixByteIntegersOneToSevenBitPrefixes) { - // Minimums. - EXPECT_EQ("\x7f\x80\x80\x80\x80\x01", EncodeUint32(7, 0x1000007f)); - EXPECT_EQ("\x3f\x80\x80\x80\x80\x01", EncodeUint32(6, 0x1000003f)); - EXPECT_EQ("\x1f\x80\x80\x80\x80\x01", EncodeUint32(5, 0x1000001f)); - EXPECT_EQ("\x0f\x80\x80\x80\x80\x01", EncodeUint32(4, 0x1000000f)); - EXPECT_EQ("\x07\x80\x80\x80\x80\x01", EncodeUint32(3, 0x10000007)); - EXPECT_EQ("\x03\x80\x80\x80\x80\x01", EncodeUint32(2, 0x10000003)); - EXPECT_EQ("\x01\x80\x80\x80\x80\x01", EncodeUint32(1, 0x10000001)); - - // Maximums. - EXPECT_EQ("\x7f\x80\xff\xff\xff\x0f", EncodeUint32(7, 0xffffffff)); - EXPECT_EQ("\x3f\xc0\xff\xff\xff\x0f", EncodeUint32(6, 0xffffffff)); - EXPECT_EQ("\x1f\xe0\xff\xff\xff\x0f", EncodeUint32(5, 0xffffffff)); - EXPECT_EQ("\x0f\xf0\xff\xff\xff\x0f", EncodeUint32(4, 0xffffffff)); - EXPECT_EQ("\x07\xf8\xff\xff\xff\x0f", EncodeUint32(3, 0xffffffff)); - EXPECT_EQ("\x03\xfc\xff\xff\xff\x0f", EncodeUint32(2, 0xffffffff)); - EXPECT_EQ("\x01\xfe\xff\xff\xff\x0f", EncodeUint32(1, 0xffffffff)); -} - -// Test that encoding an integer with an N-bit prefix preserves the -// upper (8-N) bits of the first byte. -TEST(HpackOutputStreamTest, AppendUint32PreservesUpperBits) { - HpackOutputStream output_stream; - output_stream.AppendBits(0x7f, 7); - output_stream.AppendUint32(0x01); - SpdyString str; - output_stream.TakeString(&str); - EXPECT_EQ(SpdyString("\xff\x00", 2), str); -} - -TEST(HpackOutputStreamTest, AppendBytes) { - HpackOutputStream output_stream; - - output_stream.AppendBytes("buffer1"); - output_stream.AppendBytes("buffer2"); - - SpdyString str; - output_stream.TakeString(&str); - EXPECT_EQ("buffer1buffer2", str); -} - -TEST(HpackOutputStreamTest, BoundedTakeString) { - HpackOutputStream output_stream; - - output_stream.AppendBytes("buffer12"); - output_stream.AppendBytes("buffer456"); - - SpdyString str; - output_stream.BoundedTakeString(9, &str); - EXPECT_EQ("buffer12b", str); - - output_stream.AppendBits(0x7f, 7); - output_stream.AppendUint32(0x11); - output_stream.BoundedTakeString(9, &str); - EXPECT_EQ("uffer456\xff", str); - - output_stream.BoundedTakeString(9, &str); - EXPECT_EQ("\x10", str); -} - -} // namespace - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_round_trip_test.cc b/net/third_party/spdy/core/hpack/hpack_round_trip_test.cc deleted file mode 100644 index 774dd29..0000000 --- a/net/third_party/spdy/core/hpack/hpack_round_trip_test.cc +++ /dev/null
@@ -1,227 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <cmath> -#include <cstdint> -#include <ctime> -#include <vector> - -#include "net/third_party/quiche/src/http2/test_tools/http2_random.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/hpack/hpack_decoder_adapter.h" -#include "net/third_party/spdy/core/hpack/hpack_encoder.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { -namespace test { - -namespace { - -// Supports testing with the input split at every byte boundary. -enum InputSizeParam { ALL_INPUT, ONE_BYTE, ZERO_THEN_ONE_BYTE }; - -class HpackRoundTripTest : public ::testing::TestWithParam<InputSizeParam> { - protected: - HpackRoundTripTest() : encoder_(ObtainHpackHuffmanTable()), decoder_() {} - - void SetUp() override { - // Use a small table size to tickle eviction handling. - encoder_.ApplyHeaderTableSizeSetting(256); - decoder_.ApplyHeaderTableSizeSetting(256); - } - - bool RoundTrip(const SpdyHeaderBlock& header_set) { - SpdyString encoded; - encoder_.EncodeHeaderSet(header_set, &encoded); - - bool success = true; - if (GetParam() == ALL_INPUT) { - // Pass all the input to the decoder at once. - success = decoder_.HandleControlFrameHeadersData(encoded.data(), - encoded.size()); - } else if (GetParam() == ONE_BYTE) { - // Pass the input to the decoder one byte at a time. - const char* data = encoded.data(); - for (size_t ndx = 0; ndx < encoded.size() && success; ++ndx) { - success = decoder_.HandleControlFrameHeadersData(data + ndx, 1); - } - } else if (GetParam() == ZERO_THEN_ONE_BYTE) { - // Pass the input to the decoder one byte at a time, but before each - // byte pass an empty buffer. - const char* data = encoded.data(); - for (size_t ndx = 0; ndx < encoded.size() && success; ++ndx) { - success = (decoder_.HandleControlFrameHeadersData(data + ndx, 0) && - decoder_.HandleControlFrameHeadersData(data + ndx, 1)); - } - } else { - ADD_FAILURE() << "Unknown param: " << GetParam(); - } - - if (success) { - success = decoder_.HandleControlFrameHeadersComplete(nullptr); - } - - EXPECT_EQ(header_set, decoder_.decoded_block()); - return success; - } - - size_t SampleExponential(size_t mean, size_t sanity_bound) { - return std::min<size_t>(-std::log(random_.RandDouble()) * mean, - sanity_bound); - } - - http2::test::Http2Random random_; - HpackEncoder encoder_; - HpackDecoderAdapter decoder_; -}; - -INSTANTIATE_TEST_CASE_P(Tests, - HpackRoundTripTest, - ::testing::Values(ALL_INPUT, - ONE_BYTE, - ZERO_THEN_ONE_BYTE)); - -TEST_P(HpackRoundTripTest, ResponseFixtures) { - { - SpdyHeaderBlock headers; - headers[":status"] = "302"; - headers["cache-control"] = "private"; - headers["date"] = "Mon, 21 Oct 2013 20:13:21 GMT"; - headers["location"] = "https://www.example.com"; - EXPECT_TRUE(RoundTrip(headers)); - } - { - SpdyHeaderBlock headers; - headers[":status"] = "200"; - headers["cache-control"] = "private"; - headers["date"] = "Mon, 21 Oct 2013 20:13:21 GMT"; - headers["location"] = "https://www.example.com"; - EXPECT_TRUE(RoundTrip(headers)); - } - { - SpdyHeaderBlock headers; - headers[":status"] = "200"; - headers["cache-control"] = "private"; - headers["content-encoding"] = "gzip"; - headers["date"] = "Mon, 21 Oct 2013 20:13:22 GMT"; - headers["location"] = "https://www.example.com"; - headers["set-cookie"] = - "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" - " max-age=3600; version=1"; - headers["multivalue"] = SpdyString("foo\0bar", 7); - EXPECT_TRUE(RoundTrip(headers)); - } -} - -TEST_P(HpackRoundTripTest, RequestFixtures) { - { - SpdyHeaderBlock headers; - headers[":authority"] = "www.example.com"; - headers[":method"] = "GET"; - headers[":path"] = "/"; - headers[":scheme"] = "http"; - headers["cookie"] = "baz=bing; foo=bar"; - EXPECT_TRUE(RoundTrip(headers)); - } - { - SpdyHeaderBlock headers; - headers[":authority"] = "www.example.com"; - headers[":method"] = "GET"; - headers[":path"] = "/"; - headers[":scheme"] = "http"; - headers["cache-control"] = "no-cache"; - headers["cookie"] = "foo=bar; spam=eggs"; - EXPECT_TRUE(RoundTrip(headers)); - } - { - SpdyHeaderBlock headers; - headers[":authority"] = "www.example.com"; - headers[":method"] = "GET"; - headers[":path"] = "/index.html"; - headers[":scheme"] = "https"; - headers["custom-key"] = "custom-value"; - headers["cookie"] = "baz=bing; fizzle=fazzle; garbage"; - headers["multivalue"] = SpdyString("foo\0bar", 7); - EXPECT_TRUE(RoundTrip(headers)); - } -} - -TEST_P(HpackRoundTripTest, RandomizedExamples) { - // Grow vectors of names & values, which are seeded with fixtures and then - // expanded with dynamically generated data. Samples are taken using the - // exponential distribution. - std::vector<SpdyString> pseudo_header_names, random_header_names; - pseudo_header_names.push_back(":authority"); - pseudo_header_names.push_back(":path"); - pseudo_header_names.push_back(":status"); - - // TODO(jgraettinger): Enable "cookie" as a name fixture. Crumbs may be - // reconstructed in any order, which breaks the simple validation used here. - - std::vector<SpdyString> values; - values.push_back("/"); - values.push_back("/index.html"); - values.push_back("200"); - values.push_back("404"); - values.push_back(""); - values.push_back("baz=bing; foo=bar; garbage"); - values.push_back("baz=bing; fizzle=fazzle; garbage"); - - for (size_t i = 0; i != 2000; ++i) { - SpdyHeaderBlock headers; - - // Choose a random number of headers to add, and of these a random subset - // will be HTTP/2 pseudo headers. - size_t header_count = 1 + SampleExponential(7, 50); - size_t pseudo_header_count = - std::min(header_count, 1 + SampleExponential(7, 50)); - EXPECT_LE(pseudo_header_count, header_count); - for (size_t j = 0; j != header_count; ++j) { - SpdyString name, value; - // Pseudo headers must be added before regular headers. - if (j < pseudo_header_count) { - // Choose one of the defined pseudo headers at random. - size_t name_index = random_.Uniform(pseudo_header_names.size()); - name = pseudo_header_names[name_index]; - } else { - // Randomly reuse an existing header name, or generate a new one. - size_t name_index = SampleExponential(20, 200); - if (name_index >= random_header_names.size()) { - name = random_.RandString(1 + SampleExponential(5, 30)); - // A regular header cannot begin with the pseudo header prefix ":". - if (name[0] == ':') { - name[0] = 'x'; - } - random_header_names.push_back(name); - } else { - name = random_header_names[name_index]; - } - } - - // Randomly reuse an existing value, or generate a new one. - size_t value_index = SampleExponential(20, 200); - if (value_index >= values.size()) { - SpdyString newvalue = random_.RandString(1 + SampleExponential(15, 75)); - // Currently order is not preserved in the encoder. In particular, - // when a value is decomposed at \0 delimiters, its parts might get - // encoded out of order if some but not all of them already exist in - // the header table. For now, avoid \0 bytes in values. - std::replace(newvalue.begin(), newvalue.end(), '\x00', '\x01'); - values.push_back(newvalue); - value = values.back(); - } else { - value = values[value_index]; - } - headers[name] = value; - } - EXPECT_TRUE(RoundTrip(headers)); - } -} - -} // namespace - -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_static_table.cc b/net/third_party/spdy/core/hpack/hpack_static_table.cc deleted file mode 100644 index 01a4930..0000000 --- a/net/third_party/spdy/core/hpack/hpack_static_table.cc +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_static_table.h" - -#include "base/logging.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/hpack/hpack_entry.h" -#include "net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { - -HpackStaticTable::HpackStaticTable() = default; - -HpackStaticTable::~HpackStaticTable() = default; - -void HpackStaticTable::Initialize(const HpackStaticEntry* static_entry_table, - size_t static_entry_count) { - CHECK(!IsInitialized()); - - int total_insertions = 0; - for (const HpackStaticEntry* it = static_entry_table; - it != static_entry_table + static_entry_count; ++it) { - static_entries_.push_back( - HpackEntry(SpdyStringPiece(it->name, it->name_len), - SpdyStringPiece(it->value, it->value_len), - true, // is_static - total_insertions)); - HpackEntry* entry = &static_entries_.back(); - CHECK(static_index_.insert(entry).second); - // Multiple static entries may have the same name, so inserts may fail. - static_name_index_.insert(std::make_pair(entry->name(), entry)); - - ++total_insertions; - } -} - -bool HpackStaticTable::IsInitialized() const { - return !static_entries_.empty(); -} - -size_t HpackStaticTable::EstimateMemoryUsage() const { - return SpdyEstimateMemoryUsage(static_entries_) + - SpdyEstimateMemoryUsage(static_index_) + - SpdyEstimateMemoryUsage(static_name_index_); -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/hpack/hpack_static_table.h b/net/third_party/spdy/core/hpack/hpack_static_table.h deleted file mode 100644 index e74da2c..0000000 --- a/net/third_party/spdy/core/hpack/hpack_static_table.h +++ /dev/null
@@ -1,54 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_STATIC_TABLE_H_ -#define NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_STATIC_TABLE_H_ - -#include "net/third_party/spdy/core/hpack/hpack_header_table.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" - -namespace spdy { - -struct HpackStaticEntry; - -// HpackStaticTable provides |static_entries_| and |static_index_| for HPACK -// encoding and decoding contexts. Once initialized, an instance is read only -// and may be accessed only through its const interface. Such an instance may -// be shared accross multiple HPACK contexts. -class SPDY_EXPORT_PRIVATE HpackStaticTable { - public: - HpackStaticTable(); - ~HpackStaticTable(); - - // Prepares HpackStaticTable by filling up static_entries_ and static_index_ - // from an array of struct HpackStaticEntry. Must be called exactly once. - void Initialize(const HpackStaticEntry* static_entry_table, - size_t static_entry_count); - - // Returns whether Initialize() has been called. - bool IsInitialized() const; - - // Accessors. - const HpackHeaderTable::EntryTable& GetStaticEntries() const { - return static_entries_; - } - const HpackHeaderTable::UnorderedEntrySet& GetStaticIndex() const { - return static_index_; - } - const HpackHeaderTable::NameToEntryMap& GetStaticNameIndex() const { - return static_name_index_; - } - - // Returns the estimate of dynamically allocated memory in bytes. - size_t EstimateMemoryUsage() const; - - private: - HpackHeaderTable::EntryTable static_entries_; - HpackHeaderTable::UnorderedEntrySet static_index_; - HpackHeaderTable::NameToEntryMap static_name_index_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_HPACK_HPACK_STATIC_TABLE_H_
diff --git a/net/third_party/spdy/core/hpack/hpack_static_table_test.cc b/net/third_party/spdy/core/hpack/hpack_static_table_test.cc deleted file mode 100644 index 3905743..0000000 --- a/net/third_party/spdy/core/hpack/hpack_static_table_test.cc +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/hpack/hpack_static_table.h" - -#include <set> -#include <vector> - -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -namespace test { - -namespace { - -class HpackStaticTableTest : public ::testing::Test { - protected: - HpackStaticTableTest() : table_() {} - - HpackStaticTable table_; -}; - -// Check that an initialized instance has the right number of entries. -TEST_F(HpackStaticTableTest, Initialize) { - EXPECT_FALSE(table_.IsInitialized()); - table_.Initialize(HpackStaticTableVector().data(), - HpackStaticTableVector().size()); - EXPECT_TRUE(table_.IsInitialized()); - - HpackHeaderTable::EntryTable static_entries = table_.GetStaticEntries(); - EXPECT_EQ(HpackStaticTableVector().size(), static_entries.size()); - - HpackHeaderTable::UnorderedEntrySet static_index = table_.GetStaticIndex(); - EXPECT_EQ(HpackStaticTableVector().size(), static_index.size()); - - HpackHeaderTable::NameToEntryMap static_name_index = - table_.GetStaticNameIndex(); - std::set<SpdyStringPiece> names; - for (auto* entry : static_index) { - names.insert(entry->name()); - } - EXPECT_EQ(names.size(), static_name_index.size()); -} - -// Test that ObtainHpackStaticTable returns the same instance every time. -TEST_F(HpackStaticTableTest, IsSingleton) { - const HpackStaticTable* static_table_one = &ObtainHpackStaticTable(); - const HpackStaticTable* static_table_two = &ObtainHpackStaticTable(); - EXPECT_EQ(static_table_one, static_table_two); -} - -} // namespace - -} // namespace test - -} // namespace spdy
diff --git a/net/third_party/spdy/core/http2_frame_decoder_adapter.cc b/net/third_party/spdy/core/http2_frame_decoder_adapter.cc deleted file mode 100644 index d63ec25..0000000 --- a/net/third_party/spdy/core/http2_frame_decoder_adapter.cc +++ /dev/null
@@ -1,1022 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/http2_frame_decoder_adapter.h" - -// Logging policy: If an error in the input is detected, VLOG(n) is used so that -// the option exists to debug the situation. Otherwise, this code mostly uses -// DVLOG so that the logging does not slow down production code when things are -// working OK. - -#include <stddef.h> - -#include <cstdint> -#include <cstring> -#include <utility> - -#include "base/logging.h" -#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h" -#include "net/third_party/quiche/src/http2/decoder/decode_status.h" -#include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder.h" -#include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder_listener.h" -#include "net/third_party/quiche/src/http2/http2_constants.h" -#include "net/third_party/quiche/src/http2/http2_structures.h" -#include "net/third_party/quiche/src/http2/platform/api/http2_string.h" -#include "net/third_party/spdy/core/hpack/hpack_decoder_adapter.h" -#include "net/third_party/spdy/core/hpack/hpack_header_table.h" -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_headers_handler_interface.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/platform/api/spdy_bug_tracker.h" -#include "net/third_party/spdy/platform/api/spdy_endianness_util.h" -#include "net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h" -#include "net/third_party/spdy/platform/api/spdy_flags.h" -#include "net/third_party/spdy/platform/api/spdy_ptr_util.h" -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" - -using ::spdy::ExtensionVisitorInterface; -using ::spdy::HpackDecoderAdapter; -using ::spdy::HpackHeaderTable; -using ::spdy::ParseErrorCode; -using ::spdy::ParseFrameType; -using ::spdy::SpdyAltSvcWireFormat; -using ::spdy::SpdyErrorCode; -using ::spdy::SpdyEstimateMemoryUsage; -using ::spdy::SpdyFramerDebugVisitorInterface; -using ::spdy::SpdyFramerVisitorInterface; -using ::spdy::SpdyFrameType; -using ::spdy::SpdyHeadersHandlerInterface; -using ::spdy::SpdyKnownSettingsId; -using ::spdy::SpdyMakeUnique; -using ::spdy::SpdySettingsId; - -namespace http2 { -namespace { - -const bool kHasPriorityFields = true; -const bool kNotHasPriorityFields = false; - -bool IsPaddable(Http2FrameType type) { - return type == Http2FrameType::DATA || type == Http2FrameType::HEADERS || - type == Http2FrameType::PUSH_PROMISE; -} - -SpdyFrameType ToSpdyFrameType(Http2FrameType type) { - return ParseFrameType(static_cast<uint8_t>(type)); -} - -uint64_t ToSpdyPingId(const Http2PingFields& ping) { - uint64_t v; - std::memcpy(&v, ping.opaque_bytes, Http2PingFields::EncodedSize()); - return spdy::SpdyNetToHost64(v); -} - -// Overwrites the fields of the header with invalid values, for the purpose -// of identifying reading of unset fields. Only takes effect for debug builds. -// In Address Sanatizer builds, it also marks the fields as un-readable. -void CorruptFrameHeader(Http2FrameHeader* header) { -#ifndef NDEBUG - // Beyond a valid payload length, which is 2^24 - 1. - header->payload_length = 0x1010dead; - // An unsupported frame type. - header->type = Http2FrameType(0x80); - DCHECK(!IsSupportedHttp2FrameType(header->type)); - // Frame flag bits that aren't used by any supported frame type. - header->flags = Http2FrameFlag(0xd2); - // A stream id with the reserved high-bit (R in the RFC) set. - // 2129510127 when the high-bit is cleared. - header->stream_id = 0xfeedbeef; -#endif -} - -} // namespace - -const char* Http2DecoderAdapter::StateToString(int state) { - switch (state) { - case SPDY_ERROR: - return "ERROR"; - case SPDY_FRAME_COMPLETE: - return "FRAME_COMPLETE"; - case SPDY_READY_FOR_FRAME: - return "READY_FOR_FRAME"; - case SPDY_READING_COMMON_HEADER: - return "READING_COMMON_HEADER"; - case SPDY_CONTROL_FRAME_PAYLOAD: - return "CONTROL_FRAME_PAYLOAD"; - case SPDY_READ_DATA_FRAME_PADDING_LENGTH: - return "SPDY_READ_DATA_FRAME_PADDING_LENGTH"; - case SPDY_CONSUME_PADDING: - return "SPDY_CONSUME_PADDING"; - case SPDY_IGNORE_REMAINING_PAYLOAD: - return "IGNORE_REMAINING_PAYLOAD"; - case SPDY_FORWARD_STREAM_FRAME: - return "FORWARD_STREAM_FRAME"; - case SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK: - return "SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK"; - case SPDY_CONTROL_FRAME_HEADER_BLOCK: - return "SPDY_CONTROL_FRAME_HEADER_BLOCK"; - case SPDY_GOAWAY_FRAME_PAYLOAD: - return "SPDY_GOAWAY_FRAME_PAYLOAD"; - case SPDY_SETTINGS_FRAME_HEADER: - return "SPDY_SETTINGS_FRAME_HEADER"; - case SPDY_SETTINGS_FRAME_PAYLOAD: - return "SPDY_SETTINGS_FRAME_PAYLOAD"; - case SPDY_ALTSVC_FRAME_PAYLOAD: - return "SPDY_ALTSVC_FRAME_PAYLOAD"; - } - return "UNKNOWN_STATE"; -} - -const char* Http2DecoderAdapter::SpdyFramerErrorToString( - SpdyFramerError spdy_framer_error) { - switch (spdy_framer_error) { - case SPDY_NO_ERROR: - return "NO_ERROR"; - case SPDY_INVALID_STREAM_ID: - return "INVALID_STREAM_ID"; - case SPDY_INVALID_CONTROL_FRAME: - return "INVALID_CONTROL_FRAME"; - case SPDY_CONTROL_PAYLOAD_TOO_LARGE: - return "CONTROL_PAYLOAD_TOO_LARGE"; - case SPDY_ZLIB_INIT_FAILURE: - return "ZLIB_INIT_FAILURE"; - case SPDY_UNSUPPORTED_VERSION: - return "UNSUPPORTED_VERSION"; - case SPDY_DECOMPRESS_FAILURE: - return "DECOMPRESS_FAILURE"; - case SPDY_COMPRESS_FAILURE: - return "COMPRESS_FAILURE"; - case SPDY_GOAWAY_FRAME_CORRUPT: - return "GOAWAY_FRAME_CORRUPT"; - case SPDY_RST_STREAM_FRAME_CORRUPT: - return "RST_STREAM_FRAME_CORRUPT"; - case SPDY_INVALID_PADDING: - return "INVALID_PADDING"; - case SPDY_INVALID_DATA_FRAME_FLAGS: - return "INVALID_DATA_FRAME_FLAGS"; - case SPDY_INVALID_CONTROL_FRAME_FLAGS: - return "INVALID_CONTROL_FRAME_FLAGS"; - case SPDY_UNEXPECTED_FRAME: - return "UNEXPECTED_FRAME"; - case SPDY_INTERNAL_FRAMER_ERROR: - return "INTERNAL_FRAMER_ERROR"; - case SPDY_INVALID_CONTROL_FRAME_SIZE: - return "INVALID_CONTROL_FRAME_SIZE"; - case SPDY_OVERSIZED_PAYLOAD: - return "OVERSIZED_PAYLOAD"; - case LAST_ERROR: - return "UNKNOWN_ERROR"; - } - return "UNKNOWN_ERROR"; -} - -Http2DecoderAdapter::Http2DecoderAdapter() { - DVLOG(1) << "Http2DecoderAdapter ctor"; - ResetInternal(); -} - -Http2DecoderAdapter::~Http2DecoderAdapter() = default; - -void Http2DecoderAdapter::set_visitor(SpdyFramerVisitorInterface* visitor) { - visitor_ = visitor; -} - -void Http2DecoderAdapter::set_debug_visitor( - SpdyFramerDebugVisitorInterface* debug_visitor) { - debug_visitor_ = debug_visitor; -} - -void Http2DecoderAdapter::set_process_single_input_frame(bool v) { - process_single_input_frame_ = v; -} - -void Http2DecoderAdapter::set_extension_visitor( - ExtensionVisitorInterface* visitor) { - extension_ = visitor; -} - -// Passes the call on to the HPACK decoder. -void Http2DecoderAdapter::SetDecoderHeaderTableDebugVisitor( - std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) { - GetHpackDecoder()->SetHeaderTableDebugVisitor(std::move(visitor)); -} - -size_t Http2DecoderAdapter::ProcessInput(const char* data, size_t len) { - size_t limit = recv_frame_size_limit_; - frame_decoder_->set_maximum_payload_size(limit); - - size_t total_processed = 0; - while (len > 0 && spdy_state_ != SPDY_ERROR) { - // Process one at a time so that we update the adapter's internal - // state appropriately. - const size_t processed = ProcessInputFrame(data, len); - - // We had some data, and weren't in an error state, so should have - // processed/consumed at least one byte of it, even if we then ended up - // in an error state. - DCHECK(processed > 0) << "processed=" << processed - << " spdy_state_=" << spdy_state_ - << " spdy_framer_error_=" << spdy_framer_error_; - - data += processed; - len -= processed; - total_processed += processed; - if (process_single_input_frame() || processed == 0) { - break; - } - } - return total_processed; -} - -void Http2DecoderAdapter::Reset() { - ResetInternal(); -} - -Http2DecoderAdapter::SpdyState Http2DecoderAdapter::state() const { - return spdy_state_; -} - -Http2DecoderAdapter::SpdyFramerError Http2DecoderAdapter::spdy_framer_error() - const { - return spdy_framer_error_; -} - -bool Http2DecoderAdapter::probable_http_response() const { - return latched_probable_http_response_; -} - -size_t Http2DecoderAdapter::EstimateMemoryUsage() const { - // Skip |frame_decoder_|, |frame_header_| and |hpack_first_frame_header_| as - // they don't allocate. - return SpdyEstimateMemoryUsage(alt_svc_origin_) + - SpdyEstimateMemoryUsage(alt_svc_value_); -} - -// =========================================================================== -// Implementations of the methods declared by Http2FrameDecoderListener. - -// Called once the common frame header has been decoded for any frame. -// This function is largely based on Http2DecoderAdapter::ValidateFrameHeader -// and some parts of Http2DecoderAdapter::ProcessCommonHeader. -bool Http2DecoderAdapter::OnFrameHeader(const Http2FrameHeader& header) { - DVLOG(1) << "OnFrameHeader: " << header; - decoded_frame_header_ = true; - if (!latched_probable_http_response_) { - latched_probable_http_response_ = header.IsProbableHttpResponse(); - } - const uint8_t raw_frame_type = static_cast<uint8_t>(header.type); - visitor()->OnCommonHeader(header.stream_id, header.payload_length, - raw_frame_type, header.flags); - if (has_expected_frame_type_ && header.type != expected_frame_type_) { - // Report an unexpected frame error and close the connection if we - // expect a known frame type (probably CONTINUATION) and receive an - // unknown frame. - VLOG(1) << "The framer was expecting to receive a " << expected_frame_type_ - << " frame, but instead received an unknown frame of type " - << header.type; - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); - return false; - } - if (!IsSupportedHttp2FrameType(header.type)) { - if (extension_ != nullptr) { - // Unknown frames will be passed to the registered extension. - return true; - } - // In HTTP2 we ignore unknown frame types for extensibility, as long as - // the rest of the control frame header is valid. - // We rely on the visitor to check validity of stream_id. - bool valid_stream = - visitor()->OnUnknownFrame(header.stream_id, raw_frame_type); - if (!valid_stream) { - // Report an invalid frame error if the stream_id is not valid. - VLOG(1) << "Unknown control frame type " << header.type - << " received on invalid stream " << header.stream_id; - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); - return false; - } else { - DVLOG(1) << "Ignoring unknown frame type " << header.type; - return true; - } - } - - SpdyFrameType frame_type = ToSpdyFrameType(header.type); - if (!IsValidHTTP2FrameStreamId(header.stream_id, frame_type)) { - VLOG(1) << "The framer received an invalid streamID of " << header.stream_id - << " for a frame of type " << header.type; - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID); - return false; - } - - if (has_expected_frame_type_ && header.type != expected_frame_type_) { - VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not " - << header.type; - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); - return false; - } - - if (!has_expected_frame_type_ && - header.type == Http2FrameType::CONTINUATION) { - VLOG(1) << "Got CONTINUATION frame when not expected."; - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); - return false; - } - - if (header.type == Http2FrameType::DATA) { - // For some reason SpdyFramer still rejects invalid DATA frame flags. - uint8_t valid_flags = Http2FrameFlag::PADDED | Http2FrameFlag::END_STREAM; - if (header.HasAnyFlags(~valid_flags)) { - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_DATA_FRAME_FLAGS); - return false; - } - } - - return true; -} - -void Http2DecoderAdapter::OnDataStart(const Http2FrameHeader& header) { - DVLOG(1) << "OnDataStart: " << header; - - if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { - frame_header_ = header; - has_frame_header_ = true; - visitor()->OnDataFrameHeader(header.stream_id, header.payload_length, - header.IsEndStream()); - } -} - -void Http2DecoderAdapter::OnDataPayload(const char* data, size_t len) { - DVLOG(1) << "OnDataPayload: len=" << len; - DCHECK(has_frame_header_); - DCHECK_EQ(frame_header_.type, Http2FrameType::DATA); - visitor()->OnStreamFrameData(frame_header().stream_id, data, len); -} - -void Http2DecoderAdapter::OnDataEnd() { - DVLOG(1) << "OnDataEnd"; - DCHECK(has_frame_header_); - DCHECK_EQ(frame_header_.type, Http2FrameType::DATA); - if (frame_header().IsEndStream()) { - visitor()->OnStreamEnd(frame_header().stream_id); - } - opt_pad_length_.reset(); -} - -void Http2DecoderAdapter::OnHeadersStart(const Http2FrameHeader& header) { - DVLOG(1) << "OnHeadersStart: " << header; - if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { - frame_header_ = header; - has_frame_header_ = true; - if (header.HasPriority()) { - // Once we've got the priority fields, then we can report the arrival - // of this HEADERS frame. - on_headers_called_ = false; - return; - } - on_headers_called_ = true; - ReportReceiveCompressedFrame(header); - visitor()->OnHeaders(header.stream_id, kNotHasPriorityFields, - 0, // priority - 0, // parent_stream_id - false, // exclusive - header.IsEndStream(), header.IsEndHeaders()); - CommonStartHpackBlock(); - } -} - -void Http2DecoderAdapter::OnHeadersPriority( - const Http2PriorityFields& priority) { - DVLOG(1) << "OnHeadersPriority: " << priority; - DCHECK(has_frame_header_); - DCHECK_EQ(frame_type(), Http2FrameType::HEADERS) << frame_header_; - DCHECK(frame_header_.HasPriority()); - DCHECK(!on_headers_called_); - on_headers_called_ = true; - ReportReceiveCompressedFrame(frame_header_); - visitor()->OnHeaders(frame_header_.stream_id, kHasPriorityFields, - priority.weight, priority.stream_dependency, - priority.is_exclusive, frame_header_.IsEndStream(), - frame_header_.IsEndHeaders()); - CommonStartHpackBlock(); -} - -void Http2DecoderAdapter::OnHpackFragment(const char* data, size_t len) { - DVLOG(1) << "OnHpackFragment: len=" << len; - on_hpack_fragment_called_ = true; - if (!GetHpackDecoder()->HandleControlFrameHeadersData(data, len)) { - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE); - return; - } -} - -void Http2DecoderAdapter::OnHeadersEnd() { - DVLOG(1) << "OnHeadersEnd"; - CommonHpackFragmentEnd(); - opt_pad_length_.reset(); -} - -void Http2DecoderAdapter::OnPriorityFrame(const Http2FrameHeader& header, - const Http2PriorityFields& priority) { - DVLOG(1) << "OnPriorityFrame: " << header << "; priority: " << priority; - if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { - visitor()->OnPriority(header.stream_id, priority.stream_dependency, - priority.weight, priority.is_exclusive); - } -} - -void Http2DecoderAdapter::OnContinuationStart(const Http2FrameHeader& header) { - DVLOG(1) << "OnContinuationStart: " << header; - if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { - DCHECK(has_hpack_first_frame_header_); - if (header.stream_id != hpack_first_frame_header_.stream_id) { - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); - return; - } - frame_header_ = header; - has_frame_header_ = true; - ReportReceiveCompressedFrame(header); - visitor()->OnContinuation(header.stream_id, header.IsEndHeaders()); - } -} - -void Http2DecoderAdapter::OnContinuationEnd() { - DVLOG(1) << "OnContinuationEnd"; - CommonHpackFragmentEnd(); -} - -void Http2DecoderAdapter::OnPadLength(size_t trailing_length) { - DVLOG(1) << "OnPadLength: " << trailing_length; - opt_pad_length_ = trailing_length; - DCHECK_LT(trailing_length, 256u); - if (frame_header_.type == Http2FrameType::DATA) { - visitor()->OnStreamPadLength(stream_id(), trailing_length); - } -} - -void Http2DecoderAdapter::OnPadding(const char* padding, - size_t skipped_length) { - DVLOG(1) << "OnPadding: " << skipped_length; - if (frame_header_.type == Http2FrameType::DATA) { - visitor()->OnStreamPadding(stream_id(), skipped_length); - } else { - MaybeAnnounceEmptyFirstHpackFragment(); - } -} - -void Http2DecoderAdapter::OnRstStream(const Http2FrameHeader& header, - Http2ErrorCode http2_error_code) { - DVLOG(1) << "OnRstStream: " << header << "; code=" << http2_error_code; - if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { - SpdyErrorCode error_code = - ParseErrorCode(static_cast<uint32_t>(http2_error_code)); - visitor()->OnRstStream(header.stream_id, error_code); - } -} - -void Http2DecoderAdapter::OnSettingsStart(const Http2FrameHeader& header) { - DVLOG(1) << "OnSettingsStart: " << header; - if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { - frame_header_ = header; - has_frame_header_ = true; - visitor()->OnSettings(); - } -} - -void Http2DecoderAdapter::OnSetting(const Http2SettingFields& setting_fields) { - DVLOG(1) << "OnSetting: " << setting_fields; - const auto parameter = static_cast<SpdySettingsId>(setting_fields.parameter); - visitor()->OnSetting(parameter, setting_fields.value); - if (extension_ != nullptr) { - extension_->OnSetting(parameter, setting_fields.value); - } -} - -void Http2DecoderAdapter::OnSettingsEnd() { - DVLOG(1) << "OnSettingsEnd"; - visitor()->OnSettingsEnd(); -} - -void Http2DecoderAdapter::OnSettingsAck(const Http2FrameHeader& header) { - DVLOG(1) << "OnSettingsAck: " << header; - if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { - visitor()->OnSettingsAck(); - } -} - -void Http2DecoderAdapter::OnPushPromiseStart( - const Http2FrameHeader& header, - const Http2PushPromiseFields& promise, - size_t total_padding_length) { - DVLOG(1) << "OnPushPromiseStart: " << header << "; promise: " << promise - << "; total_padding_length: " << total_padding_length; - if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { - if (promise.promised_stream_id == 0) { - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); - return; - } - frame_header_ = header; - has_frame_header_ = true; - ReportReceiveCompressedFrame(header); - visitor()->OnPushPromise(header.stream_id, promise.promised_stream_id, - header.IsEndHeaders()); - CommonStartHpackBlock(); - } -} - -void Http2DecoderAdapter::OnPushPromiseEnd() { - DVLOG(1) << "OnPushPromiseEnd"; - CommonHpackFragmentEnd(); - opt_pad_length_.reset(); -} - -void Http2DecoderAdapter::OnPing(const Http2FrameHeader& header, - const Http2PingFields& ping) { - DVLOG(1) << "OnPing: " << header << "; ping: " << ping; - if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { - visitor()->OnPing(ToSpdyPingId(ping), false); - } -} - -void Http2DecoderAdapter::OnPingAck(const Http2FrameHeader& header, - const Http2PingFields& ping) { - DVLOG(1) << "OnPingAck: " << header << "; ping: " << ping; - if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { - visitor()->OnPing(ToSpdyPingId(ping), true); - } -} - -void Http2DecoderAdapter::OnGoAwayStart(const Http2FrameHeader& header, - const Http2GoAwayFields& goaway) { - DVLOG(1) << "OnGoAwayStart: " << header << "; goaway: " << goaway; - if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { - frame_header_ = header; - has_frame_header_ = true; - SpdyErrorCode error_code = - ParseErrorCode(static_cast<uint32_t>(goaway.error_code)); - visitor()->OnGoAway(goaway.last_stream_id, error_code); - } -} - -void Http2DecoderAdapter::OnGoAwayOpaqueData(const char* data, size_t len) { - DVLOG(1) << "OnGoAwayOpaqueData: len=" << len; - visitor()->OnGoAwayFrameData(data, len); -} - -void Http2DecoderAdapter::OnGoAwayEnd() { - DVLOG(1) << "OnGoAwayEnd"; - visitor()->OnGoAwayFrameData(nullptr, 0); -} - -void Http2DecoderAdapter::OnWindowUpdate(const Http2FrameHeader& header, - uint32_t increment) { - DVLOG(1) << "OnWindowUpdate: " << header << "; increment=" << increment; - if (IsOkToStartFrame(header)) { - visitor()->OnWindowUpdate(header.stream_id, increment); - } -} - -// Per RFC7838, an ALTSVC frame on stream 0 with origin_length == 0, or one on -// a stream other than stream 0 with origin_length != 0 MUST be ignored. All -// frames are decoded by Http2DecoderAdapter, and it is left to the consumer -// (listener) to implement this behavior. -void Http2DecoderAdapter::OnAltSvcStart(const Http2FrameHeader& header, - size_t origin_length, - size_t value_length) { - DVLOG(1) << "OnAltSvcStart: " << header - << "; origin_length: " << origin_length - << "; value_length: " << value_length; - if (!IsOkToStartFrame(header)) { - return; - } - frame_header_ = header; - has_frame_header_ = true; - alt_svc_origin_.clear(); - alt_svc_value_.clear(); -} - -void Http2DecoderAdapter::OnAltSvcOriginData(const char* data, size_t len) { - DVLOG(1) << "OnAltSvcOriginData: len=" << len; - alt_svc_origin_.append(data, len); -} - -// Called when decoding the Alt-Svc-Field-Value of an ALTSVC; -// the field is uninterpreted. -void Http2DecoderAdapter::OnAltSvcValueData(const char* data, size_t len) { - DVLOG(1) << "OnAltSvcValueData: len=" << len; - alt_svc_value_.append(data, len); -} - -void Http2DecoderAdapter::OnAltSvcEnd() { - DVLOG(1) << "OnAltSvcEnd: origin.size(): " << alt_svc_origin_.size() - << "; value.size(): " << alt_svc_value_.size(); - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - if (!SpdyAltSvcWireFormat::ParseHeaderFieldValue(alt_svc_value_, - &altsvc_vector)) { - DLOG(ERROR) << "SpdyAltSvcWireFormat::ParseHeaderFieldValue failed."; - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); - return; - } - visitor()->OnAltSvc(frame_header_.stream_id, alt_svc_origin_, altsvc_vector); - // We assume that ALTSVC frames are rare, so get rid of the storage. - alt_svc_origin_.clear(); - alt_svc_origin_.shrink_to_fit(); - alt_svc_value_.clear(); - alt_svc_value_.shrink_to_fit(); -} - -// Except for BLOCKED frames, all other unknown frames are either dropped or -// passed to a registered extension. -void Http2DecoderAdapter::OnUnknownStart(const Http2FrameHeader& header) { - DVLOG(1) << "OnUnknownStart: " << header; - if (IsOkToStartFrame(header)) { - if (extension_ != nullptr) { - const uint8_t type = static_cast<uint8_t>(header.type); - const uint8_t flags = static_cast<uint8_t>(header.flags); - handling_extension_payload_ = extension_->OnFrameHeader( - header.stream_id, header.payload_length, type, flags); - } - } -} - -void Http2DecoderAdapter::OnUnknownPayload(const char* data, size_t len) { - if (handling_extension_payload_) { - extension_->OnFramePayload(data, len); - } else { - DVLOG(1) << "OnUnknownPayload: len=" << len; - } -} - -void Http2DecoderAdapter::OnUnknownEnd() { - DVLOG(1) << "OnUnknownEnd"; - handling_extension_payload_ = false; -} - -void Http2DecoderAdapter::OnPaddingTooLong(const Http2FrameHeader& header, - size_t missing_length) { - DVLOG(1) << "OnPaddingTooLong: " << header - << "; missing_length: " << missing_length; - if (header.type == Http2FrameType::DATA) { - if (header.payload_length == 0) { - DCHECK_EQ(1u, missing_length); - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_DATA_FRAME_FLAGS); - return; - } - visitor()->OnStreamPadding(header.stream_id, 1); - } - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_PADDING); -} - -void Http2DecoderAdapter::OnFrameSizeError(const Http2FrameHeader& header) { - DVLOG(1) << "OnFrameSizeError: " << header; - size_t recv_limit = recv_frame_size_limit_; - if (header.payload_length > recv_limit) { - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_OVERSIZED_PAYLOAD); - return; - } - if (header.type != Http2FrameType::DATA && - header.payload_length > recv_limit) { - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_CONTROL_PAYLOAD_TOO_LARGE); - return; - } - switch (header.type) { - case Http2FrameType::GOAWAY: - case Http2FrameType::ALTSVC: - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); - break; - default: - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME_SIZE); - } -} - -// Decodes the input up to the next frame boundary (i.e. at most one frame), -// stopping early if an error is detected. -size_t Http2DecoderAdapter::ProcessInputFrame(const char* data, size_t len) { - DCHECK_NE(spdy_state_, SpdyState::SPDY_ERROR); - DecodeBuffer db(data, len); - DecodeStatus status = frame_decoder_->DecodeFrame(&db); - if (spdy_state_ != SpdyState::SPDY_ERROR) { - DetermineSpdyState(status); - } else { - VLOG(1) << "ProcessInputFrame spdy_framer_error_=" - << SpdyFramerErrorToString(spdy_framer_error_); - if (spdy_framer_error_ == SpdyFramerError::SPDY_INVALID_PADDING && - has_frame_header_ && frame_type() != Http2FrameType::DATA) { - // spdy_framer_test checks that all of the available frame payload - // has been consumed, so do that. - size_t total = remaining_total_payload(); - if (total <= frame_header().payload_length) { - size_t avail = db.MinLengthRemaining(total); - VLOG(1) << "Skipping past " << avail << " bytes, of " << total - << " total remaining in the frame's payload."; - db.AdvanceCursor(avail); - } else { - SPDY_BUG << "Total remaining (" << total - << ") should not be greater than the payload length; " - << frame_header(); - } - } - } - return db.Offset(); -} - -// After decoding, determine the next SpdyState. Only called if the current -// state is NOT SpdyState::SPDY_ERROR (i.e. if none of the callback methods -// detected an error condition), because otherwise we assume that the callback -// method has set spdy_framer_error_ appropriately. -void Http2DecoderAdapter::DetermineSpdyState(DecodeStatus status) { - DCHECK_EQ(spdy_framer_error_, SPDY_NO_ERROR); - DCHECK(!HasError()) << spdy_framer_error_; - switch (status) { - case DecodeStatus::kDecodeDone: - DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeDone"; - ResetBetweenFrames(); - break; - case DecodeStatus::kDecodeInProgress: - DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeInProgress"; - if (decoded_frame_header_) { - if (IsDiscardingPayload()) { - set_spdy_state(SpdyState::SPDY_IGNORE_REMAINING_PAYLOAD); - } else if (has_frame_header_ && frame_type() == Http2FrameType::DATA) { - if (IsReadingPaddingLength()) { - set_spdy_state(SpdyState::SPDY_READ_DATA_FRAME_PADDING_LENGTH); - } else if (IsSkippingPadding()) { - set_spdy_state(SpdyState::SPDY_CONSUME_PADDING); - } else { - set_spdy_state(SpdyState::SPDY_FORWARD_STREAM_FRAME); - } - } else { - set_spdy_state(SpdyState::SPDY_CONTROL_FRAME_PAYLOAD); - } - } else { - set_spdy_state(SpdyState::SPDY_READING_COMMON_HEADER); - } - break; - case DecodeStatus::kDecodeError: - VLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeError"; - if (IsDiscardingPayload()) { - if (remaining_total_payload() == 0) { - // Push the Http2FrameDecoder out of state kDiscardPayload now - // since doing so requires no input. - DecodeBuffer tmp("", 0); - DecodeStatus status = frame_decoder_->DecodeFrame(&tmp); - if (status != DecodeStatus::kDecodeDone) { - SPDY_BUG << "Expected to be done decoding the frame, not " - << status; - SetSpdyErrorAndNotify(SPDY_INTERNAL_FRAMER_ERROR); - } else if (spdy_framer_error_ != SPDY_NO_ERROR) { - SPDY_BUG << "Expected to have no error, not " - << SpdyFramerErrorToString(spdy_framer_error_); - } else { - ResetBetweenFrames(); - } - } else { - set_spdy_state(SpdyState::SPDY_IGNORE_REMAINING_PAYLOAD); - } - } else { - SetSpdyErrorAndNotify(SPDY_INVALID_CONTROL_FRAME); - } - break; - } -} - -void Http2DecoderAdapter::ResetBetweenFrames() { - CorruptFrameHeader(&frame_header_); - decoded_frame_header_ = false; - has_frame_header_ = false; - set_spdy_state(SpdyState::SPDY_READY_FOR_FRAME); -} - -// ResetInternal is called from the constructor, and during tests, but not -// otherwise (i.e. not between every frame). -void Http2DecoderAdapter::ResetInternal() { - set_spdy_state(SpdyState::SPDY_READY_FOR_FRAME); - spdy_framer_error_ = SpdyFramerError::SPDY_NO_ERROR; - - decoded_frame_header_ = false; - has_frame_header_ = false; - on_headers_called_ = false; - on_hpack_fragment_called_ = false; - latched_probable_http_response_ = false; - has_expected_frame_type_ = false; - - CorruptFrameHeader(&frame_header_); - CorruptFrameHeader(&hpack_first_frame_header_); - - frame_decoder_ = SpdyMakeUnique<Http2FrameDecoder>(this); - hpack_decoder_ = nullptr; -} - -void Http2DecoderAdapter::set_spdy_state(SpdyState v) { - DVLOG(2) << "set_spdy_state(" << StateToString(v) << ")"; - spdy_state_ = v; -} - -void Http2DecoderAdapter::SetSpdyErrorAndNotify(SpdyFramerError error) { - if (HasError()) { - DCHECK_EQ(spdy_state_, SpdyState::SPDY_ERROR); - } else { - VLOG(2) << "SetSpdyErrorAndNotify(" << SpdyFramerErrorToString(error) - << ")"; - DCHECK_NE(error, SpdyFramerError::SPDY_NO_ERROR); - spdy_framer_error_ = error; - set_spdy_state(SpdyState::SPDY_ERROR); - frame_decoder_->set_listener(&no_op_listener_); - visitor()->OnError(error); - } -} - -bool Http2DecoderAdapter::HasError() const { - if (spdy_state_ == SpdyState::SPDY_ERROR) { - DCHECK_NE(spdy_framer_error(), SpdyFramerError::SPDY_NO_ERROR); - return true; - } else { - DCHECK_EQ(spdy_framer_error(), SpdyFramerError::SPDY_NO_ERROR); - return false; - } -} - -const Http2FrameHeader& Http2DecoderAdapter::frame_header() const { - DCHECK(has_frame_header_); - return frame_header_; -} - -uint32_t Http2DecoderAdapter::stream_id() const { - return frame_header().stream_id; -} - -Http2FrameType Http2DecoderAdapter::frame_type() const { - return frame_header().type; -} - -size_t Http2DecoderAdapter::remaining_total_payload() const { - DCHECK(has_frame_header_); - size_t remaining = frame_decoder_->remaining_payload(); - if (IsPaddable(frame_type()) && frame_header_.IsPadded()) { - remaining += frame_decoder_->remaining_padding(); - } - return remaining; -} - -bool Http2DecoderAdapter::IsReadingPaddingLength() { - bool result = frame_header_.IsPadded() && !opt_pad_length_; - DVLOG(2) << "Http2DecoderAdapter::IsReadingPaddingLength: " << result; - return result; -} -bool Http2DecoderAdapter::IsSkippingPadding() { - bool result = frame_header_.IsPadded() && opt_pad_length_ && - frame_decoder_->remaining_payload() == 0 && - frame_decoder_->remaining_padding() > 0; - DVLOG(2) << "Http2DecoderAdapter::IsSkippingPadding: " << result; - return result; -} -bool Http2DecoderAdapter::IsDiscardingPayload() { - bool result = decoded_frame_header_ && frame_decoder_->IsDiscardingPayload(); - DVLOG(2) << "Http2DecoderAdapter::IsDiscardingPayload: " << result; - return result; -} -// Called from OnXyz or OnXyzStart methods to decide whether it is OK to -// handle the callback. -bool Http2DecoderAdapter::IsOkToStartFrame(const Http2FrameHeader& header) { - DVLOG(3) << "IsOkToStartFrame"; - if (HasError()) { - VLOG(2) << "HasError()"; - return false; - } - DCHECK(!has_frame_header_); - if (has_expected_frame_type_ && header.type != expected_frame_type_) { - VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not " - << header.type; - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); - return false; - } - - return true; -} - -bool Http2DecoderAdapter::HasRequiredStreamId(uint32_t stream_id) { - DVLOG(3) << "HasRequiredStreamId: " << stream_id; - if (HasError()) { - VLOG(2) << "HasError()"; - return false; - } - if (stream_id != 0) { - return true; - } - VLOG(1) << "Stream Id is required, but zero provided"; - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID); - return false; -} - -bool Http2DecoderAdapter::HasRequiredStreamId(const Http2FrameHeader& header) { - return HasRequiredStreamId(header.stream_id); -} - -bool Http2DecoderAdapter::HasRequiredStreamIdZero(uint32_t stream_id) { - DVLOG(3) << "HasRequiredStreamIdZero: " << stream_id; - if (HasError()) { - VLOG(2) << "HasError()"; - return false; - } - if (stream_id == 0) { - return true; - } - VLOG(1) << "Stream Id was not zero, as required: " << stream_id; - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID); - return false; -} - -bool Http2DecoderAdapter::HasRequiredStreamIdZero( - const Http2FrameHeader& header) { - return HasRequiredStreamIdZero(header.stream_id); -} - -void Http2DecoderAdapter::ReportReceiveCompressedFrame( - const Http2FrameHeader& header) { - if (debug_visitor() != nullptr) { - size_t total = header.payload_length + Http2FrameHeader::EncodedSize(); - debug_visitor()->OnReceiveCompressedFrame( - header.stream_id, ToSpdyFrameType(header.type), total); - } -} - -HpackDecoderAdapter* Http2DecoderAdapter::GetHpackDecoder() { - if (hpack_decoder_ == nullptr) { - hpack_decoder_ = SpdyMakeUnique<HpackDecoderAdapter>(); - } - return hpack_decoder_.get(); -} - -void Http2DecoderAdapter::CommonStartHpackBlock() { - DVLOG(1) << "CommonStartHpackBlock"; - DCHECK(!has_hpack_first_frame_header_); - if (!frame_header_.IsEndHeaders()) { - hpack_first_frame_header_ = frame_header_; - has_hpack_first_frame_header_ = true; - } else { - CorruptFrameHeader(&hpack_first_frame_header_); - } - on_hpack_fragment_called_ = false; - SpdyHeadersHandlerInterface* handler = - visitor()->OnHeaderFrameStart(stream_id()); - if (handler == nullptr) { - SPDY_BUG << "visitor_->OnHeaderFrameStart returned nullptr"; - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INTERNAL_FRAMER_ERROR); - return; - } - GetHpackDecoder()->HandleControlFrameHeadersStart(handler); -} - -// SpdyFramer calls HandleControlFrameHeadersData even if there are zero -// fragment bytes in the first frame, so do the same. -void Http2DecoderAdapter::MaybeAnnounceEmptyFirstHpackFragment() { - if (!on_hpack_fragment_called_) { - OnHpackFragment(nullptr, 0); - DCHECK(on_hpack_fragment_called_); - } -} - -void Http2DecoderAdapter::CommonHpackFragmentEnd() { - DVLOG(1) << "CommonHpackFragmentEnd: stream_id=" << stream_id(); - if (HasError()) { - VLOG(1) << "HasError(), returning"; - return; - } - DCHECK(has_frame_header_); - MaybeAnnounceEmptyFirstHpackFragment(); - if (frame_header_.IsEndHeaders()) { - DCHECK_EQ(has_hpack_first_frame_header_, - frame_type() == Http2FrameType::CONTINUATION) - << frame_header(); - has_expected_frame_type_ = false; - if (GetHpackDecoder()->HandleControlFrameHeadersComplete(nullptr)) { - visitor()->OnHeaderFrameEnd(stream_id()); - } else { - SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE); - return; - } - const Http2FrameHeader& first = frame_type() == Http2FrameType::CONTINUATION - ? hpack_first_frame_header_ - : frame_header_; - if (first.type == Http2FrameType::HEADERS && first.IsEndStream()) { - visitor()->OnStreamEnd(first.stream_id); - } - has_hpack_first_frame_header_ = false; - CorruptFrameHeader(&hpack_first_frame_header_); - } else { - DCHECK(has_hpack_first_frame_header_); - has_expected_frame_type_ = true; - expected_frame_type_ = Http2FrameType::CONTINUATION; - } -} - -} // namespace http2 - -namespace spdy { - -bool SpdyFramerVisitorInterface::OnGoAwayFrameData(const char* goaway_data, - size_t len) { - return true; -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/http2_frame_decoder_adapter.h b/net/third_party/spdy/core/http2_frame_decoder_adapter.h deleted file mode 100644 index 47db5d39..0000000 --- a/net/third_party/spdy/core/http2_frame_decoder_adapter.h +++ /dev/null
@@ -1,514 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_HTTP2_FRAME_DECODER_ADAPTER_H_ -#define NET_THIRD_PARTY_SPDY_CORE_HTTP2_FRAME_DECODER_ADAPTER_H_ - -#include <stddef.h> - -#include <cstdint> -#include <memory> - -#include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder.h" -#include "net/third_party/quiche/src/http2/platform/api/http2_optional.h" -#include "net/third_party/spdy/core/hpack/hpack_decoder_adapter.h" -#include "net/third_party/spdy/core/hpack/hpack_header_table.h" -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" -#include "net/third_party/spdy/core/spdy_headers_handler_interface.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { - -class SpdyFramerVisitorInterface; -class ExtensionVisitorInterface; - -} // namespace spdy - -// TODO(dahollings): Perform various renames/moves suggested in cl/164660364. - -namespace http2 { - -// Adapts SpdyFramer interface to use Http2FrameDecoder. -class SPDY_EXPORT_PRIVATE Http2DecoderAdapter - : public http2::Http2FrameDecoderListener { - public: - // HTTP2 states. - enum SpdyState { - SPDY_ERROR, - SPDY_READY_FOR_FRAME, // Framer is ready for reading the next frame. - SPDY_FRAME_COMPLETE, // Framer has finished reading a frame, need to reset. - SPDY_READING_COMMON_HEADER, - SPDY_CONTROL_FRAME_PAYLOAD, - SPDY_READ_DATA_FRAME_PADDING_LENGTH, - SPDY_CONSUME_PADDING, - SPDY_IGNORE_REMAINING_PAYLOAD, - SPDY_FORWARD_STREAM_FRAME, - SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK, - SPDY_CONTROL_FRAME_HEADER_BLOCK, - SPDY_GOAWAY_FRAME_PAYLOAD, - SPDY_SETTINGS_FRAME_HEADER, - SPDY_SETTINGS_FRAME_PAYLOAD, - SPDY_ALTSVC_FRAME_PAYLOAD, - SPDY_EXTENSION_FRAME_PAYLOAD, - }; - - // Framer error codes. - enum SpdyFramerError { - SPDY_NO_ERROR, - SPDY_INVALID_STREAM_ID, // Stream ID is invalid - SPDY_INVALID_CONTROL_FRAME, // Control frame is mal-formatted. - SPDY_CONTROL_PAYLOAD_TOO_LARGE, // Control frame payload was too large. - SPDY_ZLIB_INIT_FAILURE, // The Zlib library could not initialize. - SPDY_UNSUPPORTED_VERSION, // Control frame has unsupported version. - SPDY_DECOMPRESS_FAILURE, // There was an error decompressing. - SPDY_COMPRESS_FAILURE, // There was an error compressing. - SPDY_GOAWAY_FRAME_CORRUPT, // GOAWAY frame could not be parsed. - SPDY_RST_STREAM_FRAME_CORRUPT, // RST_STREAM frame could not be parsed. - SPDY_INVALID_PADDING, // HEADERS or DATA frame padding invalid - SPDY_INVALID_DATA_FRAME_FLAGS, // Data frame has invalid flags. - SPDY_INVALID_CONTROL_FRAME_FLAGS, // Control frame has invalid flags. - SPDY_UNEXPECTED_FRAME, // Frame received out of order. - SPDY_INTERNAL_FRAMER_ERROR, // SpdyFramer was used incorrectly. - SPDY_INVALID_CONTROL_FRAME_SIZE, // Control frame not sized to spec - SPDY_OVERSIZED_PAYLOAD, // Payload size was too large - - LAST_ERROR, // Must be the last entry in the enum. - }; - - // For debugging. - static const char* StateToString(int state); - static const char* SpdyFramerErrorToString(SpdyFramerError spdy_framer_error); - - Http2DecoderAdapter(); - ~Http2DecoderAdapter() override; - - // Set callbacks to be called from the framer. A visitor must be set, or - // else the framer will likely crash. It is acceptable for the visitor - // to do nothing. If this is called multiple times, only the last visitor - // will be used. - void set_visitor(spdy::SpdyFramerVisitorInterface* visitor); - spdy::SpdyFramerVisitorInterface* visitor() const { return visitor_; } - - // Set extension callbacks to be called from the framer or decoder. Optional. - // If called multiple times, only the last visitor will be used. - void set_extension_visitor(spdy::ExtensionVisitorInterface* visitor); - - // Set debug callbacks to be called from the framer. The debug visitor is - // completely optional and need not be set in order for normal operation. - // If this is called multiple times, only the last visitor will be used. - void set_debug_visitor(spdy::SpdyFramerDebugVisitorInterface* debug_visitor); - spdy::SpdyFramerDebugVisitorInterface* debug_visitor() const { - return debug_visitor_; - } - - // Set debug callbacks to be called from the HPACK decoder. - void SetDecoderHeaderTableDebugVisitor( - std::unique_ptr<spdy::HpackHeaderTable::DebugVisitorInterface> visitor); - - // Sets whether or not ProcessInput returns after finishing a frame, or - // continues processing additional frames. Normally ProcessInput processes - // all input, but this method enables the caller (and visitor) to work with - // a single frame at a time (or that portion of the frame which is provided - // as input). Reset() does not change the value of this flag. - void set_process_single_input_frame(bool v); - bool process_single_input_frame() const { - return process_single_input_frame_; - } - - // Decode the |len| bytes of encoded HTTP/2 starting at |*data|. Returns - // the number of bytes consumed. It is safe to pass more bytes in than - // may be consumed. Should process (or otherwise buffer) as much as - // available, unless process_single_input_frame is true. - size_t ProcessInput(const char* data, size_t len); - - // Reset the decoder (used just for tests at this time). - void Reset(); - - // Current state of the decoder. - SpdyState state() const; - - // Current error code (NO_ERROR if state != ERROR). - SpdyFramerError spdy_framer_error() const; - - // Has any frame header looked like the start of an HTTP/1.1 (or earlier) - // response? Used to detect if a backend/server that we sent a request to - // has responded with an HTTP/1.1 (or earlier) response. - bool probable_http_response() const; - - // Returns the estimate of dynamically allocated memory in bytes. - size_t EstimateMemoryUsage() const; - - spdy::HpackDecoderAdapter* GetHpackDecoder(); - - bool HasError() const; - - private: - bool OnFrameHeader(const Http2FrameHeader& header) override; - void OnDataStart(const Http2FrameHeader& header) override; - void OnDataPayload(const char* data, size_t len) override; - void OnDataEnd() override; - void OnHeadersStart(const Http2FrameHeader& header) override; - void OnHeadersPriority(const Http2PriorityFields& priority) override; - void OnHpackFragment(const char* data, size_t len) override; - void OnHeadersEnd() override; - void OnPriorityFrame(const Http2FrameHeader& header, - const Http2PriorityFields& priority) override; - void OnContinuationStart(const Http2FrameHeader& header) override; - void OnContinuationEnd() override; - void OnPadLength(size_t trailing_length) override; - void OnPadding(const char* padding, size_t skipped_length) override; - void OnRstStream(const Http2FrameHeader& header, - Http2ErrorCode http2_error_code) override; - void OnSettingsStart(const Http2FrameHeader& header) override; - void OnSetting(const Http2SettingFields& setting_fields) override; - void OnSettingsEnd() override; - void OnSettingsAck(const Http2FrameHeader& header) override; - void OnPushPromiseStart(const Http2FrameHeader& header, - const Http2PushPromiseFields& promise, - size_t total_padding_length) override; - void OnPushPromiseEnd() override; - void OnPing(const Http2FrameHeader& header, - const Http2PingFields& ping) override; - void OnPingAck(const Http2FrameHeader& header, - const Http2PingFields& ping) override; - void OnGoAwayStart(const Http2FrameHeader& header, - const Http2GoAwayFields& goaway) override; - void OnGoAwayOpaqueData(const char* data, size_t len) override; - void OnGoAwayEnd() override; - void OnWindowUpdate(const Http2FrameHeader& header, - uint32_t increment) override; - void OnAltSvcStart(const Http2FrameHeader& header, - size_t origin_length, - size_t value_length) override; - void OnAltSvcOriginData(const char* data, size_t len) override; - void OnAltSvcValueData(const char* data, size_t len) override; - void OnAltSvcEnd() override; - void OnUnknownStart(const Http2FrameHeader& header) override; - void OnUnknownPayload(const char* data, size_t len) override; - void OnUnknownEnd() override; - void OnPaddingTooLong(const Http2FrameHeader& header, - size_t missing_length) override; - void OnFrameSizeError(const Http2FrameHeader& header) override; - - size_t ProcessInputFrame(const char* data, size_t len); - - void DetermineSpdyState(DecodeStatus status); - void ResetBetweenFrames(); - - // ResetInternal is called from the constructor, and during tests, but not - // otherwise (i.e. not between every frame). - void ResetInternal(); - - void set_spdy_state(SpdyState v); - - void SetSpdyErrorAndNotify(SpdyFramerError error); - - const Http2FrameHeader& frame_header() const; - - uint32_t stream_id() const; - Http2FrameType frame_type() const; - - size_t remaining_total_payload() const; - - bool IsReadingPaddingLength(); - bool IsSkippingPadding(); - bool IsDiscardingPayload(); - // Called from OnXyz or OnXyzStart methods to decide whether it is OK to - // handle the callback. - bool IsOkToStartFrame(const Http2FrameHeader& header); - bool HasRequiredStreamId(uint32_t stream_id); - - bool HasRequiredStreamId(const Http2FrameHeader& header); - - bool HasRequiredStreamIdZero(uint32_t stream_id); - - bool HasRequiredStreamIdZero(const Http2FrameHeader& header); - - void ReportReceiveCompressedFrame(const Http2FrameHeader& header); - - void CommonStartHpackBlock(); - - // SpdyFramer calls HandleControlFrameHeadersData even if there are zero - // fragment bytes in the first frame, so do the same. - void MaybeAnnounceEmptyFirstHpackFragment(); - void CommonHpackFragmentEnd(); - - // The most recently decoded frame header; invalid after we reached the end - // of that frame. - Http2FrameHeader frame_header_; - - // If decoding an HPACK block that is split across multiple frames, this holds - // the frame header of the HEADERS or PUSH_PROMISE that started the block. - Http2FrameHeader hpack_first_frame_header_; - - // Amount of trailing padding. Currently used just as an indicator of whether - // OnPadLength has been called. - Http2Optional<size_t> opt_pad_length_; - - // Temporary buffers for the AltSvc fields. - Http2String alt_svc_origin_; - Http2String alt_svc_value_; - - // Listener used if we transition to an error state; the listener ignores all - // the callbacks. - Http2FrameDecoderNoOpListener no_op_listener_; - - spdy::SpdyFramerVisitorInterface* visitor_ = nullptr; - spdy::SpdyFramerDebugVisitorInterface* debug_visitor_ = nullptr; - - // If non-null, unknown frames and settings are passed to the extension. - spdy::ExtensionVisitorInterface* extension_ = nullptr; - - // The HPACK decoder to be used for this adapter. User is responsible for - // clearing if the adapter is to be used for another connection. - std::unique_ptr<spdy::HpackDecoderAdapter> hpack_decoder_ = nullptr; - - // The HTTP/2 frame decoder. Accessed via a unique_ptr to allow replacement - // (e.g. in tests) when Reset() is called. - std::unique_ptr<Http2FrameDecoder> frame_decoder_; - - // Next frame type expected. Currently only used for CONTINUATION frames, - // but could be used for detecting whether the first frame is a SETTINGS - // frame. - // TODO(jamessyng): Provide means to indicate that decoder should require - // SETTINGS frame as the first frame. - Http2FrameType expected_frame_type_; - - // Attempt to duplicate the SpdyState and SpdyFramerError values that - // SpdyFramer sets. Values determined by getting tests to pass. - SpdyState spdy_state_; - SpdyFramerError spdy_framer_error_; - - // The limit on the size of received HTTP/2 payloads as specified in the - // SETTINGS_MAX_FRAME_SIZE advertised to peer. - size_t recv_frame_size_limit_ = spdy::kHttp2DefaultFramePayloadLimit; - - // Has OnFrameHeader been called? - bool decoded_frame_header_ = false; - - // Have we recorded an Http2FrameHeader for the current frame? - // We only do so if the decoder will make multiple callbacks for - // the frame; for example, for PING frames we don't make record - // the frame header, but for ALTSVC we do. - bool has_frame_header_ = false; - - // Have we recorded an Http2FrameHeader for the current HPACK block? - // True only for multi-frame HPACK blocks. - bool has_hpack_first_frame_header_ = false; - - // Has OnHeaders() already been called for current HEADERS block? Only - // meaningful between OnHeadersStart and OnHeadersPriority. - bool on_headers_called_; - - // Has OnHpackFragment() already been called for current HPACK block? - // SpdyFramer will pass an empty buffer to the HPACK decoder if a HEADERS - // or PUSH_PROMISE has no HPACK data in it (e.g. a HEADERS frame with only - // padding). Detect that condition and replicate the behavior using this - // field. - bool on_hpack_fragment_called_; - - // Have we seen a frame header that appears to be an HTTP/1 response? - bool latched_probable_http_response_ = false; - - // Is expected_frame_type_ set? - bool has_expected_frame_type_ = false; - - // Is the current frame payload destined for |extension_|? - bool handling_extension_payload_ = false; - - bool process_single_input_frame_ = false; -}; - -} // namespace http2 - -namespace spdy { - -// Http2DecoderAdapter will use the given visitor implementing this -// interface to deliver event callbacks as frames are decoded. -// -// Control frames that contain HTTP2 header blocks (HEADER, and PUSH_PROMISE) -// are processed in fashion that allows the decompressed header block to be -// delivered in chunks to the visitor. -// The following steps are followed: -// 1. OnHeaders, or OnPushPromise is called. -// 2. OnHeaderFrameStart is called; visitor is expected to return an instance -// of SpdyHeadersHandlerInterface that will receive the header key-value -// pairs. -// 3. OnHeaderFrameEnd is called, indicating that the full header block has -// been delivered for the control frame. -// During step 2, if the visitor is not interested in accepting the header data, -// it should return a no-op implementation of SpdyHeadersHandlerInterface. -class SPDY_EXPORT_PRIVATE SpdyFramerVisitorInterface { - public: - virtual ~SpdyFramerVisitorInterface() {} - - // Called if an error is detected in the SpdyFrame protocol. - virtual void OnError(http2::Http2DecoderAdapter::SpdyFramerError error) = 0; - - // Called when the common header for a frame is received. Validating the - // common header occurs in later processing. - virtual void OnCommonHeader(SpdyStreamId /*stream_id*/, - size_t /*length*/, - uint8_t /*type*/, - uint8_t /*flags*/) {} - - // Called when a data frame header is received. The frame's data - // payload will be provided via subsequent calls to - // OnStreamFrameData(). - virtual void OnDataFrameHeader(SpdyStreamId stream_id, - size_t length, - bool fin) = 0; - - // Called when data is received. - // |stream_id| The stream receiving data. - // |data| A buffer containing the data received. - // |len| The length of the data buffer. - virtual void OnStreamFrameData(SpdyStreamId stream_id, - const char* data, - size_t len) = 0; - - // Called when the other side has finished sending data on this stream. - // |stream_id| The stream that was receiving data. - virtual void OnStreamEnd(SpdyStreamId stream_id) = 0; - - // Called when padding length field is received on a DATA frame. - // |stream_id| The stream receiving data. - // |value| The value of the padding length field. - virtual void OnStreamPadLength(SpdyStreamId stream_id, size_t value) {} - - // Called when padding is received (the trailing octets, not pad_len field) on - // a DATA frame. - // |stream_id| The stream receiving data. - // |len| The number of padding octets. - virtual void OnStreamPadding(SpdyStreamId stream_id, size_t len) = 0; - - // Called just before processing the payload of a frame containing header - // data. Should return an implementation of SpdyHeadersHandlerInterface that - // will receive headers for stream |stream_id|. The caller will not take - // ownership of the headers handler. The same instance should remain live - // and be returned for all header frames comprising a logical header block - // (i.e. until OnHeaderFrameEnd() is called). - virtual SpdyHeadersHandlerInterface* OnHeaderFrameStart( - SpdyStreamId stream_id) = 0; - - // Called after processing the payload of a frame containing header data. - virtual void OnHeaderFrameEnd(SpdyStreamId stream_id) = 0; - - // Called when a RST_STREAM frame has been parsed. - virtual void OnRstStream(SpdyStreamId stream_id, - SpdyErrorCode error_code) = 0; - - // Called when a SETTINGS frame is received. - virtual void OnSettings() {} - - // Called when a complete setting within a SETTINGS frame has been parsed. - // Note that |id| may or may not be a SETTINGS ID defined in the HTTP/2 spec. - virtual void OnSetting(SpdySettingsId id, uint32_t value) = 0; - - // Called when a SETTINGS frame is received with the ACK flag set. - virtual void OnSettingsAck() {} - - // Called before and after parsing SETTINGS id and value tuples. - virtual void OnSettingsEnd() = 0; - - // Called when a PING frame has been parsed. - virtual void OnPing(SpdyPingId unique_id, bool is_ack) = 0; - - // Called when a GOAWAY frame has been parsed. - virtual void OnGoAway(SpdyStreamId last_accepted_stream_id, - SpdyErrorCode error_code) = 0; - - // Called when a HEADERS frame is received. - // Note that header block data is not included. See OnHeaderFrameStart(). - // |stream_id| The stream receiving the header. - // |has_priority| Whether or not the headers frame included a priority value, - // and stream dependency info. - // |weight| If |has_priority| is true, then weight (in the range [1, 256]) - // for the receiving stream, otherwise 0. - // |parent_stream_id| If |has_priority| is true the parent stream of the - // receiving stream, else 0. - // |exclusive| If |has_priority| is true the exclusivity of dependence on the - // parent stream, else false. - // |fin| Whether FIN flag is set in frame headers. - // |end| False if HEADERs frame is to be followed by a CONTINUATION frame, - // or true if not. - virtual void OnHeaders(SpdyStreamId stream_id, - bool has_priority, - int weight, - SpdyStreamId parent_stream_id, - bool exclusive, - bool fin, - bool end) = 0; - - // Called when a WINDOW_UPDATE frame has been parsed. - virtual void OnWindowUpdate(SpdyStreamId stream_id, - int delta_window_size) = 0; - - // Called when a goaway frame opaque data is available. - // |goaway_data| A buffer containing the opaque GOAWAY data chunk received. - // |len| The length of the header data buffer. A length of zero indicates - // that the header data block has been completely sent. - // When this function returns true the visitor indicates that it accepted - // all of the data. Returning false indicates that that an error has - // occurred while processing the data. Default implementation returns true. - virtual bool OnGoAwayFrameData(const char* goaway_data, size_t len); - - // Called when a PUSH_PROMISE frame is received. - // Note that header block data is not included. See OnHeaderFrameStart(). - virtual void OnPushPromise(SpdyStreamId stream_id, - SpdyStreamId promised_stream_id, - bool end) = 0; - - // Called when a CONTINUATION frame is received. - // Note that header block data is not included. See OnHeaderFrameStart(). - virtual void OnContinuation(SpdyStreamId stream_id, bool end) = 0; - - // Called when an ALTSVC frame has been parsed. - virtual void OnAltSvc( - SpdyStreamId /*stream_id*/, - SpdyStringPiece /*origin*/, - const SpdyAltSvcWireFormat::AlternativeServiceVector& /*altsvc_vector*/) { - } - - // Called when a PRIORITY frame is received. - // |stream_id| The stream to update the priority of. - // |parent_stream_id| The parent stream of |stream_id|. - // |weight| Stream weight, in the range [1, 256]. - // |exclusive| Whether |stream_id| should be an only child of - // |parent_stream_id|. - virtual void OnPriority(SpdyStreamId stream_id, - SpdyStreamId parent_stream_id, - int weight, - bool exclusive) = 0; - - // Called when a frame type we don't recognize is received. - // Return true if this appears to be a valid extension frame, false otherwise. - // We distinguish between extension frames and nonsense by checking - // whether the stream id is valid. - virtual bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) = 0; -}; - -class SPDY_EXPORT_PRIVATE ExtensionVisitorInterface { - public: - virtual ~ExtensionVisitorInterface() {} - - // Called when SETTINGS are received, including non-standard SETTINGS. - virtual void OnSetting(SpdySettingsId id, uint32_t value) = 0; - - // Called when non-standard frames are received. - virtual bool OnFrameHeader(SpdyStreamId stream_id, - size_t length, - uint8_t type, - uint8_t flags) = 0; - - // The payload for a single frame may be delivered as multiple calls to - // OnFramePayload. Since the length field is passed in OnFrameHeader, there is - // no explicit indication of the end of the frame payload. - virtual void OnFramePayload(const char* data, size_t len) = 0; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_HTTP2_FRAME_DECODER_ADAPTER_H_
diff --git a/net/third_party/spdy/core/mock_spdy_framer_visitor.cc b/net/third_party/spdy/core/mock_spdy_framer_visitor.cc deleted file mode 100644 index c93b825..0000000 --- a/net/third_party/spdy/core/mock_spdy_framer_visitor.cc +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/mock_spdy_framer_visitor.h" - -namespace spdy { - -namespace test { - -MockSpdyFramerVisitor::MockSpdyFramerVisitor() { - DelegateHeaderHandling(); -} - -MockSpdyFramerVisitor::~MockSpdyFramerVisitor() = default; - -} // namespace test - -} // namespace spdy
diff --git a/net/third_party/spdy/core/mock_spdy_framer_visitor.h b/net/third_party/spdy/core/mock_spdy_framer_visitor.h deleted file mode 100644 index 2a531f7..0000000 --- a/net/third_party/spdy/core/mock_spdy_framer_visitor.h +++ /dev/null
@@ -1,103 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_MOCK_SPDY_FRAMER_VISITOR_H_ -#define NET_THIRD_PARTY_SPDY_CORE_MOCK_SPDY_FRAMER_VISITOR_H_ - -#include <cstdint> -#include <memory> - -#include "net/third_party/spdy/core/http2_frame_decoder_adapter.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" -#include "net/third_party/spdy/platform/api/spdy_ptr_util.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace spdy { - -namespace test { - -class MockSpdyFramerVisitor : public SpdyFramerVisitorInterface { - public: - MockSpdyFramerVisitor(); - ~MockSpdyFramerVisitor() override; - - MOCK_METHOD1(OnError, - void(http2::Http2DecoderAdapter::SpdyFramerError error)); - MOCK_METHOD3(OnDataFrameHeader, - void(SpdyStreamId stream_id, size_t length, bool fin)); - MOCK_METHOD3(OnStreamFrameData, - void(SpdyStreamId stream_id, const char* data, size_t len)); - MOCK_METHOD1(OnStreamEnd, void(SpdyStreamId stream_id)); - MOCK_METHOD2(OnStreamPadLength, void(SpdyStreamId stream_id, size_t value)); - MOCK_METHOD2(OnStreamPadding, void(SpdyStreamId stream_id, size_t len)); - MOCK_METHOD1(OnHeaderFrameStart, - SpdyHeadersHandlerInterface*(SpdyStreamId stream_id)); - MOCK_METHOD1(OnHeaderFrameEnd, void(SpdyStreamId stream_id)); - MOCK_METHOD2(OnRstStream, - void(SpdyStreamId stream_id, SpdyErrorCode error_code)); - MOCK_METHOD0(OnSettings, void()); - MOCK_METHOD2(OnSetting, void(SpdySettingsId id, uint32_t value)); - MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack)); - MOCK_METHOD0(OnSettingsEnd, void()); - MOCK_METHOD2(OnGoAway, - void(SpdyStreamId last_accepted_stream_id, - SpdyErrorCode error_code)); - MOCK_METHOD7(OnHeaders, - void(SpdyStreamId stream_id, - bool has_priority, - int weight, - SpdyStreamId parent_stream_id, - bool exclusive, - bool fin, - bool end)); - MOCK_METHOD2(OnWindowUpdate, - void(SpdyStreamId stream_id, int delta_window_size)); - MOCK_METHOD3(OnPushPromise, - void(SpdyStreamId stream_id, - SpdyStreamId promised_stream_id, - bool end)); - MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end)); - MOCK_METHOD3(OnAltSvc, - void(SpdyStreamId stream_id, - SpdyStringPiece origin, - const SpdyAltSvcWireFormat::AlternativeServiceVector& - altsvc_vector)); - MOCK_METHOD4(OnPriority, - void(SpdyStreamId stream_id, - SpdyStreamId parent_stream_id, - int weight, - bool exclusive)); - MOCK_METHOD2(OnUnknownFrame, - bool(SpdyStreamId stream_id, uint8_t frame_type)); - - void DelegateHeaderHandling() { - ON_CALL(*this, OnHeaderFrameStart(testing::_)) - .WillByDefault(testing::Invoke( - this, &MockSpdyFramerVisitor::ReturnTestHeadersHandler)); - ON_CALL(*this, OnHeaderFrameEnd(testing::_)) - .WillByDefault(testing::Invoke( - this, &MockSpdyFramerVisitor::ResetTestHeadersHandler)); - } - - SpdyHeadersHandlerInterface* ReturnTestHeadersHandler( - SpdyStreamId /* stream_id */) { - if (headers_handler_ == nullptr) { - headers_handler_ = SpdyMakeUnique<TestHeadersHandler>(); - } - return headers_handler_.get(); - } - - void ResetTestHeadersHandler(SpdyStreamId /* stream_id */) { - headers_handler_.reset(); - } - - std::unique_ptr<SpdyHeadersHandlerInterface> headers_handler_; -}; - -} // namespace test - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_MOCK_SPDY_FRAMER_VISITOR_H_
diff --git a/net/third_party/spdy/core/priority_write_scheduler.h b/net/third_party/spdy/core/priority_write_scheduler.h deleted file mode 100644 index 8e6b826..0000000 --- a/net/third_party/spdy/core/priority_write_scheduler.h +++ /dev/null
@@ -1,322 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_PRIORITY_WRITE_SCHEDULER_H_ -#define NET_THIRD_PARTY_SPDY_CORE_PRIORITY_WRITE_SCHEDULER_H_ - -#include <algorithm> -#include <cstddef> -#include <cstdint> -#include <tuple> -#include <unordered_map> -#include <utility> -#include <vector> - -#include "base/logging.h" -#include "net/third_party/quiche/src/http2/platform/api/http2_containers.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/write_scheduler.h" -#include "net/third_party/spdy/platform/api/spdy_bug_tracker.h" -#include "net/third_party/spdy/platform/api/spdy_macros.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" - -namespace spdy { - -namespace test { -template <typename StreamIdType> -class PriorityWriteSchedulerPeer; -} - -// WriteScheduler implementation that manages the order in which streams are -// written using the SPDY priority scheme described at: -// https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1#TOC-2.3.3-Stream-priority -// -// Internally, PriorityWriteScheduler consists of 8 PriorityInfo objects, one -// for each priority value. Each PriorityInfo contains a list of streams of -// that priority that are ready to write, as well as a timestamp of the last -// I/O event that occurred for a stream of that priority. -// -// DO NOT USE. Deprecated. -template <typename StreamIdType> -class PriorityWriteScheduler : public WriteScheduler<StreamIdType> { - public: - using typename WriteScheduler<StreamIdType>::StreamPrecedenceType; - - // Creates scheduler with no streams. - PriorityWriteScheduler() = default; - - void RegisterStream(StreamIdType stream_id, - const StreamPrecedenceType& precedence) override { - // TODO(mpw): verify |precedence.is_spdy3_priority() == true| once - // Http2PriorityWriteScheduler enabled for HTTP/2. - - // parent_id not used here, but may as well validate it. However, - // parent_id may legitimately not be registered yet--see b/15676312. - StreamIdType parent_id = precedence.parent_id(); - SPDY_DVLOG_IF( - 1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id)) - << "Parent stream " << parent_id << " not registered"; - - if (stream_id == kHttp2RootStreamId) { - SPDY_BUG << "Stream " << kHttp2RootStreamId << " already registered"; - return; - } - StreamInfo stream_info = {precedence.spdy3_priority(), stream_id, false}; - bool inserted = - stream_infos_.insert(std::make_pair(stream_id, stream_info)).second; - SPDY_BUG_IF(!inserted) << "Stream " << stream_id << " already registered"; - } - - void UnregisterStream(StreamIdType stream_id) override { - auto it = stream_infos_.find(stream_id); - if (it == stream_infos_.end()) { - SPDY_BUG << "Stream " << stream_id << " not registered"; - return; - } - StreamInfo& stream_info = it->second; - if (stream_info.ready) { - bool erased = - Erase(&priority_infos_[stream_info.priority].ready_list, stream_info); - DCHECK(erased); - } - stream_infos_.erase(it); - } - - bool StreamRegistered(StreamIdType stream_id) const override { - return stream_infos_.find(stream_id) != stream_infos_.end(); - } - - StreamPrecedenceType GetStreamPrecedence( - StreamIdType stream_id) const override { - auto it = stream_infos_.find(stream_id); - if (it == stream_infos_.end()) { - DVLOG(1) << "Stream " << stream_id << " not registered"; - return StreamPrecedenceType(kV3LowestPriority); - } - return StreamPrecedenceType(it->second.priority); - } - - void UpdateStreamPrecedence(StreamIdType stream_id, - const StreamPrecedenceType& precedence) override { - // TODO(mpw): verify |precedence.is_spdy3_priority() == true| once - // Http2PriorityWriteScheduler enabled for HTTP/2. - - // parent_id not used here, but may as well validate it. However, - // parent_id may legitimately not be registered yet--see b/15676312. - StreamIdType parent_id = precedence.parent_id(); - SPDY_DVLOG_IF( - 1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id)) - << "Parent stream " << parent_id << " not registered"; - - auto it = stream_infos_.find(stream_id); - if (it == stream_infos_.end()) { - // TODO(mpw): add to stream_infos_ on demand--see b/15676312. - DVLOG(1) << "Stream " << stream_id << " not registered"; - return; - } - StreamInfo& stream_info = it->second; - SpdyPriority new_priority = precedence.spdy3_priority(); - if (stream_info.priority == new_priority) { - return; - } - if (stream_info.ready) { - bool erased = - Erase(&priority_infos_[stream_info.priority].ready_list, stream_info); - DCHECK(erased); - priority_infos_[new_priority].ready_list.push_back(&stream_info); - ++num_ready_streams_; - } - stream_info.priority = new_priority; - } - - std::vector<StreamIdType> GetStreamChildren( - StreamIdType stream_id) const override { - return std::vector<StreamIdType>(); - } - - void RecordStreamEventTime(StreamIdType stream_id, - int64_t now_in_usec) override { - auto it = stream_infos_.find(stream_id); - if (it == stream_infos_.end()) { - SPDY_BUG << "Stream " << stream_id << " not registered"; - return; - } - PriorityInfo& priority_info = priority_infos_[it->second.priority]; - priority_info.last_event_time_usec = - std::max(priority_info.last_event_time_usec, now_in_usec); - } - - int64_t GetLatestEventWithPrecedence(StreamIdType stream_id) const override { - auto it = stream_infos_.find(stream_id); - if (it == stream_infos_.end()) { - SPDY_BUG << "Stream " << stream_id << " not registered"; - return 0; - } - int64_t last_event_time_usec = 0; - const StreamInfo& stream_info = it->second; - for (SpdyPriority p = kV3HighestPriority; p < stream_info.priority; ++p) { - last_event_time_usec = std::max(last_event_time_usec, - priority_infos_[p].last_event_time_usec); - } - return last_event_time_usec; - } - - StreamIdType PopNextReadyStream() override { - return std::get<0>(PopNextReadyStreamAndPrecedence()); - } - - // Returns the next ready stream and its precedence. - std::tuple<StreamIdType, StreamPrecedenceType> - PopNextReadyStreamAndPrecedence() override { - for (SpdyPriority p = kV3HighestPriority; p <= kV3LowestPriority; ++p) { - ReadyList& ready_list = priority_infos_[p].ready_list; - if (!ready_list.empty()) { - StreamInfo* info = ready_list.front(); - ready_list.pop_front(); - --num_ready_streams_; - - DCHECK(stream_infos_.find(info->stream_id) != stream_infos_.end()); - info->ready = false; - return std::make_tuple(info->stream_id, - StreamPrecedenceType(info->priority)); - } - } - SPDY_BUG << "No ready streams available"; - return std::make_tuple(0, StreamPrecedenceType(kV3LowestPriority)); - } - - bool ShouldYield(StreamIdType stream_id) const override { - auto it = stream_infos_.find(stream_id); - if (it == stream_infos_.end()) { - SPDY_BUG << "Stream " << stream_id << " not registered"; - return false; - } - - // If there's a higher priority stream, this stream should yield. - const StreamInfo& stream_info = it->second; - for (SpdyPriority p = kV3HighestPriority; p < stream_info.priority; ++p) { - if (!priority_infos_[p].ready_list.empty()) { - return true; - } - } - - // If this priority level is empty, or this stream is the next up, there's - // no need to yield. - const auto& ready_list = priority_infos_[it->second.priority].ready_list; - if (ready_list.empty() || ready_list.front()->stream_id == stream_id) { - return false; - } - - // There are other streams in this priority level which take precedence. - // Yield. - return true; - } - - void MarkStreamReady(StreamIdType stream_id, bool add_to_front) override { - auto it = stream_infos_.find(stream_id); - if (it == stream_infos_.end()) { - SPDY_BUG << "Stream " << stream_id << " not registered"; - return; - } - StreamInfo& stream_info = it->second; - if (stream_info.ready) { - return; - } - ReadyList& ready_list = priority_infos_[stream_info.priority].ready_list; - if (add_to_front) { - ready_list.push_front(&stream_info); - } else { - ready_list.push_back(&stream_info); - } - ++num_ready_streams_; - stream_info.ready = true; - } - - void MarkStreamNotReady(StreamIdType stream_id) override { - auto it = stream_infos_.find(stream_id); - if (it == stream_infos_.end()) { - SPDY_BUG << "Stream " << stream_id << " not registered"; - return; - } - StreamInfo& stream_info = it->second; - if (!stream_info.ready) { - return; - } - bool erased = - Erase(&priority_infos_[stream_info.priority].ready_list, stream_info); - DCHECK(erased); - stream_info.ready = false; - } - - // Returns true iff the number of ready streams is non-zero. - bool HasReadyStreams() const override { return num_ready_streams_ > 0; } - - // Returns the number of ready streams. - size_t NumReadyStreams() const override { return num_ready_streams_; } - - SpdyString DebugString() const override { - return SpdyStrCat( - "PriorityWriteScheduler {num_streams=", stream_infos_.size(), - " num_ready_streams=", NumReadyStreams(), "}"); - } - - // Returns true if a stream is ready. - bool IsStreamReady(StreamIdType stream_id) const { - auto it = stream_infos_.find(stream_id); - if (it == stream_infos_.end()) { - DLOG(INFO) << "Stream " << stream_id << " not registered"; - return false; - } - return it->second.ready; - } - - private: - friend class test::PriorityWriteSchedulerPeer<StreamIdType>; - - // State kept for all registered streams. All ready streams have ready = true - // and should be present in priority_infos_[priority].ready_list. - struct StreamInfo { - SpdyPriority priority; - StreamIdType stream_id; - bool ready; - }; - - // O(1) size lookup, O(1) insert at front or back (amortized). - using ReadyList = http2::Http2Deque<StreamInfo*>; - - // State kept for each priority level. - struct PriorityInfo { - // IDs of streams that are ready to write. - ReadyList ready_list; - // Time of latest write event for stream of this priority, in microseconds. - int64_t last_event_time_usec = 0; - }; - - typedef std::unordered_map<StreamIdType, StreamInfo> StreamInfoMap; - - // Erases first occurrence (which should be the only one) of |info| in - // |ready_list|, returning true if found (and erased), or false otherwise. - // Decrements |num_ready_streams_| if an entry is erased. - bool Erase(ReadyList* ready_list, const StreamInfo& info) { - auto it = std::find(ready_list->begin(), ready_list->end(), &info); - if (it == ready_list->end()) { - return false; - } - ready_list->erase(it); - --num_ready_streams_; - return true; - } - - // Number of ready streams. - size_t num_ready_streams_ = 0; - // Per-priority state, including ready lists. - PriorityInfo priority_infos_[kV3LowestPriority + 1]; - // StreamInfos for all registered streams. - StreamInfoMap stream_infos_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_PRIORITY_WRITE_SCHEDULER_H_
diff --git a/net/third_party/spdy/core/priority_write_scheduler_test.cc b/net/third_party/spdy/core/priority_write_scheduler_test.cc deleted file mode 100644 index 68a4f88..0000000 --- a/net/third_party/spdy/core/priority_write_scheduler_test.cc +++ /dev/null
@@ -1,371 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/priority_write_scheduler.h" - -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { -namespace test { - -template <typename StreamIdType> -class PriorityWriteSchedulerPeer { - public: - explicit PriorityWriteSchedulerPeer( - PriorityWriteScheduler<StreamIdType>* scheduler) - : scheduler_(scheduler) {} - - size_t NumReadyStreams(SpdyPriority priority) const { - return scheduler_->priority_infos_[priority].ready_list.size(); - } - - private: - PriorityWriteScheduler<StreamIdType>* scheduler_; -}; - -namespace { - -class PriorityWriteSchedulerTest : public ::testing::Test { - public: - PriorityWriteSchedulerTest() : peer_(&scheduler_) {} - - PriorityWriteScheduler<SpdyStreamId> scheduler_; - PriorityWriteSchedulerPeer<SpdyStreamId> peer_; -}; - -TEST_F(PriorityWriteSchedulerTest, RegisterUnregisterStreams) { - EXPECT_FALSE(scheduler_.HasReadyStreams()); - EXPECT_FALSE(scheduler_.StreamRegistered(1)); - scheduler_.RegisterStream(1, SpdyStreamPrecedence(1)); - EXPECT_TRUE(scheduler_.StreamRegistered(1)); - - // Root stream counts as already registered. - EXPECT_SPDY_BUG( - scheduler_.RegisterStream(kHttp2RootStreamId, SpdyStreamPrecedence(1)), - "Stream 0 already registered"); - - // Try redundant registrations. - EXPECT_SPDY_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(1)), - "Stream 1 already registered"); - EXPECT_SPDY_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(2)), - "Stream 1 already registered"); - - scheduler_.RegisterStream(2, SpdyStreamPrecedence(3)); - - // Verify registration != ready. - EXPECT_FALSE(scheduler_.HasReadyStreams()); - - scheduler_.UnregisterStream(1); - scheduler_.UnregisterStream(2); - - // Try redundant unregistration. - EXPECT_SPDY_BUG(scheduler_.UnregisterStream(1), "Stream 1 not registered"); - EXPECT_SPDY_BUG(scheduler_.UnregisterStream(2), "Stream 2 not registered"); -} - -TEST_F(PriorityWriteSchedulerTest, RegisterStreamWithHttp2StreamDependency) { - EXPECT_FALSE(scheduler_.HasReadyStreams()); - EXPECT_FALSE(scheduler_.StreamRegistered(1)); - scheduler_.RegisterStream( - 1, SpdyStreamPrecedence(kHttp2RootStreamId, 123, false)); - EXPECT_TRUE(scheduler_.StreamRegistered(1)); - EXPECT_TRUE(scheduler_.GetStreamPrecedence(1).is_spdy3_priority()); - EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority()); - EXPECT_FALSE(scheduler_.HasReadyStreams()); - - EXPECT_SPDY_BUG(scheduler_.RegisterStream( - 1, SpdyStreamPrecedence(kHttp2RootStreamId, 256, false)), - "Stream 1 already registered"); - EXPECT_TRUE(scheduler_.GetStreamPrecedence(1).is_spdy3_priority()); - EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority()); - - // Registering stream with a non-existent parent stream is permissible, per - // b/15676312, but parent stream will always be reset to 0. - scheduler_.RegisterStream(2, SpdyStreamPrecedence(3, 123, false)); - EXPECT_TRUE(scheduler_.StreamRegistered(2)); - EXPECT_FALSE(scheduler_.StreamRegistered(3)); - EXPECT_EQ(kHttp2RootStreamId, scheduler_.GetStreamPrecedence(2).parent_id()); -} - -TEST_F(PriorityWriteSchedulerTest, GetStreamPrecedence) { - // Unknown streams tolerated due to b/15676312. However, return lowest - // priority. - EXPECT_EQ(kV3LowestPriority, - scheduler_.GetStreamPrecedence(1).spdy3_priority()); - - scheduler_.RegisterStream(1, SpdyStreamPrecedence(3)); - EXPECT_TRUE(scheduler_.GetStreamPrecedence(1).is_spdy3_priority()); - EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority()); - - // Redundant registration shouldn't change stream priority. - EXPECT_SPDY_BUG(scheduler_.RegisterStream(1, SpdyStreamPrecedence(4)), - "Stream 1 already registered"); - EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority()); - - scheduler_.UpdateStreamPrecedence(1, SpdyStreamPrecedence(5)); - EXPECT_EQ(5, scheduler_.GetStreamPrecedence(1).spdy3_priority()); - - // Toggling ready state shouldn't change stream priority. - scheduler_.MarkStreamReady(1, true); - EXPECT_EQ(5, scheduler_.GetStreamPrecedence(1).spdy3_priority()); - - // Test changing priority of ready stream. - EXPECT_EQ(1u, peer_.NumReadyStreams(5)); - scheduler_.UpdateStreamPrecedence(1, SpdyStreamPrecedence(6)); - EXPECT_EQ(6, scheduler_.GetStreamPrecedence(1).spdy3_priority()); - EXPECT_EQ(0u, peer_.NumReadyStreams(5)); - EXPECT_EQ(1u, peer_.NumReadyStreams(6)); - - EXPECT_EQ(1u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(6, scheduler_.GetStreamPrecedence(1).spdy3_priority()); - - scheduler_.UnregisterStream(1); - EXPECT_EQ(kV3LowestPriority, - scheduler_.GetStreamPrecedence(1).spdy3_priority()); -} - -TEST_F(PriorityWriteSchedulerTest, PopNextReadyStreamAndPrecedence) { - scheduler_.RegisterStream(1, SpdyStreamPrecedence(3)); - scheduler_.MarkStreamReady(1, true); - EXPECT_EQ(std::make_tuple(1u, SpdyStreamPrecedence(3)), - scheduler_.PopNextReadyStreamAndPrecedence()); - scheduler_.UnregisterStream(1); -} - -TEST_F(PriorityWriteSchedulerTest, UpdateStreamPrecedence) { - // For the moment, updating stream precedence on a non-registered stream - // should have no effect. In the future, it will lazily cause the stream to - // be registered (b/15676312). - EXPECT_EQ(kV3LowestPriority, - scheduler_.GetStreamPrecedence(3).spdy3_priority()); - EXPECT_FALSE(scheduler_.StreamRegistered(3)); - scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(1)); - EXPECT_FALSE(scheduler_.StreamRegistered(3)); - EXPECT_EQ(kV3LowestPriority, - scheduler_.GetStreamPrecedence(3).spdy3_priority()); - - scheduler_.RegisterStream(3, SpdyStreamPrecedence(1)); - EXPECT_EQ(1, scheduler_.GetStreamPrecedence(3).spdy3_priority()); - scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(2)); - EXPECT_EQ(2, scheduler_.GetStreamPrecedence(3).spdy3_priority()); - - // Updating priority of stream to current priority value is valid, but has no - // effect. - scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(2)); - EXPECT_EQ(2, scheduler_.GetStreamPrecedence(3).spdy3_priority()); - - // Even though stream 4 is marked ready after stream 5, it should be returned - // first by PopNextReadyStream() since it has higher priority. - scheduler_.RegisterStream(4, SpdyStreamPrecedence(1)); - scheduler_.MarkStreamReady(3, false); // priority 2 - EXPECT_TRUE(scheduler_.IsStreamReady(3)); - scheduler_.MarkStreamReady(4, false); // priority 1 - EXPECT_TRUE(scheduler_.IsStreamReady(4)); - EXPECT_EQ(4u, scheduler_.PopNextReadyStream()); - EXPECT_FALSE(scheduler_.IsStreamReady(4)); - EXPECT_EQ(3u, scheduler_.PopNextReadyStream()); - EXPECT_FALSE(scheduler_.IsStreamReady(3)); - - // Verify that lowering priority of stream 4 causes it to be returned later - // by PopNextReadyStream(). - scheduler_.MarkStreamReady(3, false); // priority 2 - scheduler_.MarkStreamReady(4, false); // priority 1 - scheduler_.UpdateStreamPrecedence(4, SpdyStreamPrecedence(3)); - EXPECT_EQ(3u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(4u, scheduler_.PopNextReadyStream()); - - scheduler_.UnregisterStream(3); -} - -TEST_F(PriorityWriteSchedulerTest, - UpdateStreamPrecedenceWithHttp2StreamDependency) { - // Unknown streams tolerated due to b/15676312, but should have no effect. - scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 100, false)); - EXPECT_FALSE(scheduler_.StreamRegistered(3)); - - scheduler_.RegisterStream(3, SpdyStreamPrecedence(3)); - scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 100, false)); - EXPECT_TRUE(scheduler_.GetStreamPrecedence(3).is_spdy3_priority()); - EXPECT_EQ(4, scheduler_.GetStreamPrecedence(3).spdy3_priority()); - - scheduler_.UnregisterStream(3); - scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 100, false)); - EXPECT_FALSE(scheduler_.StreamRegistered(3)); -} - -TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyBack) { - EXPECT_FALSE(scheduler_.HasReadyStreams()); - EXPECT_SPDY_BUG(scheduler_.MarkStreamReady(1, false), - "Stream 1 not registered"); - EXPECT_FALSE(scheduler_.HasReadyStreams()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); - - // Add a bunch of ready streams to tail of per-priority lists. - // Expected order: (P2) 4, (P3) 1, 2, 3, (P5) 5. - scheduler_.RegisterStream(1, SpdyStreamPrecedence(3)); - scheduler_.MarkStreamReady(1, false); - EXPECT_TRUE(scheduler_.HasReadyStreams()); - scheduler_.RegisterStream(2, SpdyStreamPrecedence(3)); - scheduler_.MarkStreamReady(2, false); - scheduler_.RegisterStream(3, SpdyStreamPrecedence(3)); - scheduler_.MarkStreamReady(3, false); - scheduler_.RegisterStream(4, SpdyStreamPrecedence(2)); - scheduler_.MarkStreamReady(4, false); - scheduler_.RegisterStream(5, SpdyStreamPrecedence(5)); - scheduler_.MarkStreamReady(5, false); - - EXPECT_EQ(4u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(1u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(2u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(3u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(5u, scheduler_.PopNextReadyStream()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); -} - -TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyFront) { - EXPECT_FALSE(scheduler_.HasReadyStreams()); - EXPECT_SPDY_BUG(scheduler_.MarkStreamReady(1, true), - "Stream 1 not registered"); - EXPECT_FALSE(scheduler_.HasReadyStreams()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); - - // Add a bunch of ready streams to head of per-priority lists. - // Expected order: (P2) 4, (P3) 3, 2, 1, (P5) 5 - scheduler_.RegisterStream(1, SpdyStreamPrecedence(3)); - scheduler_.MarkStreamReady(1, true); - EXPECT_TRUE(scheduler_.HasReadyStreams()); - scheduler_.RegisterStream(2, SpdyStreamPrecedence(3)); - scheduler_.MarkStreamReady(2, true); - scheduler_.RegisterStream(3, SpdyStreamPrecedence(3)); - scheduler_.MarkStreamReady(3, true); - scheduler_.RegisterStream(4, SpdyStreamPrecedence(2)); - scheduler_.MarkStreamReady(4, true); - scheduler_.RegisterStream(5, SpdyStreamPrecedence(5)); - scheduler_.MarkStreamReady(5, true); - - EXPECT_EQ(4u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(3u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(2u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(1u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(5u, scheduler_.PopNextReadyStream()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); -} - -TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyBackAndFront) { - scheduler_.RegisterStream(1, SpdyStreamPrecedence(4)); - scheduler_.RegisterStream(2, SpdyStreamPrecedence(3)); - scheduler_.RegisterStream(3, SpdyStreamPrecedence(3)); - scheduler_.RegisterStream(4, SpdyStreamPrecedence(3)); - scheduler_.RegisterStream(5, SpdyStreamPrecedence(4)); - scheduler_.RegisterStream(6, SpdyStreamPrecedence(1)); - - // Add a bunch of ready streams to per-priority lists, with variety of adding - // at head and tail. - // Expected order: (P1) 6, (P3) 4, 2, 3, (P4) 1, 5 - scheduler_.MarkStreamReady(1, true); - scheduler_.MarkStreamReady(2, true); - scheduler_.MarkStreamReady(3, false); - scheduler_.MarkStreamReady(4, true); - scheduler_.MarkStreamReady(5, false); - scheduler_.MarkStreamReady(6, true); - - EXPECT_EQ(6u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(4u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(2u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(3u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(1u, scheduler_.PopNextReadyStream()); - EXPECT_EQ(5u, scheduler_.PopNextReadyStream()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); -} - -TEST_F(PriorityWriteSchedulerTest, MarkStreamNotReady) { - // Verify ready state reflected in NumReadyStreams(). - scheduler_.RegisterStream(1, SpdyStreamPrecedence(1)); - EXPECT_EQ(0u, scheduler_.NumReadyStreams()); - scheduler_.MarkStreamReady(1, false); - EXPECT_EQ(1u, scheduler_.NumReadyStreams()); - scheduler_.MarkStreamNotReady(1); - EXPECT_EQ(0u, scheduler_.NumReadyStreams()); - - // Empty pop should fail. - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); - - // Tolerate redundant marking of a stream as not ready. - scheduler_.MarkStreamNotReady(1); - EXPECT_EQ(0u, scheduler_.NumReadyStreams()); - - // Should only be able to mark registered streams. - EXPECT_SPDY_BUG(scheduler_.MarkStreamNotReady(3), "Stream 3 not registered"); -} - -TEST_F(PriorityWriteSchedulerTest, UnregisterRemovesStream) { - scheduler_.RegisterStream(3, SpdyStreamPrecedence(4)); - scheduler_.MarkStreamReady(3, false); - EXPECT_EQ(1u, scheduler_.NumReadyStreams()); - - // Unregistering a stream should remove it from set of ready streams. - scheduler_.UnregisterStream(3); - EXPECT_EQ(0u, scheduler_.NumReadyStreams()); - EXPECT_SPDY_BUG(EXPECT_EQ(0u, scheduler_.PopNextReadyStream()), - "No ready streams available"); -} - -TEST_F(PriorityWriteSchedulerTest, ShouldYield) { - scheduler_.RegisterStream(1, SpdyStreamPrecedence(1)); - scheduler_.RegisterStream(4, SpdyStreamPrecedence(4)); - scheduler_.RegisterStream(5, SpdyStreamPrecedence(4)); - scheduler_.RegisterStream(7, SpdyStreamPrecedence(7)); - - // Make sure we don't yield when the list is empty. - EXPECT_FALSE(scheduler_.ShouldYield(1)); - - // Add a low priority stream. - scheduler_.MarkStreamReady(4, false); - // 4 should not yield to itself. - EXPECT_FALSE(scheduler_.ShouldYield(4)); - // 7 should yield as 4 is blocked and a higher priority. - EXPECT_TRUE(scheduler_.ShouldYield(7)); - // 5 should yield to 4 as they are the same priority. - EXPECT_TRUE(scheduler_.ShouldYield(5)); - // 1 should not yield as 1 is higher priority. - EXPECT_FALSE(scheduler_.ShouldYield(1)); - - // Add a second stream in that priority class. - scheduler_.MarkStreamReady(5, false); - // 4 and 5 are both blocked, but 4 is at the front so should not yield. - EXPECT_FALSE(scheduler_.ShouldYield(4)); - EXPECT_TRUE(scheduler_.ShouldYield(5)); -} - -TEST_F(PriorityWriteSchedulerTest, GetLatestEventWithPrecedence) { - EXPECT_SPDY_BUG(scheduler_.RecordStreamEventTime(3, 5), - "Stream 3 not registered"); - EXPECT_SPDY_BUG(EXPECT_EQ(0, scheduler_.GetLatestEventWithPrecedence(4)), - "Stream 4 not registered"); - - for (int i = 1; i < 5; ++i) { - scheduler_.RegisterStream(i, SpdyStreamPrecedence(i)); - } - for (int i = 1; i < 5; ++i) { - EXPECT_EQ(0, scheduler_.GetLatestEventWithPrecedence(i)); - } - for (int i = 1; i < 5; ++i) { - scheduler_.RecordStreamEventTime(i, i * 100); - } - for (int i = 1; i < 5; ++i) { - EXPECT_EQ((i - 1) * 100, scheduler_.GetLatestEventWithPrecedence(i)); - } -} - -} // namespace -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_alt_svc_wire_format.cc b/net/third_party/spdy/core/spdy_alt_svc_wire_format.cc deleted file mode 100644 index 2d5fd214..0000000 --- a/net/third_party/spdy/core/spdy_alt_svc_wire_format.cc +++ /dev/null
@@ -1,390 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" - -#include <algorithm> -#include <cctype> -#include <limits> - -#include "base/logging.h" -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" - -namespace spdy { - -namespace { - -template <class T> -bool ParsePositiveIntegerImpl(SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - T* value) { - *value = 0; - for (; c != end && std::isdigit(*c); ++c) { - if (*value > std::numeric_limits<T>::max() / 10) { - return false; - } - *value *= 10; - if (*value > std::numeric_limits<T>::max() - (*c - '0')) { - return false; - } - *value += *c - '0'; - } - return (c == end && *value > 0); -} - -} // namespace - -SpdyAltSvcWireFormat::AlternativeService::AlternativeService() = default; - -SpdyAltSvcWireFormat::AlternativeService::AlternativeService( - const SpdyString& protocol_id, - const SpdyString& host, - uint16_t port, - uint32_t max_age, - VersionVector version) - : protocol_id(protocol_id), - host(host), - port(port), - max_age(max_age), - version(std::move(version)) {} - -SpdyAltSvcWireFormat::AlternativeService::~AlternativeService() = default; - -SpdyAltSvcWireFormat::AlternativeService::AlternativeService( - const AlternativeService& other) = default; - -// static -bool SpdyAltSvcWireFormat::ParseHeaderFieldValue( - SpdyStringPiece value, - AlternativeServiceVector* altsvc_vector) { - // Empty value is invalid according to the specification. - if (value.empty()) { - return false; - } - altsvc_vector->clear(); - if (value == SpdyStringPiece("clear")) { - return true; - } - SpdyStringPiece::const_iterator c = value.begin(); - while (c != value.end()) { - // Parse protocol-id. - SpdyStringPiece::const_iterator percent_encoded_protocol_id_end = - std::find(c, value.end(), '='); - SpdyString protocol_id; - if (percent_encoded_protocol_id_end == c || - !PercentDecode(c, percent_encoded_protocol_id_end, &protocol_id)) { - return false; - } - // Check for IETF format for advertising QUIC: - // hq=":443";quic=51303338;quic=51303334 - const bool is_ietf_format_quic = (protocol_id == "hq"); - c = percent_encoded_protocol_id_end; - if (c == value.end()) { - return false; - } - // Parse alt-authority. - DCHECK_EQ('=', *c); - ++c; - if (c == value.end() || *c != '"') { - return false; - } - ++c; - SpdyStringPiece::const_iterator alt_authority_begin = c; - for (; c != value.end() && *c != '"'; ++c) { - // Decode backslash encoding. - if (*c != '\\') { - continue; - } - ++c; - if (c == value.end()) { - return false; - } - } - if (c == alt_authority_begin || c == value.end()) { - return false; - } - DCHECK_EQ('"', *c); - SpdyString host; - uint16_t port; - if (!ParseAltAuthority(alt_authority_begin, c, &host, &port)) { - return false; - } - ++c; - // Parse parameters. - uint32_t max_age = 86400; - VersionVector version; - SpdyStringPiece::const_iterator parameters_end = - std::find(c, value.end(), ','); - while (c != parameters_end) { - SkipWhiteSpace(&c, parameters_end); - if (c == parameters_end) { - break; - } - if (*c != ';') { - return false; - } - ++c; - SkipWhiteSpace(&c, parameters_end); - if (c == parameters_end) { - break; - } - SpdyString parameter_name; - for (; c != parameters_end && *c != '=' && *c != ' ' && *c != '\t'; ++c) { - parameter_name.push_back(tolower(*c)); - } - SkipWhiteSpace(&c, parameters_end); - if (c == parameters_end || *c != '=') { - return false; - } - ++c; - SkipWhiteSpace(&c, parameters_end); - SpdyStringPiece::const_iterator parameter_value_begin = c; - for (; c != parameters_end && *c != ';' && *c != ' ' && *c != '\t'; ++c) { - } - if (c == parameter_value_begin) { - return false; - } - if (parameter_name == "ma") { - if (!ParsePositiveInteger32(parameter_value_begin, c, &max_age)) { - return false; - } - } else if (!is_ietf_format_quic && parameter_name == "v") { - // Version is a comma separated list of positive integers enclosed in - // quotation marks. Since it can contain commas, which are not - // delineating alternative service entries, |parameters_end| and |c| can - // be invalid. - if (*parameter_value_begin != '"') { - return false; - } - c = std::find(parameter_value_begin + 1, value.end(), '"'); - if (c == value.end()) { - return false; - } - ++c; - parameters_end = std::find(c, value.end(), ','); - SpdyStringPiece::const_iterator v_begin = parameter_value_begin + 1; - while (v_begin < c) { - SpdyStringPiece::const_iterator v_end = v_begin; - while (v_end < c - 1 && *v_end != ',') { - ++v_end; - } - uint16_t v; - if (!ParsePositiveInteger16(v_begin, v_end, &v)) { - return false; - } - version.push_back(v); - v_begin = v_end + 1; - if (v_begin == c - 1) { - // List ends in comma. - return false; - } - } - } else if (is_ietf_format_quic && parameter_name == "quic") { - // IETF format for advertising QUIC. Version is hex encoding of QUIC - // version tag. Hex-encoded string should not include leading "0x" or - // leading zeros. - // Example for advertising QUIC versions "Q038" and "Q034": - // hq=":443";quic=51303338;quic=51303334 - if (*parameter_value_begin == '0') { - return false; - } - // Versions will be stored as the uint32_t hex decoding of the param - // value string. Example: QUIC version "Q038", which is advertised as: - // hq=":443";quic=51303338 - // ... will be stored in |versions| as 0x51303338. - uint32_t quic_version; - if (!SpdyHexDecodeToUInt32(SpdyStringPiece(parameter_value_begin, - c - parameter_value_begin), - &quic_version) || - quic_version == 0) { - return false; - } - version.push_back(quic_version); - } - } - altsvc_vector->emplace_back(protocol_id, host, port, max_age, version); - for (; c != value.end() && (*c == ' ' || *c == '\t' || *c == ','); ++c) { - } - } - return true; -} - -// static -SpdyString SpdyAltSvcWireFormat::SerializeHeaderFieldValue( - const AlternativeServiceVector& altsvc_vector) { - if (altsvc_vector.empty()) { - return SpdyString("clear"); - } - const char kNibbleToHex[] = "0123456789ABCDEF"; - SpdyString value; - for (const AlternativeService& altsvc : altsvc_vector) { - if (!value.empty()) { - value.push_back(','); - } - // Check for IETF format for advertising QUIC. - const bool is_ietf_format_quic = (altsvc.protocol_id == "hq"); - // Percent escape protocol id according to - // http://tools.ietf.org/html/rfc7230#section-3.2.6. - for (char c : altsvc.protocol_id) { - if (isalnum(c)) { - value.push_back(c); - continue; - } - switch (c) { - case '!': - case '#': - case '$': - case '&': - case '\'': - case '*': - case '+': - case '-': - case '.': - case '^': - case '_': - case '`': - case '|': - case '~': - value.push_back(c); - break; - default: - value.push_back('%'); - // Network byte order is big-endian. - value.push_back(kNibbleToHex[c >> 4]); - value.push_back(kNibbleToHex[c & 0x0f]); - break; - } - } - value.push_back('='); - value.push_back('"'); - for (char c : altsvc.host) { - if (c == '"' || c == '\\') { - value.push_back('\\'); - } - value.push_back(c); - } - value.append(SpdyStrCat(":", altsvc.port, "\"")); - if (altsvc.max_age != 86400) { - value.append(SpdyStrCat("; ma=", altsvc.max_age)); - } - if (!altsvc.version.empty()) { - if (is_ietf_format_quic) { - for (uint32_t quic_version : altsvc.version) { - value.append("; quic="); - value.append(SpdyHexEncodeUInt32AndTrim(quic_version)); - } - } else { - value.append("; v=\""); - for (auto it = altsvc.version.begin(); it != altsvc.version.end(); - ++it) { - if (it != altsvc.version.begin()) { - value.append(","); - } - value.append(SpdyStrCat(*it)); - } - value.append("\""); - } - } - } - return value; -} - -// static -void SpdyAltSvcWireFormat::SkipWhiteSpace(SpdyStringPiece::const_iterator* c, - SpdyStringPiece::const_iterator end) { - for (; *c != end && (**c == ' ' || **c == '\t'); ++*c) { - } -} - -// static -bool SpdyAltSvcWireFormat::PercentDecode(SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - SpdyString* output) { - output->clear(); - for (; c != end; ++c) { - if (*c != '%') { - output->push_back(*c); - continue; - } - DCHECK_EQ('%', *c); - ++c; - if (c == end || !std::isxdigit(*c)) { - return false; - } - // Network byte order is big-endian. - char decoded = SpdyHexDigitToInt(*c) << 4; - ++c; - if (c == end || !std::isxdigit(*c)) { - return false; - } - decoded += SpdyHexDigitToInt(*c); - output->push_back(decoded); - } - return true; -} - -// static -bool SpdyAltSvcWireFormat::ParseAltAuthority( - SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - SpdyString* host, - uint16_t* port) { - host->clear(); - if (c == end) { - return false; - } - if (*c == '[') { - for (; c != end && *c != ']'; ++c) { - if (*c == '"') { - // Port is mandatory. - return false; - } - host->push_back(*c); - } - if (c == end) { - return false; - } - DCHECK_EQ(']', *c); - host->push_back(*c); - ++c; - } else { - for (; c != end && *c != ':'; ++c) { - if (*c == '"') { - // Port is mandatory. - return false; - } - if (*c == '\\') { - ++c; - if (c == end) { - return false; - } - } - host->push_back(*c); - } - } - if (c == end || *c != ':') { - return false; - } - DCHECK_EQ(':', *c); - ++c; - return ParsePositiveInteger16(c, end, port); -} - -// static -bool SpdyAltSvcWireFormat::ParsePositiveInteger16( - SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - uint16_t* value) { - return ParsePositiveIntegerImpl<uint16_t>(c, end, value); -} - -// static -bool SpdyAltSvcWireFormat::ParsePositiveInteger32( - SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - uint32_t* value) { - return ParsePositiveIntegerImpl<uint32_t>(c, end, value); -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_alt_svc_wire_format.h b/net/third_party/spdy/core/spdy_alt_svc_wire_format.h deleted file mode 100644 index 1d2c189..0000000 --- a/net/third_party/spdy/core/spdy_alt_svc_wire_format.h +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains data structures and utility functions used for serializing -// and parsing alternative service header values, common to HTTP/1.1 header -// fields and HTTP/2 and QUIC ALTSVC frames. See specification at -// https://httpwg.github.io/http-extensions/alt-svc.html. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_ALT_SVC_WIRE_FORMAT_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_ALT_SVC_WIRE_FORMAT_H_ - -#include <cstdint> -#include <vector> - -#include "net/third_party/spdy/platform/api/spdy_containers.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { - -namespace test { -class SpdyAltSvcWireFormatPeer; -} // namespace test - -class SPDY_EXPORT_PRIVATE SpdyAltSvcWireFormat { - public: - using VersionVector = SpdyInlinedVector<uint32_t, 8>; - - struct SPDY_EXPORT_PRIVATE AlternativeService { - SpdyString protocol_id; - SpdyString host; - - // Default is 0: invalid port. - uint16_t port = 0; - // Default is one day. - uint32_t max_age = 86400; - // Default is empty: unspecified version. - VersionVector version; - - AlternativeService(); - AlternativeService(const SpdyString& protocol_id, - const SpdyString& host, - uint16_t port, - uint32_t max_age, - VersionVector version); - AlternativeService(const AlternativeService& other); - ~AlternativeService(); - - bool operator==(const AlternativeService& other) const { - return protocol_id == other.protocol_id && host == other.host && - port == other.port && version == other.version && - max_age == other.max_age; - } - }; - // An empty vector means alternative services should be cleared for given - // origin. Note that the wire format for this is the string "clear", not an - // empty value (which is invalid). - typedef std::vector<AlternativeService> AlternativeServiceVector; - - friend class test::SpdyAltSvcWireFormatPeer; - static bool ParseHeaderFieldValue(SpdyStringPiece value, - AlternativeServiceVector* altsvc_vector); - static SpdyString SerializeHeaderFieldValue( - const AlternativeServiceVector& altsvc_vector); - - private: - static void SkipWhiteSpace(SpdyStringPiece::const_iterator* c, - SpdyStringPiece::const_iterator end); - static bool PercentDecode(SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - SpdyString* output); - static bool ParseAltAuthority(SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - SpdyString* host, - uint16_t* port); - static bool ParsePositiveInteger16(SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - uint16_t* value); - static bool ParsePositiveInteger32(SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - uint32_t* value); -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_ALT_SVC_WIRE_FORMAT_H_
diff --git a/net/third_party/spdy/core/spdy_alt_svc_wire_format_test.cc b/net/third_party/spdy/core/spdy_alt_svc_wire_format_test.cc deleted file mode 100644 index 9911ccf3..0000000 --- a/net/third_party/spdy/core/spdy_alt_svc_wire_format_test.cc +++ /dev/null
@@ -1,573 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" - -#include "base/logging.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -namespace test { - -// Expose all private methods of class SpdyAltSvcWireFormat. -class SpdyAltSvcWireFormatPeer { - public: - static void SkipWhiteSpace(SpdyStringPiece::const_iterator* c, - SpdyStringPiece::const_iterator end) { - SpdyAltSvcWireFormat::SkipWhiteSpace(c, end); - } - static bool PercentDecode(SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - SpdyString* output) { - return SpdyAltSvcWireFormat::PercentDecode(c, end, output); - } - static bool ParseAltAuthority(SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - SpdyString* host, - uint16_t* port) { - return SpdyAltSvcWireFormat::ParseAltAuthority(c, end, host, port); - } - static bool ParsePositiveInteger16(SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - uint16_t* max_age) { - return SpdyAltSvcWireFormat::ParsePositiveInteger16(c, end, max_age); - } - static bool ParsePositiveInteger32(SpdyStringPiece::const_iterator c, - SpdyStringPiece::const_iterator end, - uint32_t* max_age) { - return SpdyAltSvcWireFormat::ParsePositiveInteger32(c, end, max_age); - } -}; - -} // namespace test - -namespace { - -// Generate header field values, possibly with multiply defined parameters and -// random case, and corresponding AlternativeService entries. -void FuzzHeaderFieldValue( - int i, - SpdyString* header_field_value, - SpdyAltSvcWireFormat::AlternativeService* expected_altsvc) { - if (!header_field_value->empty()) { - header_field_value->push_back(','); - } - // TODO(b/77515496): use struct of bools instead of int |i| to generate the - // header field value. - bool is_ietf_format_quic = (i & 1 << 0) != 0; - if (i & 1 << 0) { - expected_altsvc->protocol_id = "hq"; - header_field_value->append("hq=\""); - } else { - expected_altsvc->protocol_id = "a=b%c"; - header_field_value->append("a%3Db%25c=\""); - } - if (i & 1 << 1) { - expected_altsvc->host = "foo\"bar\\baz"; - header_field_value->append("foo\\\"bar\\\\baz"); - } else { - expected_altsvc->host = ""; - } - expected_altsvc->port = 42; - header_field_value->append(":42\""); - if (i & 1 << 2) { - header_field_value->append(" "); - } - if (i & 3 << 3) { - expected_altsvc->max_age = 1111; - header_field_value->append(";"); - if (i & 1 << 3) { - header_field_value->append(" "); - } - header_field_value->append("mA=1111"); - if (i & 2 << 3) { - header_field_value->append(" "); - } - } - if (i & 1 << 5) { - header_field_value->append("; J=s"); - } - if (i & 1 << 6) { - if (is_ietf_format_quic) { - if (i & 1 << 7) { - expected_altsvc->version.push_back(0x923457e); - header_field_value->append("; quic=923457E"); - } else { - expected_altsvc->version.push_back(1); - expected_altsvc->version.push_back(0xFFFFFFFF); - header_field_value->append("; quic=1; quic=fFfFffFf"); - } - } else { - if (i & i << 7) { - expected_altsvc->version.push_back(24); - header_field_value->append("; v=\"24\""); - } else { - expected_altsvc->version.push_back(1); - expected_altsvc->version.push_back(65535); - header_field_value->append("; v=\"1,65535\""); - } - } - } - if (i & 1 << 8) { - expected_altsvc->max_age = 999999999; - header_field_value->append("; Ma=999999999"); - } - if (i & 1 << 9) { - header_field_value->append(";"); - } - if (i & 1 << 10) { - header_field_value->append(" "); - } - if (i & 1 << 11) { - header_field_value->append(","); - } - if (i & 1 << 12) { - header_field_value->append(" "); - } -} - -// Generate AlternativeService entries and corresponding header field values in -// canonical form, that is, what SerializeHeaderFieldValue() should output. -void FuzzAlternativeService(int i, - SpdyAltSvcWireFormat::AlternativeService* altsvc, - SpdyString* expected_header_field_value) { - if (!expected_header_field_value->empty()) { - expected_header_field_value->push_back(','); - } - altsvc->protocol_id = "a=b%c"; - altsvc->port = 42; - expected_header_field_value->append("a%3Db%25c=\""); - if (i & 1 << 0) { - altsvc->host = "foo\"bar\\baz"; - expected_header_field_value->append("foo\\\"bar\\\\baz"); - } - expected_header_field_value->append(":42\""); - if (i & 1 << 1) { - altsvc->max_age = 1111; - expected_header_field_value->append("; ma=1111"); - } - if (i & 1 << 2) { - altsvc->version.push_back(24); - altsvc->version.push_back(25); - expected_header_field_value->append("; v=\"24,25\""); - } -} - -// Tests of public API. - -TEST(SpdyAltSvcWireFormatTest, DefaultValues) { - SpdyAltSvcWireFormat::AlternativeService altsvc; - EXPECT_EQ("", altsvc.protocol_id); - EXPECT_EQ("", altsvc.host); - EXPECT_EQ(0u, altsvc.port); - EXPECT_EQ(86400u, altsvc.max_age); - EXPECT_TRUE(altsvc.version.empty()); -} - -TEST(SpdyAltSvcWireFormatTest, ParseInvalidEmptyHeaderFieldValue) { - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - ASSERT_FALSE(SpdyAltSvcWireFormat::ParseHeaderFieldValue("", &altsvc_vector)); -} - -TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueClear) { - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - ASSERT_TRUE( - SpdyAltSvcWireFormat::ParseHeaderFieldValue("clear", &altsvc_vector)); - EXPECT_EQ(0u, altsvc_vector.size()); -} - -// Fuzz test of ParseHeaderFieldValue() with optional whitespaces, ignored -// parameters, duplicate parameters, trailing space, trailing alternate service -// separator, etc. Single alternative service at a time. -TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValue) { - for (int i = 0; i < 1 << 13; ++i) { - SpdyString header_field_value; - SpdyAltSvcWireFormat::AlternativeService expected_altsvc; - FuzzHeaderFieldValue(i, &header_field_value, &expected_altsvc); - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue(header_field_value, - &altsvc_vector)); - ASSERT_EQ(1u, altsvc_vector.size()); - EXPECT_EQ(expected_altsvc.protocol_id, altsvc_vector[0].protocol_id); - EXPECT_EQ(expected_altsvc.host, altsvc_vector[0].host); - EXPECT_EQ(expected_altsvc.port, altsvc_vector[0].port); - EXPECT_EQ(expected_altsvc.max_age, altsvc_vector[0].max_age); - EXPECT_EQ(expected_altsvc.version, altsvc_vector[0].version); - - // Roundtrip test starting with |altsvc_vector|. - SpdyString reserialized_header_field_value = - SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector); - SpdyAltSvcWireFormat::AlternativeServiceVector roundtrip_altsvc_vector; - ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( - reserialized_header_field_value, &roundtrip_altsvc_vector)); - ASSERT_EQ(1u, roundtrip_altsvc_vector.size()); - EXPECT_EQ(expected_altsvc.protocol_id, - roundtrip_altsvc_vector[0].protocol_id); - EXPECT_EQ(expected_altsvc.host, roundtrip_altsvc_vector[0].host); - EXPECT_EQ(expected_altsvc.port, roundtrip_altsvc_vector[0].port); - EXPECT_EQ(expected_altsvc.max_age, roundtrip_altsvc_vector[0].max_age); - EXPECT_EQ(expected_altsvc.version, roundtrip_altsvc_vector[0].version); - } -} - -// Fuzz test of ParseHeaderFieldValue() with optional whitespaces, ignored -// parameters, duplicate parameters, trailing space, trailing alternate service -// separator, etc. Possibly multiple alternative service at a time. -TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueMultiple) { - for (int i = 0; i < 1 << 13;) { - SpdyString header_field_value; - SpdyAltSvcWireFormat::AlternativeServiceVector expected_altsvc_vector; - // This will generate almost two hundred header field values with two, - // three, four, five, six, and seven alternative services each, and - // thousands with a single one. - do { - SpdyAltSvcWireFormat::AlternativeService expected_altsvc; - FuzzHeaderFieldValue(i, &header_field_value, &expected_altsvc); - expected_altsvc_vector.push_back(expected_altsvc); - ++i; - } while (i % 6 < i % 7); - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue(header_field_value, - &altsvc_vector)); - ASSERT_EQ(expected_altsvc_vector.size(), altsvc_vector.size()); - for (unsigned int j = 0; j < altsvc_vector.size(); ++j) { - EXPECT_EQ(expected_altsvc_vector[j].protocol_id, - altsvc_vector[j].protocol_id); - EXPECT_EQ(expected_altsvc_vector[j].host, altsvc_vector[j].host); - EXPECT_EQ(expected_altsvc_vector[j].port, altsvc_vector[j].port); - EXPECT_EQ(expected_altsvc_vector[j].max_age, altsvc_vector[j].max_age); - EXPECT_EQ(expected_altsvc_vector[j].version, altsvc_vector[j].version); - } - - // Roundtrip test starting with |altsvc_vector|. - SpdyString reserialized_header_field_value = - SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector); - SpdyAltSvcWireFormat::AlternativeServiceVector roundtrip_altsvc_vector; - ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( - reserialized_header_field_value, &roundtrip_altsvc_vector)); - ASSERT_EQ(expected_altsvc_vector.size(), roundtrip_altsvc_vector.size()); - for (unsigned int j = 0; j < roundtrip_altsvc_vector.size(); ++j) { - EXPECT_EQ(expected_altsvc_vector[j].protocol_id, - roundtrip_altsvc_vector[j].protocol_id); - EXPECT_EQ(expected_altsvc_vector[j].host, - roundtrip_altsvc_vector[j].host); - EXPECT_EQ(expected_altsvc_vector[j].port, - roundtrip_altsvc_vector[j].port); - EXPECT_EQ(expected_altsvc_vector[j].max_age, - roundtrip_altsvc_vector[j].max_age); - EXPECT_EQ(expected_altsvc_vector[j].version, - roundtrip_altsvc_vector[j].version); - } - } -} - -TEST(SpdyAltSvcWireFormatTest, SerializeEmptyHeaderFieldValue) { - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - EXPECT_EQ("clear", - SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector)); -} - -// Test ParseHeaderFieldValue() and SerializeHeaderFieldValue() on the same pair -// of |expected_header_field_value| and |altsvc|, with and without hostname and -// each -// parameter. Single alternative service at a time. -TEST(SpdyAltSvcWireFormatTest, RoundTrip) { - for (int i = 0; i < 1 << 3; ++i) { - SpdyAltSvcWireFormat::AlternativeService altsvc; - SpdyString expected_header_field_value; - FuzzAlternativeService(i, &altsvc, &expected_header_field_value); - - // Test ParseHeaderFieldValue(). - SpdyAltSvcWireFormat::AlternativeServiceVector parsed_altsvc_vector; - ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( - expected_header_field_value, &parsed_altsvc_vector)); - ASSERT_EQ(1u, parsed_altsvc_vector.size()); - EXPECT_EQ(altsvc.protocol_id, parsed_altsvc_vector[0].protocol_id); - EXPECT_EQ(altsvc.host, parsed_altsvc_vector[0].host); - EXPECT_EQ(altsvc.port, parsed_altsvc_vector[0].port); - EXPECT_EQ(altsvc.max_age, parsed_altsvc_vector[0].max_age); - EXPECT_EQ(altsvc.version, parsed_altsvc_vector[0].version); - - // Test SerializeHeaderFieldValue(). - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - altsvc_vector.push_back(altsvc); - EXPECT_EQ(expected_header_field_value, - SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector)); - } -} - -// Test ParseHeaderFieldValue() and SerializeHeaderFieldValue() on the same pair -// of |expected_header_field_value| and |altsvc|, with and without hostname and -// each -// parameter. Multiple alternative services at a time. -TEST(SpdyAltSvcWireFormatTest, RoundTripMultiple) { - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - SpdyString expected_header_field_value; - for (int i = 0; i < 1 << 3; ++i) { - SpdyAltSvcWireFormat::AlternativeService altsvc; - FuzzAlternativeService(i, &altsvc, &expected_header_field_value); - altsvc_vector.push_back(altsvc); - } - - // Test ParseHeaderFieldValue(). - SpdyAltSvcWireFormat::AlternativeServiceVector parsed_altsvc_vector; - ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( - expected_header_field_value, &parsed_altsvc_vector)); - ASSERT_EQ(altsvc_vector.size(), parsed_altsvc_vector.size()); - auto expected_it = altsvc_vector.begin(); - auto parsed_it = parsed_altsvc_vector.begin(); - for (; expected_it != altsvc_vector.end(); ++expected_it, ++parsed_it) { - EXPECT_EQ(expected_it->protocol_id, parsed_it->protocol_id); - EXPECT_EQ(expected_it->host, parsed_it->host); - EXPECT_EQ(expected_it->port, parsed_it->port); - EXPECT_EQ(expected_it->max_age, parsed_it->max_age); - EXPECT_EQ(expected_it->version, parsed_it->version); - } - - // Test SerializeHeaderFieldValue(). - EXPECT_EQ(expected_header_field_value, - SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector)); -} - -// ParseHeaderFieldValue() should return false on malformed field values: -// invalid percent encoding, unmatched quotation mark, empty port, non-numeric -// characters in numeric fields. -TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueInvalid) { - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - const char* invalid_field_value_array[] = {"a%", - "a%x", - "a%b", - "a%9z", - "a=", - "a=\"", - "a=\"b\"", - "a=\":\"", - "a=\"c:\"", - "a=\"c:foo\"", - "a=\"c:42foo\"", - "a=\"b:42\"bar", - "a=\"b:42\" ; m", - "a=\"b:42\" ; min-age", - "a=\"b:42\" ; ma", - "a=\"b:42\" ; ma=", - "a=\"b:42\" ; v=\"..\"", - "a=\"b:42\" ; ma=ma", - "a=\"b:42\" ; ma=123bar", - "a=\"b:42\" ; v=24", - "a=\"b:42\" ; v=24,25", - "a=\"b:42\" ; v=\"-3\"", - "a=\"b:42\" ; v=\"1.2\"", - "a=\"b:42\" ; v=\"24,\""}; - for (const char* invalid_field_value : invalid_field_value_array) { - EXPECT_FALSE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( - invalid_field_value, &altsvc_vector)) - << invalid_field_value; - } -} - -// ParseHeaderFieldValue() should return false on a field values truncated -// before closing quotation mark, without trying to access memory beyond the end -// of the input. -TEST(SpdyAltSvcWireFormatTest, ParseTruncatedHeaderFieldValue) { - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - const char* field_value_array[] = {"a=\":137\"", "a=\"foo:137\"", - "a%25=\"foo\\\"bar\\\\baz:137\""}; - for (const SpdyString& field_value : field_value_array) { - for (size_t len = 1; len < field_value.size(); ++len) { - EXPECT_FALSE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( - field_value.substr(0, len), &altsvc_vector)) - << len; - } - } -} - -// Tests of private methods. - -// Test SkipWhiteSpace(). -TEST(SpdyAltSvcWireFormatTest, SkipWhiteSpace) { - SpdyStringPiece input("a \tb "); - SpdyStringPiece::const_iterator c = input.begin(); - test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); - ASSERT_EQ(input.begin(), c); - ++c; - test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); - ASSERT_EQ(input.begin() + 3, c); - ++c; - test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); - ASSERT_EQ(input.end(), c); -} - -// Test PercentDecode() on valid input. -TEST(SpdyAltSvcWireFormatTest, PercentDecodeValid) { - SpdyStringPiece input(""); - SpdyString output; - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( - input.begin(), input.end(), &output)); - EXPECT_EQ("", output); - - input = SpdyStringPiece("foo"); - output.clear(); - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( - input.begin(), input.end(), &output)); - EXPECT_EQ("foo", output); - - input = SpdyStringPiece("%2ca%5Cb"); - output.clear(); - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( - input.begin(), input.end(), &output)); - EXPECT_EQ(",a\\b", output); -} - -// Test PercentDecode() on invalid input. -TEST(SpdyAltSvcWireFormatTest, PercentDecodeInvalid) { - const char* invalid_input_array[] = {"a%", "a%x", "a%b", "%J22", "%9z"}; - for (const char* invalid_input : invalid_input_array) { - SpdyStringPiece input(invalid_input); - SpdyString output; - EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::PercentDecode( - input.begin(), input.end(), &output)) - << input; - } -} - -// Test ParseAltAuthority() on valid input. -TEST(SpdyAltSvcWireFormatTest, ParseAltAuthorityValid) { - SpdyStringPiece input(":42"); - SpdyString host; - uint16_t port; - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( - input.begin(), input.end(), &host, &port)); - EXPECT_TRUE(host.empty()); - EXPECT_EQ(42, port); - - input = SpdyStringPiece("foo:137"); - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( - input.begin(), input.end(), &host, &port)); - EXPECT_EQ("foo", host); - EXPECT_EQ(137, port); - - input = SpdyStringPiece("[2003:8:0:16::509d:9615]:443"); - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( - input.begin(), input.end(), &host, &port)); - EXPECT_EQ("[2003:8:0:16::509d:9615]", host); - EXPECT_EQ(443, port); -} - -// Test ParseAltAuthority() on invalid input: empty string, no port, zero port, -// non-digit characters following port. -TEST(SpdyAltSvcWireFormatTest, ParseAltAuthorityInvalid) { - const char* invalid_input_array[] = {"", - ":", - "foo:", - ":bar", - ":0", - "foo:0", - ":12bar", - "foo:23bar", - " ", - ":12 ", - "foo:12 ", - "[2003:8:0:16::509d:9615]", - "[2003:8:0:16::509d:9615]:", - "[2003:8:0:16::509d:9615]foo:443", - "[2003:8:0:16::509d:9615:443", - "2003:8:0:16::509d:9615]:443"}; - for (const char* invalid_input : invalid_input_array) { - SpdyStringPiece input(invalid_input); - SpdyString host; - uint16_t port; - EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( - input.begin(), input.end(), &host, &port)) - << input; - } -} - -// Test ParseInteger() on valid input. -TEST(SpdyAltSvcWireFormatTest, ParseIntegerValid) { - SpdyStringPiece input("3"); - uint16_t value; - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( - input.begin(), input.end(), &value)); - EXPECT_EQ(3, value); - - input = SpdyStringPiece("1337"); - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( - input.begin(), input.end(), &value)); - EXPECT_EQ(1337, value); -} - -// Test ParseIntegerValid() on invalid input: empty, zero, non-numeric, trailing -// non-numeric characters. -TEST(SpdyAltSvcWireFormatTest, ParseIntegerInvalid) { - const char* invalid_input_array[] = {"", " ", "a", "0", "00", "1 ", "12b"}; - for (const char* invalid_input : invalid_input_array) { - SpdyStringPiece input(invalid_input); - uint16_t value; - EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( - input.begin(), input.end(), &value)) - << input; - } -} - -// Test ParseIntegerValid() around overflow limit. -TEST(SpdyAltSvcWireFormatTest, ParseIntegerOverflow) { - // Largest possible uint16_t value. - SpdyStringPiece input("65535"); - uint16_t value16; - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( - input.begin(), input.end(), &value16)); - EXPECT_EQ(65535, value16); - - // Overflow uint16_t, ParsePositiveInteger16() should return false. - input = SpdyStringPiece("65536"); - ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( - input.begin(), input.end(), &value16)); - - // However, even if overflow is not checked for, 65536 overflows to 0, which - // returns false anyway. Check for a larger number which overflows to 1. - input = SpdyStringPiece("65537"); - ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( - input.begin(), input.end(), &value16)); - - // Largest possible uint32_t value. - input = SpdyStringPiece("4294967295"); - uint32_t value32; - ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( - input.begin(), input.end(), &value32)); - EXPECT_EQ(4294967295, value32); - - // Overflow uint32_t, ParsePositiveInteger32() should return false. - input = SpdyStringPiece("4294967296"); - ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( - input.begin(), input.end(), &value32)); - - // However, even if overflow is not checked for, 4294967296 overflows to 0, - // which returns false anyway. Check for a larger number which overflows to - // 1. - input = SpdyStringPiece("4294967297"); - ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( - input.begin(), input.end(), &value32)); -} - -// Test parsing an Alt-Svc entry with IP literal hostname. -// Regression test for https://crbug.com/664173. -TEST(SpdyAltSvcWireFormatTest, ParseIPLiteral) { - const char* input = - "quic=\"[2003:8:0:16::509d:9615]:443\"; v=\"36,35\"; ma=60"; - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - ASSERT_TRUE( - SpdyAltSvcWireFormat::ParseHeaderFieldValue(input, &altsvc_vector)); - EXPECT_EQ(1u, altsvc_vector.size()); - EXPECT_EQ("quic", altsvc_vector[0].protocol_id); - EXPECT_EQ("[2003:8:0:16::509d:9615]", altsvc_vector[0].host); - EXPECT_EQ(443u, altsvc_vector[0].port); - EXPECT_EQ(60u, altsvc_vector[0].max_age); - EXPECT_THAT(altsvc_vector[0].version, ::testing::ElementsAre(36, 35)); -} - -} // namespace - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_bitmasks.h b/net/third_party/spdy/core/spdy_bitmasks.h deleted file mode 100644 index fbda2cd..0000000 --- a/net/third_party/spdy/core/spdy_bitmasks.h +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_BITMASKS_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_BITMASKS_H_ - -namespace spdy { - -// StreamId mask from the SpdyHeader -const unsigned int kStreamIdMask = 0x7fffffff; - -// Mask the lower 24 bits. -const unsigned int kLengthMask = 0xffffff; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_BITMASKS_H_
diff --git a/net/third_party/spdy/core/spdy_deframer_visitor.cc b/net/third_party/spdy/core/spdy_deframer_visitor.cc deleted file mode 100644 index d048003..0000000 --- a/net/third_party/spdy/core/spdy_deframer_visitor.cc +++ /dev/null
@@ -1,1028 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_deframer_visitor.h" - -#include <stdlib.h> - -#include <algorithm> -#include <cstdint> -#include <limits> -#include <memory> - -#include "base/logging.h" -#include "net/third_party/quiche/src/http2/platform/api/http2_macros.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/mock_spdy_framer_visitor.h" -#include "net/third_party/spdy/core/spdy_frame_reader.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" -#include "net/third_party/spdy/platform/api/spdy_flags.h" -#include "net/third_party/spdy/platform/api/spdy_ptr_util.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" -#include "testing/gmock/include/gmock/gmock.h" - -using ::testing::AssertionFailure; -using ::testing::AssertionResult; -using ::testing::AssertionSuccess; - -namespace spdy { -namespace test { - -// Specify whether to process headers as request or response in visitor-related -// params. -enum class HeaderDirection { REQUEST, RESPONSE }; - -// Types of HTTP/2 frames, per RFC 7540. -// TODO(jamessynge): Switch to using http2/http2_constants.h when ready. -enum Http2FrameType { - DATA = 0, - HEADERS = 1, - PRIORITY = 2, - RST_STREAM = 3, - SETTINGS = 4, - PUSH_PROMISE = 5, - PING = 6, - GOAWAY = 7, - WINDOW_UPDATE = 8, - CONTINUATION = 9, - ALTSVC = 10, - - // Not a frame type. - UNSET = -1, - UNKNOWN = -2, -}; - -// TODO(jamessynge): Switch to using http2/http2_constants.h when ready. -const char* Http2FrameTypeToString(Http2FrameType v) { - switch (v) { - case DATA: - return "DATA"; - case HEADERS: - return "HEADERS"; - case PRIORITY: - return "PRIORITY"; - case RST_STREAM: - return "RST_STREAM"; - case SETTINGS: - return "SETTINGS"; - case PUSH_PROMISE: - return "PUSH_PROMISE"; - case PING: - return "PING"; - case GOAWAY: - return "GOAWAY"; - case WINDOW_UPDATE: - return "WINDOW_UPDATE"; - case CONTINUATION: - return "CONTINUATION"; - case ALTSVC: - return "ALTSVC"; - case UNSET: - return "UNSET"; - case UNKNOWN: - return "UNKNOWN"; - default: - return "Invalid Http2FrameType"; - } -} - -// TODO(jamessynge): Switch to using http2/http2_constants.h when ready. -inline std::ostream& operator<<(std::ostream& out, Http2FrameType v) { - return out << Http2FrameTypeToString(v); -} - -// Flag bits in the flag field of the common header of HTTP/2 frames -// (see https://httpwg.github.io/specs/rfc7540.html#FrameHeader for details on -// the fixed 9-octet header structure shared by all frames). -// Flag bits are only valid for specified frame types. -// TODO(jamessynge): Switch to using http2/http2_constants.h when ready. -enum Http2HeaderFlag { - NO_FLAGS = 0, - - END_STREAM_FLAG = 0x1, - ACK_FLAG = 0x1, - END_HEADERS_FLAG = 0x4, - PADDED_FLAG = 0x8, - PRIORITY_FLAG = 0x20, -}; - -// Returns name of frame type. -// TODO(jamessynge): Switch to using http2/http2_constants.h when ready. -const char* Http2FrameTypeToString(Http2FrameType v); - -void SpdyDeframerVisitorInterface::OnPingAck( - std::unique_ptr<SpdyPingIR> frame) { - OnPing(std::move(frame)); -} - -void SpdyDeframerVisitorInterface::OnSettingsAck( - std::unique_ptr<SpdySettingsIR> frame) { - OnSettings(std::move(frame), nullptr); -} - -class SpdyTestDeframerImpl : public SpdyTestDeframer, - public SpdyHeadersHandlerInterface { - public: - explicit SpdyTestDeframerImpl( - std::unique_ptr<SpdyDeframerVisitorInterface> listener) - : listener_(std::move(listener)) { - CHECK(listener_ != nullptr); - } - SpdyTestDeframerImpl(const SpdyTestDeframerImpl&) = delete; - SpdyTestDeframerImpl& operator=(const SpdyTestDeframerImpl&) = delete; - ~SpdyTestDeframerImpl() override = default; - - bool AtFrameEnd() override; - - // Callbacks defined in SpdyFramerVisitorInterface. These are in the - // alphabetical order for ease of navigation, and are not in same order - // as in SpdyFramerVisitorInterface. - void OnAltSvc(SpdyStreamId stream_id, - SpdyStringPiece origin, - const SpdyAltSvcWireFormat::AlternativeServiceVector& - altsvc_vector) override; - void OnContinuation(SpdyStreamId stream_id, bool end) override; - SpdyHeadersHandlerInterface* OnHeaderFrameStart( - SpdyStreamId stream_id) override; - void OnHeaderFrameEnd(SpdyStreamId stream_id) override; - void OnDataFrameHeader(SpdyStreamId stream_id, - size_t length, - bool fin) override; - void OnError(http2::Http2DecoderAdapter::SpdyFramerError error) override; - void OnGoAway(SpdyStreamId last_accepted_stream_id, - SpdyErrorCode error_code) override; - bool OnGoAwayFrameData(const char* goaway_data, size_t len) override; - void OnHeaders(SpdyStreamId stream_id, - bool has_priority, - int weight, - SpdyStreamId parent_stream_id, - bool exclusive, - bool fin, - bool end) override; - void OnPing(SpdyPingId unique_id, bool is_ack) override; - void OnPriority(SpdyStreamId stream_id, - SpdyStreamId parent_stream_id, - int weight, - bool exclusive) override; - void OnPushPromise(SpdyStreamId stream_id, - SpdyStreamId promised_stream_id, - bool end) override; - void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override; - void OnSetting(SpdySettingsId id, uint32_t value) override; - void OnSettings() override; - void OnSettingsAck() override; - void OnSettingsEnd() override; - void OnStreamFrameData(SpdyStreamId stream_id, - const char* data, - size_t len) override; - void OnStreamEnd(SpdyStreamId stream_id) override; - void OnStreamPadLength(SpdyStreamId stream_id, size_t value) override; - void OnStreamPadding(SpdyStreamId stream_id, size_t len) override; - bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override; - void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override; - - // Callbacks defined in SpdyHeadersHandlerInterface. - - void OnHeaderBlockStart() override; - void OnHeader(SpdyStringPiece key, SpdyStringPiece value) override; - void OnHeaderBlockEnd(size_t header_bytes_parsed, - size_t compressed_header_bytes_parsed) override; - - protected: - void AtDataEnd(); - void AtGoAwayEnd(); - void AtHeadersEnd(); - void AtPushPromiseEnd(); - - // Per-physical frame state. - // Frame type of the frame currently being processed. - Http2FrameType frame_type_ = UNSET; - // Stream id of the frame currently being processed. - SpdyStreamId stream_id_; - // Did the most recent frame header include the END_HEADERS flag? - bool end_ = false; - // Did the most recent frame header include the ack flag? - bool ack_ = false; - - // Per-HPACK block state. Only valid while processing a HEADERS or - // PUSH_PROMISE frame, and its CONTINUATION frames. - // Did the most recent HEADERS or PUSH_PROMISE include the END_STREAM flag? - // Note that this does not necessarily indicate that the current frame is - // the last frame for the stream (may be followed by CONTINUATION frames, - // may only half close). - bool fin_ = false; - bool got_hpack_end_ = false; - - std::unique_ptr<SpdyString> data_; - - // Total length of the data frame. - size_t data_len_ = 0; - - // Amount of skipped padding (i.e. total length of padding, including Pad - // Length field). - size_t padding_len_ = 0; - - std::unique_ptr<SpdyString> goaway_description_; - std::unique_ptr<StringPairVector> headers_; - std::unique_ptr<SettingVector> settings_; - std::unique_ptr<TestHeadersHandler> headers_handler_; - - std::unique_ptr<SpdyGoAwayIR> goaway_ir_; - std::unique_ptr<SpdyHeadersIR> headers_ir_; - std::unique_ptr<SpdyPushPromiseIR> push_promise_ir_; - std::unique_ptr<SpdySettingsIR> settings_ir_; - - private: - std::unique_ptr<SpdyDeframerVisitorInterface> listener_; -}; - -// static -std::unique_ptr<SpdyTestDeframer> SpdyTestDeframer::CreateConverter( - std::unique_ptr<SpdyDeframerVisitorInterface> listener) { - return SpdyMakeUnique<SpdyTestDeframerImpl>(std::move(listener)); -} - -void SpdyTestDeframerImpl::AtDataEnd() { - DVLOG(1) << "AtDataEnd"; - CHECK_EQ(data_len_, padding_len_ + data_->size()); - auto ptr = SpdyMakeUnique<SpdyDataIR>(stream_id_, std::move(*data_)); - CHECK_EQ(0u, data_->size()); - data_.reset(); - - CHECK_LE(0u, padding_len_); - CHECK_LE(padding_len_, 256u); - if (padding_len_ > 0) { - ptr->set_padding_len(padding_len_); - } - padding_len_ = 0; - - ptr->set_fin(fin_); - listener_->OnData(std::move(ptr)); - frame_type_ = UNSET; - fin_ = false; - data_len_ = 0; -} - -void SpdyTestDeframerImpl::AtGoAwayEnd() { - DVLOG(1) << "AtDataEnd"; - CHECK_EQ(frame_type_, GOAWAY); - if (HTTP2_DIE_IF_NULL(goaway_description_)->empty()) { - listener_->OnGoAway(std::move(goaway_ir_)); - } else { - listener_->OnGoAway(SpdyMakeUnique<SpdyGoAwayIR>( - goaway_ir_->last_good_stream_id(), goaway_ir_->error_code(), - std::move(*goaway_description_))); - CHECK_EQ(0u, goaway_description_->size()); - } - goaway_description_.reset(); - goaway_ir_.reset(); - frame_type_ = UNSET; -} - -void SpdyTestDeframerImpl::AtHeadersEnd() { - DVLOG(1) << "AtDataEnd"; - CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(end_) << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(got_hpack_end_); - - CHECK(headers_ir_ != nullptr); - CHECK(headers_ != nullptr); - CHECK(headers_handler_ != nullptr); - - CHECK_LE(0u, padding_len_); - CHECK_LE(padding_len_, 256u); - if (padding_len_ > 0) { - headers_ir_->set_padding_len(padding_len_); - } - padding_len_ = 0; - - headers_ir_->set_header_block(headers_handler_->decoded_block().Clone()); - headers_handler_.reset(); - listener_->OnHeaders(std::move(headers_ir_), std::move(headers_)); - - frame_type_ = UNSET; - fin_ = false; - end_ = false; - got_hpack_end_ = false; -} - -void SpdyTestDeframerImpl::AtPushPromiseEnd() { - DVLOG(1) << "AtDataEnd"; - CHECK(frame_type_ == PUSH_PROMISE || frame_type_ == CONTINUATION) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(end_) << " frame_type_=" << Http2FrameTypeToString(frame_type_); - - CHECK(push_promise_ir_ != nullptr); - CHECK(headers_ != nullptr); - CHECK(headers_handler_ != nullptr); - - CHECK_EQ(headers_ir_.get(), nullptr); - - CHECK_LE(0u, padding_len_); - CHECK_LE(padding_len_, 256u); - if (padding_len_ > 0) { - push_promise_ir_->set_padding_len(padding_len_); - } - padding_len_ = 0; - - push_promise_ir_->set_header_block(headers_handler_->decoded_block().Clone()); - headers_handler_.reset(); - listener_->OnPushPromise(std::move(push_promise_ir_), std::move(headers_)); - - frame_type_ = UNSET; - end_ = false; -} - -bool SpdyTestDeframerImpl::AtFrameEnd() { - bool incomplete_logical_header = false; - // The caller says that the SpdyFrame has reached the end of the frame, - // so if we have any accumulated data, flush it. - switch (frame_type_) { - case DATA: - AtDataEnd(); - break; - - case GOAWAY: - AtGoAwayEnd(); - break; - - case HEADERS: - if (end_) { - AtHeadersEnd(); - } else { - incomplete_logical_header = true; - } - break; - - case PUSH_PROMISE: - if (end_) { - AtPushPromiseEnd(); - } else { - incomplete_logical_header = true; - } - break; - - case CONTINUATION: - if (end_) { - if (headers_ir_) { - AtHeadersEnd(); - } else if (push_promise_ir_) { - AtPushPromiseEnd(); - } else { - LOG(FATAL) << "Where is the SpdyFrameIR for the headers!"; - } - } else { - incomplete_logical_header = true; - } - break; - - case UNSET: - // Except for the frame types above, the others don't leave any record - // in the state of this object. Make sure nothing got left by accident. - CHECK_EQ(data_.get(), nullptr); - CHECK_EQ(goaway_description_.get(), nullptr); - CHECK_EQ(goaway_ir_.get(), nullptr); - CHECK_EQ(headers_.get(), nullptr); - CHECK_EQ(headers_handler_.get(), nullptr); - CHECK_EQ(headers_ir_.get(), nullptr); - CHECK_EQ(push_promise_ir_.get(), nullptr); - CHECK_EQ(settings_.get(), nullptr); - CHECK_EQ(settings_ir_.get(), nullptr); - break; - - default: - SPDY_BUG << "Expected UNSET, instead frame_type_==" << frame_type_; - return false; - } - frame_type_ = UNSET; - stream_id_ = 0; - end_ = false; - ack_ = false; - if (!incomplete_logical_header) { - fin_ = false; - } - return true; -} - -// Overridden methods from SpdyFramerVisitorInterface in alpha order... - -void SpdyTestDeframerImpl::OnAltSvc( - SpdyStreamId stream_id, - SpdyStringPiece origin, - const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) { - DVLOG(1) << "OnAltSvc stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - auto ptr = SpdyMakeUnique<SpdyAltSvcIR>(stream_id); - ptr->set_origin(SpdyString(origin)); - for (auto& altsvc : altsvc_vector) { - ptr->add_altsvc(altsvc); - } - listener_->OnAltSvc(std::move(ptr)); -} - -// A CONTINUATION frame contains a Header Block Fragment, and immediately -// follows another frame that contains a Header Block Fragment (HEADERS, -// PUSH_PROMISE or CONTINUATION). The last such frame has the END flag set. -// SpdyFramer ensures that the behavior is correct before calling the visitor. -void SpdyTestDeframerImpl::OnContinuation(SpdyStreamId stream_id, bool end) { - DVLOG(1) << "OnContinuation stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - CHECK_NE(nullptr, headers_.get()); - frame_type_ = CONTINUATION; - - stream_id_ = stream_id; - end_ = end; -} - -// Note that length includes the padding length (0 to 256, when the optional -// padding length field is counted). Padding comes after the payload, both -// for DATA frames and for control frames. -void SpdyTestDeframerImpl::OnDataFrameHeader(SpdyStreamId stream_id, - size_t length, - bool fin) { - DVLOG(1) << "OnDataFrameHeader stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - CHECK_EQ(data_.get(), nullptr); - frame_type_ = DATA; - - stream_id_ = stream_id; - fin_ = fin; - data_len_ = length; - data_ = SpdyMakeUnique<SpdyString>(); -} - -// The SpdyFramer will not process any more data at this point. -void SpdyTestDeframerImpl::OnError( - http2::Http2DecoderAdapter::SpdyFramerError error) { - DVLOG(1) << "SpdyFramer detected an error in the stream: " - << http2::Http2DecoderAdapter::SpdyFramerErrorToString(error) - << " frame_type_: " << Http2FrameTypeToString(frame_type_); - listener_->OnError(error, this); -} - -// Received a GOAWAY frame from the peer. The last stream id it accepted from us -// is |last_accepted_stream_id|. |status| is a protocol defined error code. -// The frame may also contain data. After this OnGoAwayFrameData will be called -// for any non-zero amount of data, and after that it will be called with len==0 -// to indicate the end of the GOAWAY frame. -void SpdyTestDeframerImpl::OnGoAway(SpdyStreamId last_good_stream_id, - SpdyErrorCode error_code) { - DVLOG(1) << "OnGoAway last_good_stream_id: " << last_good_stream_id - << " error code: " << error_code; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - frame_type_ = GOAWAY; - goaway_ir_ = - SpdyMakeUnique<SpdyGoAwayIR>(last_good_stream_id, error_code, ""); - goaway_description_ = SpdyMakeUnique<SpdyString>(); -} - -// If len==0 then we've reached the end of the GOAWAY frame. -bool SpdyTestDeframerImpl::OnGoAwayFrameData(const char* goaway_data, - size_t len) { - DVLOG(1) << "OnGoAwayFrameData"; - CHECK_EQ(frame_type_, GOAWAY) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(goaway_description_ != nullptr); - goaway_description_->append(goaway_data, len); - return true; -} - -SpdyHeadersHandlerInterface* SpdyTestDeframerImpl::OnHeaderFrameStart( - SpdyStreamId stream_id) { - return this; -} - -void SpdyTestDeframerImpl::OnHeaderFrameEnd(SpdyStreamId stream_id) { - DVLOG(1) << "OnHeaderFrameEnd stream_id: " << stream_id; -} - -// Received the fixed portion of a HEADERS frame. Called before the variable -// length (including zero length) Header Block Fragment is processed. If fin -// is true then there will be no DATA or trailing HEADERS after this HEADERS -// frame. -// If end is true, then there will be no CONTINUATION frame(s) following this -// frame; else if true then there will be CONTINATION frames(s) immediately -// following this frame, terminated by a CONTINUATION frame with end==true. -void SpdyTestDeframerImpl::OnHeaders(SpdyStreamId stream_id, - bool has_priority, - int weight, - SpdyStreamId parent_stream_id, - bool exclusive, - bool fin, - bool end) { - DVLOG(1) << "OnHeaders stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - frame_type_ = HEADERS; - - stream_id_ = stream_id; - fin_ = fin; - end_ = end; - - headers_ = SpdyMakeUnique<StringPairVector>(); - headers_handler_ = SpdyMakeUnique<TestHeadersHandler>(); - headers_ir_ = SpdyMakeUnique<SpdyHeadersIR>(stream_id); - headers_ir_->set_fin(fin); - if (has_priority) { - headers_ir_->set_has_priority(true); - headers_ir_->set_weight(weight); - headers_ir_->set_parent_stream_id(parent_stream_id); - headers_ir_->set_exclusive(exclusive); - } -} - -// The HTTP/2 protocol refers to the payload, |unique_id| here, as 8 octets of -// opaque data that is to be echoed back to the sender, with the ACK bit added. -// It isn't defined as a counter, -// or frame id, as the SpdyPingId naming might imply. -// Responding to a PING is supposed to be at the highest priority. -void SpdyTestDeframerImpl::OnPing(uint64_t unique_id, bool is_ack) { - DVLOG(1) << "OnPing unique_id: " << unique_id - << " is_ack: " << (is_ack ? "true" : "false"); - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - auto ptr = SpdyMakeUnique<SpdyPingIR>(unique_id); - if (is_ack) { - ptr->set_is_ack(is_ack); - listener_->OnPingAck(std::move(ptr)); - } else { - listener_->OnPing(std::move(ptr)); - } -} - -void SpdyTestDeframerImpl::OnPriority(SpdyStreamId stream_id, - SpdyStreamId parent_stream_id, - int weight, - bool exclusive) { - DVLOG(1) << "OnPriority stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - - listener_->OnPriority(SpdyMakeUnique<SpdyPriorityIR>( - stream_id, parent_stream_id, weight, exclusive)); -} - -void SpdyTestDeframerImpl::OnPushPromise(SpdyStreamId stream_id, - SpdyStreamId promised_stream_id, - bool end) { - DVLOG(1) << "OnPushPromise stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - - frame_type_ = PUSH_PROMISE; - stream_id_ = stream_id; - end_ = end; - - headers_ = SpdyMakeUnique<StringPairVector>(); - headers_handler_ = SpdyMakeUnique<TestHeadersHandler>(); - push_promise_ir_ = - SpdyMakeUnique<SpdyPushPromiseIR>(stream_id, promised_stream_id); -} - -// Closes the specified stream. After this the sender may still send PRIORITY -// frames for this stream, which we can ignore. -void SpdyTestDeframerImpl::OnRstStream(SpdyStreamId stream_id, - SpdyErrorCode error_code) { - DVLOG(1) << "OnRstStream stream_id: " << stream_id - << " error code: " << error_code; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_GT(stream_id, 0u); - - listener_->OnRstStream( - SpdyMakeUnique<SpdyRstStreamIR>(stream_id, error_code)); -} - -// Called for an individual setting. There is no negotiation; the sender is -// stating the value that the sender is using. -void SpdyTestDeframerImpl::OnSetting(SpdySettingsId id, uint32_t value) { - DVLOG(1) << "OnSetting id: " << id << std::hex << " value: " << value; - CHECK_EQ(frame_type_, SETTINGS) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(settings_ != nullptr); - SpdyKnownSettingsId known_id; - if (ParseSettingsId(id, &known_id)) { - settings_->push_back(std::make_pair(known_id, value)); - settings_ir_->AddSetting(known_id, value); - } -} - -// Called at the start of a SETTINGS frame with setting entries, but not the -// (required) ACK of a SETTINGS frame. There is no stream_id because -// the settings apply to the entire connection, not to an individual stream. -void SpdyTestDeframerImpl::OnSettings() { - DVLOG(1) << "OnSettings"; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_EQ(nullptr, settings_ir_.get()); - CHECK_EQ(nullptr, settings_.get()); - frame_type_ = SETTINGS; - ack_ = false; - - settings_ = SpdyMakeUnique<SettingVector>(); - settings_ir_ = SpdyMakeUnique<SpdySettingsIR>(); -} - -void SpdyTestDeframerImpl::OnSettingsAck() { - DVLOG(1) << "OnSettingsAck"; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - auto ptr = SpdyMakeUnique<SpdySettingsIR>(); - ptr->set_is_ack(true); - listener_->OnSettingsAck(std::move(ptr)); -} - -void SpdyTestDeframerImpl::OnSettingsEnd() { - DVLOG(1) << "OnSettingsEnd"; - CHECK_EQ(frame_type_, SETTINGS) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(!ack_); - CHECK_NE(nullptr, settings_ir_.get()); - CHECK_NE(nullptr, settings_.get()); - listener_->OnSettings(std::move(settings_ir_), std::move(settings_)); - frame_type_ = UNSET; -} - -// Called for a zero length DATA frame with the END_STREAM flag set, or at the -// end a complete HPACK block (and its padding) that started with a HEADERS -// frame with the END_STREAM flag set. Doesn't apply to PUSH_PROMISE frames -// because they don't have END_STREAM flags. -void SpdyTestDeframerImpl::OnStreamEnd(SpdyStreamId stream_id) { - DVLOG(1) << "OnStreamEnd stream_id: " << stream_id; - CHECK_EQ(stream_id_, stream_id); - CHECK(frame_type_ == DATA || frame_type_ == HEADERS || - frame_type_ == CONTINUATION) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(fin_); -} - -// The data arg points into the non-padding payload of a DATA frame. -// This must be a DATA frame (i.e. this method will not be -// called for HEADERS or CONTINUATION frames). -// This method may be called multiple times for a single DATA frame, depending -// upon buffer boundaries. -void SpdyTestDeframerImpl::OnStreamFrameData(SpdyStreamId stream_id, - const char* data, - size_t len) { - DVLOG(1) << "OnStreamFrameData stream_id: " << stream_id - << " len: " << len; - CHECK_EQ(stream_id_, stream_id); - CHECK_EQ(frame_type_, DATA); - data_->append(data, len); -} - -// Called when receiving the padding length field at the start of the DATA frame -// payload. value will be in the range 0 to 255. -void SpdyTestDeframerImpl::OnStreamPadLength(SpdyStreamId stream_id, - size_t value) { - DVLOG(1) << "OnStreamPadding stream_id: " << stream_id - << " value: " << value; - CHECK(frame_type_ == DATA || frame_type_ == HEADERS || - frame_type_ == PUSH_PROMISE) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_EQ(stream_id_, stream_id); - CHECK_GE(255u, value); - // Count the padding length byte against total padding. - padding_len_ += 1; - CHECK_EQ(1u, padding_len_); -} - -// Called when padding is skipped over at the end of the DATA frame. len will -// be in the range 1 to 255. -void SpdyTestDeframerImpl::OnStreamPadding(SpdyStreamId stream_id, size_t len) { - DVLOG(1) << "OnStreamPadding stream_id: " << stream_id << " len: " << len; - CHECK(frame_type_ == DATA || frame_type_ == HEADERS || - frame_type_ == PUSH_PROMISE) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_EQ(stream_id_, stream_id); - CHECK_LE(1u, len); - CHECK_GE(255u, len); - padding_len_ += len; - CHECK_LE(padding_len_, 256u) << "len=" << len; -} - -// WINDOW_UPDATE is supposed to be hop-by-hop, according to the spec. -// stream_id is 0 if the update applies to the connection, else stream_id -// will be the id of a stream previously seen, which maybe half or fully -// closed. -void SpdyTestDeframerImpl::OnWindowUpdate(SpdyStreamId stream_id, - int delta_window_size) { - DVLOG(1) << "OnWindowUpdate stream_id: " << stream_id - << " delta_window_size: " << delta_window_size; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK_NE(0, delta_window_size); - - listener_->OnWindowUpdate( - SpdyMakeUnique<SpdyWindowUpdateIR>(stream_id, delta_window_size)); -} - -// Return true to indicate that the stream_id is valid; if not valid then -// SpdyFramer considers the connection corrupted. Requires keeping track -// of the set of currently open streams. For now we'll assume that unknown -// frame types are unsupported. -bool SpdyTestDeframerImpl::OnUnknownFrame(SpdyStreamId stream_id, - uint8_t frame_type) { - DVLOG(1) << "OnAltSvc stream_id: " << stream_id; - CHECK_EQ(frame_type_, UNSET) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - frame_type_ = UNKNOWN; - - stream_id_ = stream_id; - return false; -} - -// Callbacks defined in SpdyHeadersHandlerInterface. - -void SpdyTestDeframerImpl::OnHeaderBlockStart() { - CHECK(frame_type_ == HEADERS || frame_type_ == PUSH_PROMISE) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(headers_ != nullptr); - CHECK_EQ(0u, headers_->size()); - got_hpack_end_ = false; -} - -void SpdyTestDeframerImpl::OnHeader(SpdyStringPiece key, - SpdyStringPiece value) { - CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION || - frame_type_ == PUSH_PROMISE) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(!got_hpack_end_); - HTTP2_DIE_IF_NULL(headers_)->emplace_back(SpdyString(key), SpdyString(value)); - HTTP2_DIE_IF_NULL(headers_handler_)->OnHeader(key, value); -} - -void SpdyTestDeframerImpl::OnHeaderBlockEnd( - size_t /* header_bytes_parsed */, - size_t /* compressed_header_bytes_parsed */) { - CHECK(headers_ != nullptr); - CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION || - frame_type_ == PUSH_PROMISE) - << " frame_type_=" << Http2FrameTypeToString(frame_type_); - CHECK(end_); - CHECK(!got_hpack_end_); - got_hpack_end_ = true; -} - -class LoggingSpdyDeframerDelegate : public SpdyDeframerVisitorInterface { - public: - explicit LoggingSpdyDeframerDelegate( - std::unique_ptr<SpdyDeframerVisitorInterface> wrapped) - : wrapped_(std::move(wrapped)) { - if (!wrapped_) { - wrapped_ = SpdyMakeUnique<SpdyDeframerVisitorInterface>(); - } - } - ~LoggingSpdyDeframerDelegate() override = default; - - void OnAltSvc(std::unique_ptr<SpdyAltSvcIR> frame) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnAltSvc"; - wrapped_->OnAltSvc(std::move(frame)); - } - void OnData(std::unique_ptr<SpdyDataIR> frame) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnData"; - wrapped_->OnData(std::move(frame)); - } - void OnGoAway(std::unique_ptr<SpdyGoAwayIR> frame) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnGoAway"; - wrapped_->OnGoAway(std::move(frame)); - } - - // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which - // significantly modifies the headers, so the actual header entries (name - // and value strings) are provided in a vector. - void OnHeaders(std::unique_ptr<SpdyHeadersIR> frame, - std::unique_ptr<StringPairVector> headers) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnHeaders"; - wrapped_->OnHeaders(std::move(frame), std::move(headers)); - } - - void OnPing(std::unique_ptr<SpdyPingIR> frame) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPing"; - wrapped_->OnPing(std::move(frame)); - } - void OnPingAck(std::unique_ptr<SpdyPingIR> frame) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPingAck"; - wrapped_->OnPingAck(std::move(frame)); - } - - void OnPriority(std::unique_ptr<SpdyPriorityIR> frame) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPriority"; - wrapped_->OnPriority(std::move(frame)); - } - - // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which - // significantly modifies the headers, so the actual header entries (name - // and value strings) are provided in a vector. - void OnPushPromise(std::unique_ptr<SpdyPushPromiseIR> frame, - std::unique_ptr<StringPairVector> headers) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPushPromise"; - wrapped_->OnPushPromise(std::move(frame), std::move(headers)); - } - - void OnRstStream(std::unique_ptr<SpdyRstStreamIR> frame) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnRstStream"; - wrapped_->OnRstStream(std::move(frame)); - } - - // SpdySettingsIR has a map for settings, so loses info about the order of - // settings, and whether the same setting appeared more than once, so the - // the actual settings (parameter and value) are provided in a vector. - void OnSettings(std::unique_ptr<SpdySettingsIR> frame, - std::unique_ptr<SettingVector> settings) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnSettings"; - wrapped_->OnSettings(std::move(frame), std::move(settings)); - } - - // A settings frame with an ACK has no content, but for uniformity passing - // a frame with the ACK flag set. - void OnSettingsAck(std::unique_ptr<SpdySettingsIR> frame) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnSettingsAck"; - wrapped_->OnSettingsAck(std::move(frame)); - } - - void OnWindowUpdate(std::unique_ptr<SpdyWindowUpdateIR> frame) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnWindowUpdate"; - wrapped_->OnWindowUpdate(std::move(frame)); - } - - // The SpdyFramer will not process any more data at this point. - void OnError(http2::Http2DecoderAdapter::SpdyFramerError error, - SpdyTestDeframer* deframer) override { - DVLOG(1) << "LoggingSpdyDeframerDelegate::OnError"; - wrapped_->OnError(error, deframer); - } - - private: - std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_; -}; - -// static -std::unique_ptr<SpdyDeframerVisitorInterface> -SpdyDeframerVisitorInterface::LogBeforeVisiting( - std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_listener) { - return SpdyMakeUnique<LoggingSpdyDeframerDelegate>( - std::move(wrapped_listener)); -} - -CollectedFrame::CollectedFrame() = default; - -CollectedFrame::CollectedFrame(CollectedFrame&& other) - : frame_ir(std::move(other.frame_ir)), - headers(std::move(other.headers)), - settings(std::move(other.settings)), - error_reported(other.error_reported) {} - -CollectedFrame::~CollectedFrame() = default; - -CollectedFrame& CollectedFrame::operator=(CollectedFrame&& other) { - frame_ir = std::move(other.frame_ir); - headers = std::move(other.headers); - settings = std::move(other.settings); - error_reported = other.error_reported; - return *this; -} - -AssertionResult CollectedFrame::VerifyHasHeaders( - const StringPairVector& expected_headers) const { - VERIFY_NE(headers.get(), nullptr); - VERIFY_THAT(*headers, ::testing::ContainerEq(expected_headers)); - return AssertionSuccess(); -} - -AssertionResult CollectedFrame::VerifyHasSettings( - const SettingVector& expected_settings) const { - VERIFY_NE(settings.get(), nullptr); - VERIFY_THAT(*settings, testing::ContainerEq(expected_settings)); - return AssertionSuccess(); -} - -DeframerCallbackCollector::DeframerCallbackCollector( - std::vector<CollectedFrame>* collected_frames) - : collected_frames_(HTTP2_DIE_IF_NULL(collected_frames)) {} - -void DeframerCallbackCollector::OnAltSvc( - std::unique_ptr<SpdyAltSvcIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} -void DeframerCallbackCollector::OnData(std::unique_ptr<SpdyDataIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} -void DeframerCallbackCollector::OnGoAway( - std::unique_ptr<SpdyGoAwayIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -// SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which -// significantly modifies the headers, so the actual header entries (name -// and value strings) are provided in a vector. -void DeframerCallbackCollector::OnHeaders( - std::unique_ptr<SpdyHeadersIR> frame_ir, - std::unique_ptr<StringPairVector> headers) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - cf.headers = std::move(headers); - collected_frames_->push_back(std::move(cf)); -} - -void DeframerCallbackCollector::OnPing(std::unique_ptr<SpdyPingIR> frame_ir) { - EXPECT_TRUE(frame_ir && !frame_ir->is_ack()); - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -void DeframerCallbackCollector::OnPingAck( - std::unique_ptr<SpdyPingIR> frame_ir) { - EXPECT_TRUE(frame_ir && frame_ir->is_ack()); - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -void DeframerCallbackCollector::OnPriority( - std::unique_ptr<SpdyPriorityIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -// SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which -// significantly modifies the headers, so the actual header entries (name -// and value strings) are provided in a vector. -void DeframerCallbackCollector::OnPushPromise( - std::unique_ptr<SpdyPushPromiseIR> frame_ir, - std::unique_ptr<StringPairVector> headers) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - cf.headers = std::move(headers); - collected_frames_->push_back(std::move(cf)); -} - -void DeframerCallbackCollector::OnRstStream( - std::unique_ptr<SpdyRstStreamIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -// SpdySettingsIR has a map for settings, so loses info about the order of -// settings, and whether the same setting appeared more than once, so the -// the actual settings (parameter and value) are provided in a vector. -void DeframerCallbackCollector::OnSettings( - std::unique_ptr<SpdySettingsIR> frame_ir, - std::unique_ptr<SettingVector> settings) { - EXPECT_TRUE(frame_ir && !frame_ir->is_ack()); - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - cf.settings = std::move(settings); - collected_frames_->push_back(std::move(cf)); -} - -// A settings frame_ir with an ACK has no content, but for uniformity passing -// a frame_ir with the ACK flag set. -void DeframerCallbackCollector::OnSettingsAck( - std::unique_ptr<SpdySettingsIR> frame_ir) { - EXPECT_TRUE(frame_ir && frame_ir->is_ack()); - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -void DeframerCallbackCollector::OnWindowUpdate( - std::unique_ptr<SpdyWindowUpdateIR> frame_ir) { - CollectedFrame cf; - cf.frame_ir = std::move(frame_ir); - collected_frames_->push_back(std::move(cf)); -} - -// The SpdyFramer will not process any more data at this point. -void DeframerCallbackCollector::OnError( - http2::Http2DecoderAdapter::SpdyFramerError error, - SpdyTestDeframer* deframer) { - CollectedFrame cf; - cf.error_reported = true; - collected_frames_->push_back(std::move(cf)); -} - -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_deframer_visitor.h b/net/third_party/spdy/core/spdy_deframer_visitor.h deleted file mode 100644 index 181c28f..0000000 --- a/net/third_party/spdy/core/spdy_deframer_visitor.h +++ /dev/null
@@ -1,250 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_DEFRAMER_VISITOR_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_DEFRAMER_VISITOR_H_ - -// Supports testing by converting callbacks to SpdyFramerVisitorInterface into -// callbacks to SpdyDeframerVisitorInterface, whose arguments are generally -// SpdyFrameIR instances. This enables a test client or test backend to operate -// at a level between the low-level callbacks of SpdyFramerVisitorInterface and -// the much higher level of entire messages (i.e. headers, body, trailers). -// Where possible the converter (SpdyTestDeframer) tries to preserve information -// that might be useful to tests (e.g. the order of headers or the amount of -// padding); the design also aims to allow tests to be concise, ideally -// supporting gMock style EXPECT_CALL(visitor, OnHeaders(...matchers...)) -// without too much boilerplate. -// -// Only supports HTTP/2 for the moment. -// -// Example of usage: -// -// SpdyFramer framer(HTTP2); -// -// // Need to call SpdyTestDeframer::AtFrameEnd() after processing each -// // frame, so tell SpdyFramer to stop after each. -// framer.set_process_single_input_frame(true); -// -// // Need the new OnHeader callbacks. -// framer.set_use_new_methods_for_test(true); -// -// // Create your visitor, a subclass of SpdyDeframerVisitorInterface. -// // For example, using DeframerCallbackCollector to collect frames: -// std::vector<CollectedFrame> collected_frames; -// auto your_visitor = SpdyMakeUnique<DeframerCallbackCollector>( -// &collected_frames); -// -// // Transfer ownership of your visitor to the converter, which ensures that -// // your visitor stays alive while the converter needs to call it. -// auto the_deframer = SpdyTestDeframer::CreateConverter( -// std::move(your_visitor)); -// -// // Tell the framer to notify SpdyTestDeframer of the decoded frame -// // details. -// framer.set_visitor(the_deframer.get()); -// -// // Process frames. -// SpdyStringPiece input = ... -// while (!input.empty() && !framer.HasError()) { -// size_t consumed = framer.ProcessInput(input.data(), input.size()); -// input.remove_prefix(consumed); -// if (framer.state() == SpdyFramer::SPDY_READY_FOR_FRAME) { -// the_deframer->AtFrameEnd(); -// } -// } -// -// // Make sure that the correct frames were received. For example: -// ASSERT_EQ(collected_frames.size(), 3); -// -// SpdyDataIR expected1(7 /*stream_id*/, "Data Payload"); -// expected1.set_padding_len(17); -// EXPECT_TRUE(collected_frames[0].VerifyEquals(expected1)); -// -// // Repeat for the other frames. -// -// Note that you could also seed the subclass of SpdyDeframerVisitorInterface -// with the expected frames, which it would pop-off the list as its expectations -// are met. - -#include <cstdint> - -#include <memory> -#include <type_traits> -#include <utility> -#include <vector> - -#include "base/logging.h" -#include "base/macros.h" -#include "net/third_party/spdy/core/http2_frame_decoder_adapter.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/spdy_protocol_test_utils.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { -namespace test { - -// Non-lossy representation of a SETTINGS frame payload. -typedef std::vector<std::pair<SpdyKnownSettingsId, uint32_t>> SettingVector; - -// StringPairVector is used to record information lost by SpdyHeaderBlock, in -// particular the order of each header entry, though it doesn't expose the -// inner details of the HPACK block, such as the type of encoding selected -// for each header entry, nor dynamic table size changes. -typedef std::pair<SpdyString, SpdyString> StringPair; -typedef std::vector<StringPair> StringPairVector; - -// Forward decl. -class SpdyTestDeframer; - -// Note that this only roughly captures the frames, as padding bytes are lost, -// continuation frames are combined with their leading HEADERS or PUSH_PROMISE, -// the details of the HPACK encoding are lost, leaving -// only the list of header entries (name and value strings). If really helpful, -// we could add a SpdyRawDeframerVisitorInterface that gets the HPACK bytes, -// and receives continuation frames. For more info we'd need to improve -// SpdyFramerVisitorInterface. -class SpdyDeframerVisitorInterface { - public: - virtual ~SpdyDeframerVisitorInterface() {} - - // Wrap a visitor in another SpdyDeframerVisitorInterface that will - // DVLOG each call, and will then forward the calls to the wrapped visitor - // (if provided; nullptr is OK). Takes ownership of the wrapped visitor. - static std::unique_ptr<SpdyDeframerVisitorInterface> LogBeforeVisiting( - std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_visitor); - - virtual void OnAltSvc(std::unique_ptr<SpdyAltSvcIR> frame) {} - virtual void OnData(std::unique_ptr<SpdyDataIR> frame) {} - virtual void OnGoAway(std::unique_ptr<SpdyGoAwayIR> frame) {} - - // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which - // significantly modifies the headers, so the actual header entries (name - // and value strings) are provided in a vector. - virtual void OnHeaders(std::unique_ptr<SpdyHeadersIR> frame, - std::unique_ptr<StringPairVector> headers) {} - - virtual void OnPing(std::unique_ptr<SpdyPingIR> frame) {} - virtual void OnPingAck(std::unique_ptr<SpdyPingIR> frame); - virtual void OnPriority(std::unique_ptr<SpdyPriorityIR> frame) {} - - // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which - // significantly modifies the headers, so the actual header entries (name - // and value strings) are provided in a vector. - virtual void OnPushPromise(std::unique_ptr<SpdyPushPromiseIR> frame, - std::unique_ptr<StringPairVector> headers) {} - - virtual void OnRstStream(std::unique_ptr<SpdyRstStreamIR> frame) {} - - // SpdySettingsIR has a map for settings, so loses info about the order of - // settings, and whether the same setting appeared more than once, so the - // the actual settings (parameter and value) are provided in a vector. - virtual void OnSettings(std::unique_ptr<SpdySettingsIR> frame, - std::unique_ptr<SettingVector> settings) {} - - // A settings frame with an ACK has no content, but for uniformity passing - // a frame with the ACK flag set. - virtual void OnSettingsAck(std::unique_ptr<SpdySettingsIR> frame); - - virtual void OnWindowUpdate(std::unique_ptr<SpdyWindowUpdateIR> frame) {} - - // The SpdyFramer will not process any more data at this point. - virtual void OnError(http2::Http2DecoderAdapter::SpdyFramerError error, - SpdyTestDeframer* deframer) {} -}; - -class SpdyTestDeframer : public SpdyFramerVisitorInterface { - public: - ~SpdyTestDeframer() override {} - - // Creates a SpdyFramerVisitorInterface that builds SpdyFrameIR concrete - // instances based on the callbacks it receives; when an entire frame is - // decoded/reconstructed it calls the passed in SpdyDeframerVisitorInterface. - // Transfers ownership of visitor to the new SpdyTestDeframer, which ensures - // that it continues to exist while the SpdyTestDeframer exists. - static std::unique_ptr<SpdyTestDeframer> CreateConverter( - std::unique_ptr<SpdyDeframerVisitorInterface> visitor); - - // Call to notify the deframer that the SpdyFramer has returned after reaching - // the end of decoding a frame. This is used to flush info about some frame - // types where we don't get a clear end signal; others are flushed (i.e. the - // appropriate call to the SpdyDeframerVisitorInterface method is invoked) - // as they're decoded by SpdyFramer and it calls the deframer. See the - // example in the comments at the top of this file. - virtual bool AtFrameEnd() = 0; - - protected: - SpdyTestDeframer() {} - SpdyTestDeframer(const SpdyTestDeframer&) = delete; - SpdyTestDeframer& operator=(const SpdyTestDeframer&) = delete; -}; - -// CollectedFrame holds the result of one call to SpdyDeframerVisitorInterface, -// as recorded by DeframerCallbackCollector. -struct CollectedFrame { - CollectedFrame(); - CollectedFrame(CollectedFrame&& other); - ~CollectedFrame(); - CollectedFrame& operator=(CollectedFrame&& other); - - // Compare a SpdyFrameIR sub-class instance, expected_ir, against the - // collected SpdyFrameIR. - template <class T, - typename X = - typename std::enable_if<std::is_base_of<SpdyFrameIR, T>::value>> - ::testing::AssertionResult VerifyHasFrame(const T& expected_ir) const { - return VerifySpdyFrameIREquals(expected_ir, frame_ir.get()); - } - - // Compare the collected headers against a StringPairVector. Ignores - // this->frame_ir. - ::testing::AssertionResult VerifyHasHeaders( - const StringPairVector& expected_headers) const; - - // Compare the collected settings (parameter and value pairs) against - // expected_settings. Ignores this->frame_ir. - ::testing::AssertionResult VerifyHasSettings( - const SettingVector& expected_settings) const; - - std::unique_ptr<SpdyFrameIR> frame_ir; - std::unique_ptr<StringPairVector> headers; - std::unique_ptr<SettingVector> settings; - bool error_reported = false; -}; - -// Creates a CollectedFrame instance for each callback, storing it in the -// vector provided to the constructor. -class DeframerCallbackCollector : public SpdyDeframerVisitorInterface { - public: - explicit DeframerCallbackCollector( - std::vector<CollectedFrame>* collected_frames); - ~DeframerCallbackCollector() override {} - - void OnAltSvc(std::unique_ptr<SpdyAltSvcIR> frame_ir) override; - void OnData(std::unique_ptr<SpdyDataIR> frame_ir) override; - void OnGoAway(std::unique_ptr<SpdyGoAwayIR> frame_ir) override; - void OnHeaders(std::unique_ptr<SpdyHeadersIR> frame_ir, - std::unique_ptr<StringPairVector> headers) override; - void OnPing(std::unique_ptr<SpdyPingIR> frame_ir) override; - void OnPingAck(std::unique_ptr<SpdyPingIR> frame_ir) override; - void OnPriority(std::unique_ptr<SpdyPriorityIR> frame_ir) override; - void OnPushPromise(std::unique_ptr<SpdyPushPromiseIR> frame_ir, - std::unique_ptr<StringPairVector> headers) override; - void OnRstStream(std::unique_ptr<SpdyRstStreamIR> frame_ir) override; - void OnSettings(std::unique_ptr<SpdySettingsIR> frame_ir, - std::unique_ptr<SettingVector> settings) override; - void OnSettingsAck(std::unique_ptr<SpdySettingsIR> frame_ir) override; - void OnWindowUpdate(std::unique_ptr<SpdyWindowUpdateIR> frame_ir) override; - void OnError(http2::Http2DecoderAdapter::SpdyFramerError error, - SpdyTestDeframer* deframer) override; - - private: - std::vector<CollectedFrame>* collected_frames_; -}; - -} // namespace test -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_DEFRAMER_VISITOR_H_
diff --git a/net/third_party/spdy/core/spdy_deframer_visitor_test.cc b/net/third_party/spdy/core/spdy_deframer_visitor_test.cc deleted file mode 100644 index c2496c2..0000000 --- a/net/third_party/spdy/core/spdy_deframer_visitor_test.cc +++ /dev/null
@@ -1,247 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_deframer_visitor.h" - -#include <stdlib.h> - -#include <algorithm> -#include <limits> - -#include "base/logging.h" -#include "net/third_party/quiche/src/http2/test_tools/http2_random.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/mock_spdy_framer_visitor.h" -#include "net/third_party/spdy/core/spdy_frame_builder.h" -#include "net/third_party/spdy/core/spdy_frame_reader.h" -#include "net/third_party/spdy/core/spdy_framer.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/spdy_protocol_test_utils.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" -#include "net/third_party/spdy/platform/api/spdy_ptr_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { -namespace test { -namespace { - -class SpdyDeframerVisitorTest : public ::testing::Test { - protected: - SpdyDeframerVisitorTest() : encoder_(SpdyFramer::ENABLE_COMPRESSION) { - decoder_.set_process_single_input_frame(true); - auto collector = - SpdyMakeUnique<DeframerCallbackCollector>(&collected_frames_); - auto log_and_collect = - SpdyDeframerVisitorInterface::LogBeforeVisiting(std::move(collector)); - deframer_ = SpdyTestDeframer::CreateConverter(std::move(log_and_collect)); - decoder_.set_visitor(deframer_.get()); - } - - bool DeframeInput(const char* input, size_t size) { - size_t input_remaining = size; - while (input_remaining > 0 && - decoder_.spdy_framer_error() == - http2::Http2DecoderAdapter::SPDY_NO_ERROR) { - // To make the tests more interesting, we feed random (and small) chunks - // into the framer. This simulates getting strange-sized reads from - // the socket. - const size_t kMaxReadSize = 32; - size_t bytes_read = - (random_.Uniform(std::min(input_remaining, kMaxReadSize))) + 1; - size_t bytes_processed = decoder_.ProcessInput(input, bytes_read); - input_remaining -= bytes_processed; - input += bytes_processed; - if (decoder_.state() == - http2::Http2DecoderAdapter::SPDY_READY_FOR_FRAME) { - deframer_->AtFrameEnd(); - } - } - return (input_remaining == 0 && - decoder_.spdy_framer_error() == - http2::Http2DecoderAdapter::SPDY_NO_ERROR); - } - - SpdyFramer encoder_; - http2::Http2DecoderAdapter decoder_; - std::vector<CollectedFrame> collected_frames_; - std::unique_ptr<SpdyTestDeframer> deframer_; - - private: - http2::test::Http2Random random_; -}; - -TEST_F(SpdyDeframerVisitorTest, DataFrame) { - const char kFrameData[] = { - 0x00, 0x00, 0x0d, // Length = 13. - 0x00, // DATA - 0x08, // PADDED - 0x00, 0x00, 0x00, 0x01, // Stream 1 - 0x07, // Pad length field. - 'h', 'e', 'l', 'l', // Data - 'o', // More Data - 0x00, 0x00, 0x00, 0x00, // Padding - 0x00, 0x00, 0x00 // More Padding - }; - - EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); - ASSERT_EQ(1u, collected_frames_.size()); - const CollectedFrame& cf0 = collected_frames_[0]; - ASSERT_NE(cf0.frame_ir, nullptr); - - SpdyDataIR expected_ir(/* stream_id = */ 1, "hello"); - expected_ir.set_padding_len(8); - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); -} - -TEST_F(SpdyDeframerVisitorTest, HeaderFrameWithContinuation) { - const char kFrameData[] = { - 0x00, 0x00, 0x05, // Payload Length: 5 - 0x01, // Type: HEADERS - 0x09, // Flags: PADDED | END_STREAM - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x04, // Padding Length: 4 - 0x00, 0x00, 0x00, 0x00, // Padding - /* Second Frame */ - 0x00, 0x00, 0x12, // Payload Length: 18 - 0x09, // Type: CONTINUATION - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, // Unindexed, literal name & value - 0x03, 0x62, 0x61, 0x72, // Name len and name (3, "bar") - 0x03, 0x66, 0x6f, 0x6f, // Value len and value (3, "foo") - 0x00, // Unindexed, literal name & value - 0x03, 0x66, 0x6f, 0x6f, // Name len and name (3, "foo") - 0x03, 0x62, 0x61, 0x72, // Value len and value (3, "bar") - }; - - EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); - ASSERT_EQ(1u, collected_frames_.size()); - const CollectedFrame& cf0 = collected_frames_[0]; - - StringPairVector headers; - headers.push_back({"bar", "foo"}); - headers.push_back({"foo", "bar"}); - - EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); - - SpdyHeadersIR expected_ir(/* stream_id = */ 1); - // Yet again SpdyFramerVisitorInterface is lossy: it doesn't call OnPadding - // for HEADERS, just for DATA. Sigh. - // expected_ir.set_padding_len(5); - expected_ir.set_fin(true); - for (const auto& nv : headers) { - expected_ir.SetHeader(nv.first, nv.second); - } - - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); - - // Confirm that mismatches are also detected. - headers.push_back({"baz", "bing"}); - EXPECT_FALSE(cf0.VerifyHasHeaders(headers)); - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); - - headers.pop_back(); - EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); - - expected_ir.SetHeader("baz", "bing"); - EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); - EXPECT_TRUE(cf0.VerifyHasHeaders(headers)); -} - -TEST_F(SpdyDeframerVisitorTest, PriorityFrame) { - const char kFrameData[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x02, // Type: PRIORITY - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x65, // Stream: 101 - '\x80', 0x00, 0x00, 0x01, // Parent: 1 (Exclusive) - 0x10, // Weight: 17 - }; - - EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); - ASSERT_EQ(1u, collected_frames_.size()); - const CollectedFrame& cf0 = collected_frames_[0]; - - SpdyPriorityIR expected_ir(/* stream_id = */ 101, - /* parent_stream_id = */ 1, /* weight = */ 17, - /* exclusive = */ true); - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); - - // Confirm that mismatches are also detected. - EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 1, 16, true))); - EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 50, 17, true))); - EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(201, 1, 17, true))); - EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 1, 17, false))); -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_RstStreamFrame) { - // TODO(jamessynge): Please implement. -} - -TEST_F(SpdyDeframerVisitorTest, SettingsFrame) { - // Settings frame with two entries for the same parameter but with different - // values. The last one will be in the decoded SpdySettingsIR, but the vector - // of settings will have both, in the same order. - const char kFrameData[] = { - 0x00, 0x00, 0x0c, // Length - 0x04, // Type (SETTINGS) - 0x00, // Flags - 0x00, 0x00, 0x00, 0x00, // Stream id (must be zero) - 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE) - 0x0a, 0x0b, 0x0c, 0x0d, // Setting value - 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE) - 0x00, 0x00, 0x00, '\xff', // Setting value - }; - - EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData)); - ASSERT_EQ(1u, collected_frames_.size()); - const CollectedFrame& cf0 = collected_frames_[0]; - ASSERT_NE(cf0.frame_ir, nullptr); - - SpdySettingsIR expected_ir; - expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 255); - EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir)); - - SettingVector expected_settings; - expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 0x0a0b0c0d}); - expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 255}); - - EXPECT_TRUE(cf0.VerifyHasSettings(expected_settings)); - - // Confirm that mismatches are also detected. - expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 65536}); - EXPECT_FALSE(cf0.VerifyHasSettings(expected_settings)); - - expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 65536); - EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir)); - - SpdySettingsIR unexpected_ir; - unexpected_ir.set_is_ack(true); - EXPECT_FALSE(cf0.VerifyHasFrame(unexpected_ir)); -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_PushPromiseFrame) { - // TODO(jamessynge): Please implement. -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_PingFrame) { - // TODO(jamessynge): Please implement. -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_GoAwayFrame) { - // TODO(jamessynge): Please implement. -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_WindowUpdateFrame) { - // TODO(jamessynge): Please implement. -} - -TEST_F(SpdyDeframerVisitorTest, DISABLED_AltSvcFrame) { - // TODO(jamessynge): Please implement. -} - -} // namespace -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_frame_builder.cc b/net/third_party/spdy/core/spdy_frame_builder.cc deleted file mode 100644 index cdc36752..0000000 --- a/net/third_party/spdy/core/spdy_frame_builder.cc +++ /dev/null
@@ -1,183 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_frame_builder.h" - -#include <algorithm> -#include <cstdint> -#include <limits> -#include <new> - -#include "base/logging.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/zero_copy_output_buffer.h" -#include "net/third_party/spdy/platform/api/spdy_bug_tracker.h" - -namespace spdy { - -SpdyFrameBuilder::SpdyFrameBuilder(size_t size) - : buffer_(new char[size]), capacity_(size), length_(0), offset_(0) {} - -SpdyFrameBuilder::SpdyFrameBuilder(size_t size, ZeroCopyOutputBuffer* output) - : buffer_(output == nullptr ? new char[size] : nullptr), - output_(output), - capacity_(size), - length_(0), - offset_(0) {} - -SpdyFrameBuilder::~SpdyFrameBuilder() = default; - -char* SpdyFrameBuilder::GetWritableBuffer(size_t length) { - if (!CanWrite(length)) { - return nullptr; - } - return buffer_.get() + offset_ + length_; -} - -char* SpdyFrameBuilder::GetWritableOutput(size_t length, - size_t* actual_length) { - char* dest = nullptr; - int size = 0; - - if (!CanWrite(length)) { - return nullptr; - } - output_->Next(&dest, &size); - *actual_length = std::min<size_t>(length, size); - return dest; -} - -bool SpdyFrameBuilder::Seek(size_t length) { - if (!CanWrite(length)) { - return false; - } - if (output_ == nullptr) { - length_ += length; - } else { - output_->AdvanceWritePtr(length); - length_ += length; - } - return true; -} - -bool SpdyFrameBuilder::BeginNewFrame(SpdyFrameType type, - uint8_t flags, - SpdyStreamId stream_id) { - uint8_t raw_frame_type = SerializeFrameType(type); - DCHECK(IsDefinedFrameType(raw_frame_type)); - DCHECK_EQ(0u, stream_id & ~kStreamIdMask); - bool success = true; - if (length_ > 0) { - SPDY_BUG << "SpdyFrameBuilder doesn't have a clean state when BeginNewFrame" - << "is called. Leftover length_ is " << length_; - offset_ += length_; - length_ = 0; - } - - success &= WriteUInt24(capacity_ - offset_ - kFrameHeaderSize); - success &= WriteUInt8(raw_frame_type); - success &= WriteUInt8(flags); - success &= WriteUInt32(stream_id); - DCHECK_EQ(kDataFrameMinimumSize, length_); - return success; -} - -bool SpdyFrameBuilder::BeginNewFrame(SpdyFrameType type, - uint8_t flags, - SpdyStreamId stream_id, - size_t length) { - uint8_t raw_frame_type = SerializeFrameType(type); - DCHECK(IsDefinedFrameType(raw_frame_type)); - DCHECK_EQ(0u, stream_id & ~kStreamIdMask); - SPDY_BUG_IF(length > kHttp2DefaultFramePayloadLimit) - << "Frame length " << length_ << " is longer than frame size limit."; - return BeginNewFrameInternal(raw_frame_type, flags, stream_id, length); -} - -bool SpdyFrameBuilder::BeginNewUncheckedFrame(uint8_t raw_frame_type, - uint8_t flags, - SpdyStreamId stream_id, - size_t length) { - return BeginNewFrameInternal(raw_frame_type, flags, stream_id, length); -} - -bool SpdyFrameBuilder::BeginNewFrameInternal(uint8_t raw_frame_type, - uint8_t flags, - SpdyStreamId stream_id, - size_t length) { - DCHECK_EQ(length, length & kLengthMask); - bool success = true; - - offset_ += length_; - length_ = 0; - - success &= WriteUInt24(length); - success &= WriteUInt8(raw_frame_type); - success &= WriteUInt8(flags); - success &= WriteUInt32(stream_id); - DCHECK_EQ(kDataFrameMinimumSize, length_); - return success; -} - -bool SpdyFrameBuilder::WriteStringPiece32(const SpdyStringPiece value) { - if (!WriteUInt32(value.size())) { - return false; - } - - return WriteBytes(value.data(), value.size()); -} - -bool SpdyFrameBuilder::WriteBytes(const void* data, uint32_t data_len) { - if (!CanWrite(data_len)) { - return false; - } - - if (output_ == nullptr) { - char* dest = GetWritableBuffer(data_len); - memcpy(dest, data, data_len); - Seek(data_len); - } else { - char* dest = nullptr; - size_t size = 0; - size_t total_written = 0; - const char* data_ptr = reinterpret_cast<const char*>(data); - while (data_len > 0) { - dest = GetWritableOutput(data_len, &size); - if (dest == nullptr || size == 0) { - // Unable to make progress. - return false; - } - uint32_t to_copy = std::min<uint32_t>(data_len, size); - const char* src = data_ptr + total_written; - memcpy(dest, src, to_copy); - Seek(to_copy); - data_len -= to_copy; - total_written += to_copy; - } - } - return true; -} - -bool SpdyFrameBuilder::CanWrite(size_t length) const { - if (length > kLengthMask) { - DCHECK(false); - return false; - } - - if (output_ == nullptr) { - if (offset_ + length_ + length > capacity_) { - DLOG(FATAL) << "Requested: " << length << " capacity: " << capacity_ - << " used: " << offset_ + length_; - return false; - } - } else { - if (length > output_->BytesFree()) { - return false; - } - } - - return true; -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_frame_builder.h b/net/third_party/spdy/core/spdy_frame_builder.h deleted file mode 100644 index acf007b2..0000000 --- a/net/third_party/spdy/core/spdy_frame_builder.h +++ /dev/null
@@ -1,142 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_FRAME_BUILDER_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_FRAME_BUILDER_H_ - -#include <cstddef> -#include <cstdint> -#include <memory> - -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/zero_copy_output_buffer.h" -#include "net/third_party/spdy/platform/api/spdy_bug_tracker.h" -#include "net/third_party/spdy/platform/api/spdy_endianness_util.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" -#include "net/third_party/spdy/platform/api/spdy_test_utils_prod.h" - -namespace spdy { - -// This class provides facilities for basic binary value packing -// into Spdy frames. -// -// The SpdyFrameBuilder supports appending primitive values (int, string, etc) -// to a frame instance. The SpdyFrameBuilder grows its internal memory buffer -// dynamically to hold the sequence of primitive values. The internal memory -// buffer is exposed as the "data" of the SpdyFrameBuilder. -class SPDY_EXPORT_PRIVATE SpdyFrameBuilder { - public: - // Initializes a SpdyFrameBuilder with a buffer of given size - explicit SpdyFrameBuilder(size_t size); - // Doesn't take ownership of output. - SpdyFrameBuilder(size_t size, ZeroCopyOutputBuffer* output); - - ~SpdyFrameBuilder(); - - // Returns the total size of the SpdyFrameBuilder's data, which may include - // multiple frames. - size_t length() const { return offset_ + length_; } - - // Seeks forward by the given number of bytes. Useful in conjunction with - // GetWriteableBuffer() above. - bool Seek(size_t length); - - // Populates this frame with a HTTP2 frame prefix using length information - // from |capacity_|. The given type must be a control frame type. - bool BeginNewFrame(SpdyFrameType type, uint8_t flags, SpdyStreamId stream_id); - - // Populates this frame with a HTTP2 frame prefix with type and length - // information. |type| must be a defined frame type. - bool BeginNewFrame(SpdyFrameType type, - uint8_t flags, - SpdyStreamId stream_id, - size_t length); - - // Populates this frame with a HTTP2 frame prefix with type and length - // information. |raw_frame_type| may be a defined or undefined frame type. - bool BeginNewUncheckedFrame(uint8_t raw_frame_type, - uint8_t flags, - SpdyStreamId stream_id, - size_t length); - - // Takes the buffer from the SpdyFrameBuilder. - SpdySerializedFrame take() { - SPDY_BUG_IF(output_ != nullptr) << "ZeroCopyOutputBuffer is used to build " - << "frames. take() shouldn't be called"; - SPDY_BUG_IF(kMaxFrameSizeLimit < length_) - << "Frame length " << length_ - << " is longer than the maximum possible allowed length."; - SpdySerializedFrame rv(buffer_.release(), length(), true); - capacity_ = 0; - length_ = 0; - offset_ = 0; - return rv; - } - - // Methods for adding to the payload. These values are appended to the end - // of the SpdyFrameBuilder payload. Note - binary integers are converted from - // host to network form. - bool WriteUInt8(uint8_t value) { return WriteBytes(&value, sizeof(value)); } - bool WriteUInt16(uint16_t value) { - value = SpdyHostToNet16(value); - return WriteBytes(&value, sizeof(value)); - } - bool WriteUInt24(uint32_t value) { - value = SpdyHostToNet32(value); - return WriteBytes(reinterpret_cast<char*>(&value) + 1, sizeof(value) - 1); - } - bool WriteUInt32(uint32_t value) { - value = SpdyHostToNet32(value); - return WriteBytes(&value, sizeof(value)); - } - bool WriteUInt64(uint64_t value) { - uint32_t upper = SpdyHostToNet32(static_cast<uint32_t>(value >> 32)); - uint32_t lower = SpdyHostToNet32(static_cast<uint32_t>(value)); - return (WriteBytes(&upper, sizeof(upper)) && - WriteBytes(&lower, sizeof(lower))); - } - bool WriteStringPiece32(const SpdyStringPiece value); - bool WriteBytes(const void* data, uint32_t data_len); - - private: - SPDY_FRIEND_TEST(SpdyFrameBuilderTest, GetWritableBuffer); - SPDY_FRIEND_TEST(SpdyFrameBuilderTest, GetWritableOutput); - SPDY_FRIEND_TEST(SpdyFrameBuilderTest, GetWritableOutputNegative); - - // Populates this frame with a HTTP2 frame prefix with type and length - // information. - bool BeginNewFrameInternal(uint8_t raw_frame_type, - uint8_t flags, - SpdyStreamId stream_id, - size_t length); - - // Returns a writeable buffer of given size in bytes, to be appended to the - // currently written frame. Does bounds checking on length but does not - // increment the underlying iterator. To do so, consumers should subsequently - // call Seek(). - // In general, consumers should use Write*() calls instead of this. - // Returns NULL on failure. - char* GetWritableBuffer(size_t length); - char* GetWritableOutput(size_t desired_length, size_t* actual_length); - - // Checks to make sure that there is an appropriate amount of space for a - // write of given size, in bytes. - bool CanWrite(size_t length) const; - - // A buffer to be created whenever a new frame needs to be written. Used only - // if |output_| is nullptr. - std::unique_ptr<char[]> buffer_; - // A pre-allocated buffer. If not-null, serialized frame data is written to - // this buffer. - ZeroCopyOutputBuffer* output_ = nullptr; // Does not own. - - size_t capacity_; // Allocation size of payload, set by constructor. - size_t length_; // Length of the latest frame in the buffer. - size_t offset_; // Position at which the latest frame begins. -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_FRAME_BUILDER_H_
diff --git a/net/third_party/spdy/core/spdy_frame_builder_test.cc b/net/third_party/spdy/core/spdy_frame_builder_test.cc deleted file mode 100644 index f353e56b..0000000 --- a/net/third_party/spdy/core/spdy_frame_builder_test.cc +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_frame_builder.h" - -#include <memory> - -#include "net/third_party/spdy/core/array_output_buffer.h" -#include "net/third_party/spdy/core/spdy_framer.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -namespace { - -const int64_t kSize = 64 * 1024; -char output_buffer[kSize] = ""; - -} // namespace - -// Verifies that SpdyFrameBuilder::GetWritableBuffer() can be used to build a -// SpdySerializedFrame. -TEST(SpdyFrameBuilderTest, GetWritableBuffer) { - const size_t kBuilderSize = 10; - SpdyFrameBuilder builder(kBuilderSize); - char* writable_buffer = builder.GetWritableBuffer(kBuilderSize); - memset(writable_buffer, ~1, kBuilderSize); - EXPECT_TRUE(builder.Seek(kBuilderSize)); - SpdySerializedFrame frame(builder.take()); - char expected[kBuilderSize]; - memset(expected, ~1, kBuilderSize); - EXPECT_EQ(SpdyStringPiece(expected, kBuilderSize), - SpdyStringPiece(frame.data(), kBuilderSize)); -} - -// Verifies that SpdyFrameBuilder::GetWritableBuffer() can be used to build a -// SpdySerializedFrame to the output buffer. -TEST(SpdyFrameBuilderTest, GetWritableOutput) { - ArrayOutputBuffer output(output_buffer, kSize); - const size_t kBuilderSize = 10; - SpdyFrameBuilder builder(kBuilderSize, &output); - size_t actual_size = 0; - char* writable_buffer = builder.GetWritableOutput(kBuilderSize, &actual_size); - memset(writable_buffer, ~1, kBuilderSize); - EXPECT_TRUE(builder.Seek(kBuilderSize)); - SpdySerializedFrame frame(output.Begin(), kBuilderSize, false); - char expected[kBuilderSize]; - memset(expected, ~1, kBuilderSize); - EXPECT_EQ(SpdyStringPiece(expected, kBuilderSize), - SpdyStringPiece(frame.data(), kBuilderSize)); -} - -// Verifies the case that the buffer's capacity is too small. -TEST(SpdyFrameBuilderTest, GetWritableOutputNegative) { - size_t small_cap = 1; - ArrayOutputBuffer output(output_buffer, small_cap); - const size_t kBuilderSize = 10; - SpdyFrameBuilder builder(kBuilderSize, &output); - size_t actual_size = 0; - char* writable_buffer = builder.GetWritableOutput(kBuilderSize, &actual_size); - builder.GetWritableOutput(kBuilderSize, &actual_size); - EXPECT_EQ(0u, actual_size); - EXPECT_EQ(nullptr, writable_buffer); -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_frame_reader.cc b/net/third_party/spdy/core/spdy_frame_reader.cc deleted file mode 100644 index e98bb2f5..0000000 --- a/net/third_party/spdy/core/spdy_frame_reader.cc +++ /dev/null
@@ -1,200 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_frame_reader.h" - -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/platform/api/spdy_endianness_util.h" - -namespace spdy { - -SpdyFrameReader::SpdyFrameReader(const char* data, const size_t len) - : data_(data), len_(len), ofs_(0) {} - -bool SpdyFrameReader::ReadUInt8(uint8_t* result) { - // Make sure that we have the whole uint8_t. - if (!CanRead(1)) { - OnFailure(); - return false; - } - - // Read into result. - *result = *reinterpret_cast<const uint8_t*>(data_ + ofs_); - - // Iterate. - ofs_ += 1; - - return true; -} - -bool SpdyFrameReader::ReadUInt16(uint16_t* result) { - // Make sure that we have the whole uint16_t. - if (!CanRead(2)) { - OnFailure(); - return false; - } - - // Read into result. - *result = SpdyNetToHost16(*(reinterpret_cast<const uint16_t*>(data_ + ofs_))); - - // Iterate. - ofs_ += 2; - - return true; -} - -bool SpdyFrameReader::ReadUInt32(uint32_t* result) { - // Make sure that we have the whole uint32_t. - if (!CanRead(4)) { - OnFailure(); - return false; - } - - // Read into result. - *result = SpdyNetToHost32(*(reinterpret_cast<const uint32_t*>(data_ + ofs_))); - - // Iterate. - ofs_ += 4; - - return true; -} - -bool SpdyFrameReader::ReadUInt64(uint64_t* result) { - // Make sure that we have the whole uint64_t. - if (!CanRead(8)) { - OnFailure(); - return false; - } - - // Read into result. Network byte order is big-endian. - uint64_t upper = - SpdyNetToHost32(*(reinterpret_cast<const uint32_t*>(data_ + ofs_))); - uint64_t lower = - SpdyNetToHost32(*(reinterpret_cast<const uint32_t*>(data_ + ofs_ + 4))); - *result = (upper << 32) + lower; - - // Iterate. - ofs_ += 8; - - return true; -} - -bool SpdyFrameReader::ReadUInt31(uint32_t* result) { - bool success = ReadUInt32(result); - - // Zero out highest-order bit. - if (success) { - *result &= 0x7fffffff; - } - - return success; -} - -bool SpdyFrameReader::ReadUInt24(uint32_t* result) { - // Make sure that we have the whole uint24_t. - if (!CanRead(3)) { - OnFailure(); - return false; - } - - // Read into result. - *result = 0; - memcpy(reinterpret_cast<char*>(result) + 1, data_ + ofs_, 3); - *result = SpdyNetToHost32(*result); - - // Iterate. - ofs_ += 3; - - return true; -} - -bool SpdyFrameReader::ReadStringPiece16(SpdyStringPiece* result) { - // Read resultant length. - uint16_t result_len; - if (!ReadUInt16(&result_len)) { - // OnFailure() already called. - return false; - } - - // Make sure that we have the whole string. - if (!CanRead(result_len)) { - OnFailure(); - return false; - } - - // Set result. - *result = SpdyStringPiece(data_ + ofs_, result_len); - - // Iterate. - ofs_ += result_len; - - return true; -} - -bool SpdyFrameReader::ReadStringPiece32(SpdyStringPiece* result) { - // Read resultant length. - uint32_t result_len; - if (!ReadUInt32(&result_len)) { - // OnFailure() already called. - return false; - } - - // Make sure that we have the whole string. - if (!CanRead(result_len)) { - OnFailure(); - return false; - } - - // Set result. - *result = SpdyStringPiece(data_ + ofs_, result_len); - - // Iterate. - ofs_ += result_len; - - return true; -} - -bool SpdyFrameReader::ReadBytes(void* result, size_t size) { - // Make sure that we have enough data to read. - if (!CanRead(size)) { - OnFailure(); - return false; - } - - // Read into result. - memcpy(result, data_ + ofs_, size); - - // Iterate. - ofs_ += size; - - return true; -} - -bool SpdyFrameReader::Seek(size_t size) { - if (!CanRead(size)) { - OnFailure(); - return false; - } - - // Iterate. - ofs_ += size; - - return true; -} - -bool SpdyFrameReader::IsDoneReading() const { - return len_ == ofs_; -} - -bool SpdyFrameReader::CanRead(size_t bytes) const { - return bytes <= (len_ - ofs_); -} - -void SpdyFrameReader::OnFailure() { - // Set our iterator to the end of the buffer so that further reads fail - // immediately. - ofs_ = len_; -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_frame_reader.h b/net/third_party/spdy/core/spdy_frame_reader.h deleted file mode 100644 index 6c211bc..0000000 --- a/net/third_party/spdy/core/spdy_frame_reader.h +++ /dev/null
@@ -1,129 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_FRAME_READER_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_FRAME_READER_H_ - -#include <cstdint> - -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { - -// Used for reading SPDY frames. Though there isn't really anything terribly -// SPDY-specific here, it's a helper class that's useful when doing SPDY -// framing. -// -// To use, simply construct a SpdyFramerReader using the underlying buffer that -// you'd like to read fields from, then call one of the Read*() methods to -// actually do some reading. -// -// This class keeps an internal iterator to keep track of what's already been -// read and each successive Read*() call automatically increments said iterator -// on success. On failure, internal state of the SpdyFrameReader should not be -// trusted and it is up to the caller to throw away the failed instance and -// handle the error as appropriate. None of the Read*() methods should ever be -// called after failure, as they will also fail immediately. -class SPDY_EXPORT_PRIVATE SpdyFrameReader { - public: - // Caller must provide an underlying buffer to work on. - SpdyFrameReader(const char* data, const size_t len); - - // Empty destructor. - ~SpdyFrameReader() {} - - // Reads an 8-bit unsigned integer into the given output parameter. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadUInt8(uint8_t* result); - - // Reads a 16-bit unsigned integer into the given output parameter. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadUInt16(uint16_t* result); - - // Reads a 32-bit unsigned integer into the given output parameter. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadUInt32(uint32_t* result); - - // Reads a 64-bit unsigned integer into the given output parameter. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadUInt64(uint64_t* result); - - // Reads a 31-bit unsigned integer into the given output parameter. This is - // equivalent to ReadUInt32() above except that the highest-order bit is - // discarded. - // Forwards the internal iterator (by 4B) on success. - // Returns true on success, false otherwise. - bool ReadUInt31(uint32_t* result); - - // Reads a 24-bit unsigned integer into the given output parameter. - // Forwards the internal iterator (by 3B) on success. - // Returns true on success, false otherwise. - bool ReadUInt24(uint32_t* result); - - // Reads a string prefixed with 16-bit length into the given output parameter. - // - // NOTE: Does not copy but rather references strings in the underlying buffer. - // This should be kept in mind when handling memory management! - // - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadStringPiece16(SpdyStringPiece* result); - - // Reads a string prefixed with 32-bit length into the given output parameter. - // - // NOTE: Does not copy but rather references strings in the underlying buffer. - // This should be kept in mind when handling memory management! - // - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadStringPiece32(SpdyStringPiece* result); - - // Reads a given number of bytes into the given buffer. The buffer - // must be of adequate size. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadBytes(void* result, size_t size); - - // Seeks a given number of bytes into the buffer from the current offset. - // Equivelant to an empty read. - // Forwards the internal iterator. - // Returns true on success, false otherwise. - bool Seek(size_t size); - - // Rewinds this reader to the beginning of the frame. - void Rewind() { ofs_ = 0; } - - // Returns true if the entirety of the underlying buffer has been read via - // Read*() calls. - bool IsDoneReading() const; - - // Returns the number of bytes that have been consumed by the reader so far. - size_t GetBytesConsumed() const { return ofs_; } - - private: - // Returns true if the underlying buffer has enough room to read the given - // amount of bytes. - bool CanRead(size_t bytes) const; - - // To be called when a read fails for any reason. - void OnFailure(); - - // The data buffer that we're reading from. - const char* data_; - - // The length of the data buffer that we're reading from. - const size_t len_; - - // The location of the next read from our data buffer. - size_t ofs_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_FRAME_READER_H_
diff --git a/net/third_party/spdy/core/spdy_frame_reader_test.cc b/net/third_party/spdy/core/spdy_frame_reader_test.cc deleted file mode 100644 index ca557ac..0000000 --- a/net/third_party/spdy/core/spdy_frame_reader_test.cc +++ /dev/null
@@ -1,247 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_frame_reader.h" - -#include <cstdint> - -#include "net/third_party/spdy/platform/api/spdy_arraysize.h" -#include "net/third_party/spdy/platform/api/spdy_endianness_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -TEST(SpdyFrameReaderTest, ReadUInt16) { - // Frame data in network byte order. - const uint16_t kFrameData[] = { - SpdyHostToNet16(1), - SpdyHostToNet16(1 << 15), - }; - - SpdyFrameReader frame_reader(reinterpret_cast<const char*>(kFrameData), - sizeof(kFrameData)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - uint16_t uint16_val; - EXPECT_TRUE(frame_reader.ReadUInt16(&uint16_val)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - EXPECT_EQ(1, uint16_val); - - EXPECT_TRUE(frame_reader.ReadUInt16(&uint16_val)); - EXPECT_TRUE(frame_reader.IsDoneReading()); - EXPECT_EQ(1 << 15, uint16_val); -} - -TEST(SpdyFrameReaderTest, ReadUInt32) { - // Frame data in network byte order. - const uint32_t kFrameData[] = { - SpdyHostToNet32(1), - SpdyHostToNet32(0x80000000), - }; - - SpdyFrameReader frame_reader(reinterpret_cast<const char*>(kFrameData), - SPDY_ARRAYSIZE(kFrameData) * sizeof(uint32_t)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - uint32_t uint32_val; - EXPECT_TRUE(frame_reader.ReadUInt32(&uint32_val)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - EXPECT_EQ(1u, uint32_val); - - EXPECT_TRUE(frame_reader.ReadUInt32(&uint32_val)); - EXPECT_TRUE(frame_reader.IsDoneReading()); - EXPECT_EQ(1u << 31, uint32_val); -} - -TEST(SpdyFrameReaderTest, ReadStringPiece16) { - // Frame data in network byte order. - const char kFrameData[] = { - 0x00, 0x02, // uint16_t(2) - 0x48, 0x69, // "Hi" - 0x00, 0x10, // uint16_t(16) - 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2c, - 0x20, 0x31, 0x2c, 0x20, 0x32, 0x2c, 0x20, 0x33, // "Testing, 1, 2, 3" - }; - - SpdyFrameReader frame_reader(kFrameData, SPDY_ARRAYSIZE(kFrameData)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - SpdyStringPiece stringpiece_val; - EXPECT_TRUE(frame_reader.ReadStringPiece16(&stringpiece_val)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - EXPECT_EQ(0, stringpiece_val.compare("Hi")); - - EXPECT_TRUE(frame_reader.ReadStringPiece16(&stringpiece_val)); - EXPECT_TRUE(frame_reader.IsDoneReading()); - EXPECT_EQ(0, stringpiece_val.compare("Testing, 1, 2, 3")); -} - -TEST(SpdyFrameReaderTest, ReadStringPiece32) { - // Frame data in network byte order. - const char kFrameData[] = { - 0x00, 0x00, 0x00, 0x03, // uint32_t(3) - 0x66, 0x6f, 0x6f, // "foo" - 0x00, 0x00, 0x00, 0x10, // uint32_t(16) - 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2c, - 0x20, 0x34, 0x2c, 0x20, 0x35, 0x2c, 0x20, 0x36, // "Testing, 4, 5, 6" - }; - - SpdyFrameReader frame_reader(kFrameData, SPDY_ARRAYSIZE(kFrameData)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - SpdyStringPiece stringpiece_val; - EXPECT_TRUE(frame_reader.ReadStringPiece32(&stringpiece_val)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - EXPECT_EQ(0, stringpiece_val.compare("foo")); - - EXPECT_TRUE(frame_reader.ReadStringPiece32(&stringpiece_val)); - EXPECT_TRUE(frame_reader.IsDoneReading()); - EXPECT_EQ(0, stringpiece_val.compare("Testing, 4, 5, 6")); -} - -TEST(SpdyFrameReaderTest, ReadUInt16WithBufferTooSmall) { - // Frame data in network byte order. - const char kFrameData[] = { - 0x00, // part of a uint16_t - }; - - SpdyFrameReader frame_reader(kFrameData, SPDY_ARRAYSIZE(kFrameData)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - uint16_t uint16_val; - EXPECT_FALSE(frame_reader.ReadUInt16(&uint16_val)); -} - -TEST(SpdyFrameReaderTest, ReadUInt32WithBufferTooSmall) { - // Frame data in network byte order. - const char kFrameData[] = { - 0x00, 0x00, 0x00, // part of a uint32_t - }; - - SpdyFrameReader frame_reader(kFrameData, SPDY_ARRAYSIZE(kFrameData)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - uint32_t uint32_val; - EXPECT_FALSE(frame_reader.ReadUInt32(&uint32_val)); - - // Also make sure that trying to read a uint16_t, which technically could - // work, fails immediately due to previously encountered failed read. - uint16_t uint16_val; - EXPECT_FALSE(frame_reader.ReadUInt16(&uint16_val)); -} - -// Tests ReadStringPiece16() with a buffer too small to fit the entire string. -TEST(SpdyFrameReaderTest, ReadStringPiece16WithBufferTooSmall) { - // Frame data in network byte order. - const char kFrameData[] = { - 0x00, 0x03, // uint16_t(3) - 0x48, 0x69, // "Hi" - }; - - SpdyFrameReader frame_reader(kFrameData, SPDY_ARRAYSIZE(kFrameData)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - SpdyStringPiece stringpiece_val; - EXPECT_FALSE(frame_reader.ReadStringPiece16(&stringpiece_val)); - - // Also make sure that trying to read a uint16_t, which technically could - // work, fails immediately due to previously encountered failed read. - uint16_t uint16_val; - EXPECT_FALSE(frame_reader.ReadUInt16(&uint16_val)); -} - -// Tests ReadStringPiece16() with a buffer too small even to fit the length. -TEST(SpdyFrameReaderTest, ReadStringPiece16WithBufferWayTooSmall) { - // Frame data in network byte order. - const char kFrameData[] = { - 0x00, // part of a uint16_t - }; - - SpdyFrameReader frame_reader(kFrameData, SPDY_ARRAYSIZE(kFrameData)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - SpdyStringPiece stringpiece_val; - EXPECT_FALSE(frame_reader.ReadStringPiece16(&stringpiece_val)); - - // Also make sure that trying to read a uint16_t, which technically could - // work, fails immediately due to previously encountered failed read. - uint16_t uint16_val; - EXPECT_FALSE(frame_reader.ReadUInt16(&uint16_val)); -} - -// Tests ReadStringPiece32() with a buffer too small to fit the entire string. -TEST(SpdyFrameReaderTest, ReadStringPiece32WithBufferTooSmall) { - // Frame data in network byte order. - const char kFrameData[] = { - 0x00, 0x00, 0x00, 0x03, // uint32_t(3) - 0x48, 0x69, // "Hi" - }; - - SpdyFrameReader frame_reader(kFrameData, SPDY_ARRAYSIZE(kFrameData)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - SpdyStringPiece stringpiece_val; - EXPECT_FALSE(frame_reader.ReadStringPiece32(&stringpiece_val)); - - // Also make sure that trying to read a uint16_t, which technically could - // work, fails immediately due to previously encountered failed read. - uint16_t uint16_val; - EXPECT_FALSE(frame_reader.ReadUInt16(&uint16_val)); -} - -// Tests ReadStringPiece32() with a buffer too small even to fit the length. -TEST(SpdyFrameReaderTest, ReadStringPiece32WithBufferWayTooSmall) { - // Frame data in network byte order. - const char kFrameData[] = { - 0x00, 0x00, 0x00, // part of a uint32_t - }; - - SpdyFrameReader frame_reader(kFrameData, SPDY_ARRAYSIZE(kFrameData)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - SpdyStringPiece stringpiece_val; - EXPECT_FALSE(frame_reader.ReadStringPiece32(&stringpiece_val)); - - // Also make sure that trying to read a uint16_t, which technically could - // work, fails immediately due to previously encountered failed read. - uint16_t uint16_val; - EXPECT_FALSE(frame_reader.ReadUInt16(&uint16_val)); -} - -TEST(SpdyFrameReaderTest, ReadBytes) { - // Frame data in network byte order. - const char kFrameData[] = { - 0x66, 0x6f, 0x6f, // "foo" - 0x48, 0x69, // "Hi" - }; - - SpdyFrameReader frame_reader(kFrameData, SPDY_ARRAYSIZE(kFrameData)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - char dest1[3] = {}; - EXPECT_TRUE(frame_reader.ReadBytes(&dest1, SPDY_ARRAYSIZE(dest1))); - EXPECT_FALSE(frame_reader.IsDoneReading()); - EXPECT_EQ("foo", SpdyStringPiece(dest1, SPDY_ARRAYSIZE(dest1))); - - char dest2[2] = {}; - EXPECT_TRUE(frame_reader.ReadBytes(&dest2, SPDY_ARRAYSIZE(dest2))); - EXPECT_TRUE(frame_reader.IsDoneReading()); - EXPECT_EQ("Hi", SpdyStringPiece(dest2, SPDY_ARRAYSIZE(dest2))); -} - -TEST(SpdyFrameReaderTest, ReadBytesWithBufferTooSmall) { - // Frame data in network byte order. - const char kFrameData[] = { - 0x01, - }; - - SpdyFrameReader frame_reader(kFrameData, SPDY_ARRAYSIZE(kFrameData)); - EXPECT_FALSE(frame_reader.IsDoneReading()); - - char dest[SPDY_ARRAYSIZE(kFrameData) + 2] = {}; - EXPECT_FALSE(frame_reader.ReadBytes(&dest, SPDY_ARRAYSIZE(kFrameData) + 1)); - EXPECT_STREQ("", dest); -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_framer.cc b/net/third_party/spdy/core/spdy_framer.cc deleted file mode 100644 index b238b18d..0000000 --- a/net/third_party/spdy/core/spdy_framer.cc +++ /dev/null
@@ -1,1295 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_framer.h" - -#include <algorithm> -#include <cstdint> -#include <iterator> -#include <list> -#include <new> - -#include "base/logging.h" -#include "net/third_party/quiche/src/http2/platform/api/http2_macros.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/spdy_bitmasks.h" -#include "net/third_party/spdy/core/spdy_frame_builder.h" -#include "net/third_party/spdy/core/spdy_frame_reader.h" -#include "net/third_party/spdy/platform/api/spdy_bug_tracker.h" -#include "net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h" -#include "net/third_party/spdy/platform/api/spdy_ptr_util.h" -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" - -namespace spdy { - -namespace { - -// Pack parent stream ID and exclusive flag into the format used by HTTP/2 -// headers and priority frames. -uint32_t PackStreamDependencyValues(bool exclusive, - SpdyStreamId parent_stream_id) { - // Make sure the highest-order bit in the parent stream id is zeroed out. - uint32_t parent = parent_stream_id & 0x7fffffff; - // Set the one-bit exclusivity flag. - uint32_t e_bit = exclusive ? 0x80000000 : 0; - return parent | e_bit; -} - -// Used to indicate no flags in a HTTP2 flags field. -const uint8_t kNoFlags = 0; - -// Wire size of pad length field. -const size_t kPadLengthFieldSize = 1; - -// The size of one parameter in SETTINGS frame. -const size_t kOneSettingParameterSize = 6; - -size_t GetUncompressedSerializedLength(const SpdyHeaderBlock& headers) { - const size_t num_name_value_pairs_size = sizeof(uint32_t); - const size_t length_of_name_size = num_name_value_pairs_size; - const size_t length_of_value_size = num_name_value_pairs_size; - - size_t total_length = num_name_value_pairs_size; - for (const auto& header : headers) { - // We add space for the length of the name and the length of the value as - // well as the length of the name and the length of the value. - total_length += length_of_name_size + header.first.size() + - length_of_value_size + header.second.size(); - } - return total_length; -} - -// Serializes the flags octet for a given SpdyHeadersIR. -uint8_t SerializeHeaderFrameFlags(const SpdyHeadersIR& header_ir, - const bool end_headers) { - uint8_t flags = 0; - if (header_ir.fin()) { - flags |= CONTROL_FLAG_FIN; - } - if (end_headers) { - flags |= HEADERS_FLAG_END_HEADERS; - } - if (header_ir.padded()) { - flags |= HEADERS_FLAG_PADDED; - } - if (header_ir.has_priority()) { - flags |= HEADERS_FLAG_PRIORITY; - } - return flags; -} - -// Serializes the flags octet for a given SpdyPushPromiseIR. -uint8_t SerializePushPromiseFrameFlags(const SpdyPushPromiseIR& push_promise_ir, - const bool end_headers) { - uint8_t flags = 0; - if (push_promise_ir.padded()) { - flags = flags | PUSH_PROMISE_FLAG_PADDED; - } - if (end_headers) { - flags |= PUSH_PROMISE_FLAG_END_PUSH_PROMISE; - } - return flags; -} - -// Serializes a HEADERS frame from the given SpdyHeadersIR and encoded header -// block. Does not need or use the SpdyHeaderBlock inside SpdyHeadersIR. -// Return false if the serialization fails. |encoding| should not be empty. -bool SerializeHeadersGivenEncoding(const SpdyHeadersIR& headers, - const SpdyString& encoding, - const bool end_headers, - ZeroCopyOutputBuffer* output) { - const size_t frame_size = - GetHeaderFrameSizeSansBlock(headers) + encoding.size(); - SpdyFrameBuilder builder(frame_size, output); - bool ret = builder.BeginNewFrame( - SpdyFrameType::HEADERS, SerializeHeaderFrameFlags(headers, end_headers), - headers.stream_id(), frame_size - kFrameHeaderSize); - DCHECK_EQ(kFrameHeaderSize, builder.length()); - - if (ret && headers.padded()) { - ret &= builder.WriteUInt8(headers.padding_payload_len()); - } - - if (ret && headers.has_priority()) { - int weight = ClampHttp2Weight(headers.weight()); - ret &= builder.WriteUInt32(PackStreamDependencyValues( - headers.exclusive(), headers.parent_stream_id())); - // Per RFC 7540 section 6.3, serialized weight value is actual value - 1. - ret &= builder.WriteUInt8(weight - 1); - } - - if (ret) { - ret &= builder.WriteBytes(encoding.data(), encoding.size()); - } - - if (ret && headers.padding_payload_len() > 0) { - SpdyString padding(headers.padding_payload_len(), 0); - ret &= builder.WriteBytes(padding.data(), padding.length()); - } - - if (!ret) { - DLOG(WARNING) << "Failed to build HEADERS. Not enough space in output"; - } - return ret; -} - -// Serializes a PUSH_PROMISE frame from the given SpdyPushPromiseIR and -// encoded header block. Does not need or use the SpdyHeaderBlock inside -// SpdyPushPromiseIR. -bool SerializePushPromiseGivenEncoding(const SpdyPushPromiseIR& push_promise, - const SpdyString& encoding, - const bool end_headers, - ZeroCopyOutputBuffer* output) { - const size_t frame_size = - GetPushPromiseFrameSizeSansBlock(push_promise) + encoding.size(); - SpdyFrameBuilder builder(frame_size, output); - bool ok = builder.BeginNewFrame( - SpdyFrameType::PUSH_PROMISE, - SerializePushPromiseFrameFlags(push_promise, end_headers), - push_promise.stream_id(), frame_size - kFrameHeaderSize); - - if (push_promise.padded()) { - ok = ok && builder.WriteUInt8(push_promise.padding_payload_len()); - } - ok = ok && builder.WriteUInt32(push_promise.promised_stream_id()) && - builder.WriteBytes(encoding.data(), encoding.size()); - if (ok && push_promise.padding_payload_len() > 0) { - SpdyString padding(push_promise.padding_payload_len(), 0); - ok = builder.WriteBytes(padding.data(), padding.length()); - } - - DLOG_IF(ERROR, !ok) << "Failed to write PUSH_PROMISE encoding, not enough " - << "space in output"; - return ok; -} - -bool WritePayloadWithContinuation(SpdyFrameBuilder* builder, - const SpdyString& hpack_encoding, - SpdyStreamId stream_id, - SpdyFrameType type, - int padding_payload_len) { - uint8_t end_flag = 0; - uint8_t flags = 0; - if (type == SpdyFrameType::HEADERS) { - end_flag = HEADERS_FLAG_END_HEADERS; - } else if (type == SpdyFrameType::PUSH_PROMISE) { - end_flag = PUSH_PROMISE_FLAG_END_PUSH_PROMISE; - } else { - DLOG(FATAL) << "CONTINUATION frames cannot be used with frame type " - << FrameTypeToString(type); - } - - // Write all the padding payload and as much of the data payload as possible - // into the initial frame. - size_t bytes_remaining = 0; - bytes_remaining = hpack_encoding.size() - - std::min(hpack_encoding.size(), - kHttp2MaxControlFrameSendSize - builder->length() - - padding_payload_len); - bool ret = builder->WriteBytes(&hpack_encoding[0], - hpack_encoding.size() - bytes_remaining); - if (padding_payload_len > 0) { - SpdyString padding = SpdyString(padding_payload_len, 0); - ret &= builder->WriteBytes(padding.data(), padding.length()); - } - - // Tack on CONTINUATION frames for the overflow. - while (bytes_remaining > 0 && ret) { - size_t bytes_to_write = - std::min(bytes_remaining, - kHttp2MaxControlFrameSendSize - kContinuationFrameMinimumSize); - // Write CONTINUATION frame prefix. - if (bytes_remaining == bytes_to_write) { - flags |= end_flag; - } - ret &= builder->BeginNewFrame(SpdyFrameType::CONTINUATION, flags, stream_id, - bytes_to_write); - // Write payload fragment. - ret &= builder->WriteBytes( - &hpack_encoding[hpack_encoding.size() - bytes_remaining], - bytes_to_write); - bytes_remaining -= bytes_to_write; - } - return ret; -} - -void SerializeDataBuilderHelper(const SpdyDataIR& data_ir, - uint8_t* flags, - int* num_padding_fields, - size_t* size_with_padding) { - if (data_ir.fin()) { - *flags = DATA_FLAG_FIN; - } - - if (data_ir.padded()) { - *flags = *flags | DATA_FLAG_PADDED; - ++*num_padding_fields; - } - - *size_with_padding = *num_padding_fields + data_ir.data_len() + - data_ir.padding_payload_len() + kDataFrameMinimumSize; -} - -void SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper( - const SpdyDataIR& data_ir, - uint8_t* flags, - size_t* frame_size, - size_t* num_padding_fields) { - *flags = DATA_FLAG_NONE; - if (data_ir.fin()) { - *flags = DATA_FLAG_FIN; - } - - *frame_size = kDataFrameMinimumSize; - if (data_ir.padded()) { - *flags = *flags | DATA_FLAG_PADDED; - ++(*num_padding_fields); - *frame_size = *frame_size + *num_padding_fields; - } -} - -void SerializeSettingsBuilderHelper(const SpdySettingsIR& settings, - uint8_t* flags, - const SettingsMap* values, - size_t* size) { - if (settings.is_ack()) { - *flags = *flags | SETTINGS_FLAG_ACK; - } - *size = - kSettingsFrameMinimumSize + (values->size() * kOneSettingParameterSize); -} - -void SerializeAltSvcBuilderHelper(const SpdyAltSvcIR& altsvc_ir, - SpdyString* value, - size_t* size) { - *size = kGetAltSvcFrameMinimumSize; - *size = *size + altsvc_ir.origin().length(); - *value = SpdyAltSvcWireFormat::SerializeHeaderFieldValue( - altsvc_ir.altsvc_vector()); - *size = *size + value->length(); -} - -} // namespace - -SpdyFramer::SpdyFramer(CompressionOption option) - : debug_visitor_(nullptr), compression_option_(option) { - static_assert(kHttp2MaxControlFrameSendSize <= kHttp2DefaultFrameSizeLimit, - "Our send limit should be at most our receive limit."); -} - -SpdyFramer::~SpdyFramer() = default; - -void SpdyFramer::set_debug_visitor( - SpdyFramerDebugVisitorInterface* debug_visitor) { - debug_visitor_ = debug_visitor; -} - -SpdyFramer::SpdyFrameIterator::SpdyFrameIterator(SpdyFramer* framer) - : framer_(framer), is_first_frame_(true), has_next_frame_(true) {} - -SpdyFramer::SpdyFrameIterator::~SpdyFrameIterator() = default; - -size_t SpdyFramer::SpdyFrameIterator::NextFrame(ZeroCopyOutputBuffer* output) { - const SpdyFrameIR& frame_ir = GetIR(); - if (!has_next_frame_) { - SPDY_BUG << "SpdyFramer::SpdyFrameIterator::NextFrame called without " - << "a next frame."; - return false; - } - - const size_t size_without_block = - is_first_frame_ ? GetFrameSizeSansBlock() : kContinuationFrameMinimumSize; - auto encoding = SpdyMakeUnique<SpdyString>(); - encoder_->Next(kHttp2MaxControlFrameSendSize - size_without_block, - encoding.get()); - has_next_frame_ = encoder_->HasNext(); - - if (framer_->debug_visitor_ != nullptr) { - const auto& header_block_frame_ir = - static_cast<const SpdyFrameWithHeaderBlockIR&>(frame_ir); - const size_t header_list_size = - GetUncompressedSerializedLength(header_block_frame_ir.header_block()); - framer_->debug_visitor_->OnSendCompressedFrame( - frame_ir.stream_id(), - is_first_frame_ ? frame_ir.frame_type() : SpdyFrameType::CONTINUATION, - header_list_size, size_without_block + encoding->size()); - } - - const size_t free_bytes_before = output->BytesFree(); - bool ok = false; - if (is_first_frame_) { - is_first_frame_ = false; - ok = SerializeGivenEncoding(*encoding, output); - } else { - SpdyContinuationIR continuation_ir(frame_ir.stream_id()); - continuation_ir.take_encoding(std::move(encoding)); - continuation_ir.set_end_headers(!has_next_frame_); - ok = framer_->SerializeContinuation(continuation_ir, output); - } - return ok ? free_bytes_before - output->BytesFree() : 0; -} - -bool SpdyFramer::SpdyFrameIterator::HasNextFrame() const { - return has_next_frame_; -} - -SpdyFramer::SpdyHeaderFrameIterator::SpdyHeaderFrameIterator( - SpdyFramer* framer, - std::unique_ptr<const SpdyHeadersIR> headers_ir) - : SpdyFrameIterator(framer), headers_ir_(std::move(headers_ir)) { - SetEncoder(headers_ir_.get()); -} - -SpdyFramer::SpdyHeaderFrameIterator::~SpdyHeaderFrameIterator() = default; - -const SpdyFrameIR& SpdyFramer::SpdyHeaderFrameIterator::GetIR() const { - return *(headers_ir_.get()); -} - -size_t SpdyFramer::SpdyHeaderFrameIterator::GetFrameSizeSansBlock() const { - return GetHeaderFrameSizeSansBlock(*headers_ir_); -} - -bool SpdyFramer::SpdyHeaderFrameIterator::SerializeGivenEncoding( - const SpdyString& encoding, - ZeroCopyOutputBuffer* output) const { - return SerializeHeadersGivenEncoding(*headers_ir_, encoding, - !has_next_frame(), output); -} - -SpdyFramer::SpdyPushPromiseFrameIterator::SpdyPushPromiseFrameIterator( - SpdyFramer* framer, - std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir) - : SpdyFrameIterator(framer), push_promise_ir_(std::move(push_promise_ir)) { - SetEncoder(push_promise_ir_.get()); -} - -SpdyFramer::SpdyPushPromiseFrameIterator::~SpdyPushPromiseFrameIterator() = - default; - -const SpdyFrameIR& SpdyFramer::SpdyPushPromiseFrameIterator::GetIR() const { - return *(push_promise_ir_.get()); -} - -size_t SpdyFramer::SpdyPushPromiseFrameIterator::GetFrameSizeSansBlock() const { - return GetPushPromiseFrameSizeSansBlock(*push_promise_ir_); -} - -bool SpdyFramer::SpdyPushPromiseFrameIterator::SerializeGivenEncoding( - const SpdyString& encoding, - ZeroCopyOutputBuffer* output) const { - return SerializePushPromiseGivenEncoding(*push_promise_ir_, encoding, - !has_next_frame(), output); -} - -SpdyFramer::SpdyControlFrameIterator::SpdyControlFrameIterator( - SpdyFramer* framer, - std::unique_ptr<const SpdyFrameIR> frame_ir) - : framer_(framer), frame_ir_(std::move(frame_ir)) {} - -SpdyFramer::SpdyControlFrameIterator::~SpdyControlFrameIterator() = default; - -size_t SpdyFramer::SpdyControlFrameIterator::NextFrame( - ZeroCopyOutputBuffer* output) { - size_t size_written = framer_->SerializeFrame(*frame_ir_, output); - has_next_frame_ = false; - return size_written; -} - -bool SpdyFramer::SpdyControlFrameIterator::HasNextFrame() const { - return has_next_frame_; -} - -const SpdyFrameIR& SpdyFramer::SpdyControlFrameIterator::GetIR() const { - return *(frame_ir_.get()); -} - -// TODO(yasong): remove all the static_casts. -std::unique_ptr<SpdyFrameSequence> SpdyFramer::CreateIterator( - SpdyFramer* framer, - std::unique_ptr<const SpdyFrameIR> frame_ir) { - switch (frame_ir->frame_type()) { - case SpdyFrameType::HEADERS: { - return SpdyMakeUnique<SpdyHeaderFrameIterator>( - framer, SpdyWrapUnique( - static_cast<const SpdyHeadersIR*>(frame_ir.release()))); - } - case SpdyFrameType::PUSH_PROMISE: { - return SpdyMakeUnique<SpdyPushPromiseFrameIterator>( - framer, SpdyWrapUnique(static_cast<const SpdyPushPromiseIR*>( - frame_ir.release()))); - } - case SpdyFrameType::DATA: { - DVLOG(1) << "Serialize a stream end DATA frame for VTL"; - HTTP2_FALLTHROUGH; - } - default: { - return SpdyMakeUnique<SpdyControlFrameIterator>(framer, - std::move(frame_ir)); - } - } -} - -SpdySerializedFrame SpdyFramer::SerializeData(const SpdyDataIR& data_ir) { - uint8_t flags = DATA_FLAG_NONE; - int num_padding_fields = 0; - size_t size_with_padding = 0; - SerializeDataBuilderHelper(data_ir, &flags, &num_padding_fields, - &size_with_padding); - - SpdyFrameBuilder builder(size_with_padding); - builder.BeginNewFrame(SpdyFrameType::DATA, flags, data_ir.stream_id()); - if (data_ir.padded()) { - builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); - } - builder.WriteBytes(data_ir.data(), data_ir.data_len()); - if (data_ir.padding_payload_len() > 0) { - SpdyString padding(data_ir.padding_payload_len(), 0); - builder.WriteBytes(padding.data(), padding.length()); - } - DCHECK_EQ(size_with_padding, builder.length()); - return builder.take(); -} - -SpdySerializedFrame SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField( - const SpdyDataIR& data_ir) { - uint8_t flags = DATA_FLAG_NONE; - size_t frame_size = 0; - size_t num_padding_fields = 0; - SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper( - data_ir, &flags, &frame_size, &num_padding_fields); - - SpdyFrameBuilder builder(frame_size); - builder.BeginNewFrame( - SpdyFrameType::DATA, flags, data_ir.stream_id(), - num_padding_fields + data_ir.data_len() + data_ir.padding_payload_len()); - if (data_ir.padded()) { - builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); - } - DCHECK_EQ(frame_size, builder.length()); - return builder.take(); -} - -SpdySerializedFrame SpdyFramer::SerializeRstStream( - const SpdyRstStreamIR& rst_stream) const { - size_t expected_length = kRstStreamFrameSize; - SpdyFrameBuilder builder(expected_length); - - builder.BeginNewFrame(SpdyFrameType::RST_STREAM, 0, rst_stream.stream_id()); - - builder.WriteUInt32(rst_stream.error_code()); - - DCHECK_EQ(expected_length, builder.length()); - return builder.take(); -} - -SpdySerializedFrame SpdyFramer::SerializeSettings( - const SpdySettingsIR& settings) const { - uint8_t flags = 0; - // Size, in bytes, of this SETTINGS frame. - size_t size = 0; - const SettingsMap* values = &(settings.values()); - SerializeSettingsBuilderHelper(settings, &flags, values, &size); - SpdyFrameBuilder builder(size); - builder.BeginNewFrame(SpdyFrameType::SETTINGS, flags, 0); - - // If this is an ACK, payload should be empty. - if (settings.is_ack()) { - return builder.take(); - } - - DCHECK_EQ(kSettingsFrameMinimumSize, builder.length()); - for (auto it = values->begin(); it != values->end(); ++it) { - int setting_id = it->first; - DCHECK_GE(setting_id, 0); - builder.WriteUInt16(static_cast<SpdySettingsId>(setting_id)); - builder.WriteUInt32(it->second); - } - DCHECK_EQ(size, builder.length()); - return builder.take(); -} - -SpdySerializedFrame SpdyFramer::SerializePing(const SpdyPingIR& ping) const { - SpdyFrameBuilder builder(kPingFrameSize); - uint8_t flags = 0; - if (ping.is_ack()) { - flags |= PING_FLAG_ACK; - } - builder.BeginNewFrame(SpdyFrameType::PING, flags, 0); - builder.WriteUInt64(ping.id()); - DCHECK_EQ(kPingFrameSize, builder.length()); - return builder.take(); -} - -SpdySerializedFrame SpdyFramer::SerializeGoAway( - const SpdyGoAwayIR& goaway) const { - // Compute the output buffer size, take opaque data into account. - size_t expected_length = kGoawayFrameMinimumSize; - expected_length += goaway.description().size(); - SpdyFrameBuilder builder(expected_length); - - // Serialize the GOAWAY frame. - builder.BeginNewFrame(SpdyFrameType::GOAWAY, 0, 0); - - // GOAWAY frames specify the last good stream id. - builder.WriteUInt32(goaway.last_good_stream_id()); - - // GOAWAY frames also specify the error code. - builder.WriteUInt32(goaway.error_code()); - - // GOAWAY frames may also specify opaque data. - if (!goaway.description().empty()) { - builder.WriteBytes(goaway.description().data(), - goaway.description().size()); - } - - DCHECK_EQ(expected_length, builder.length()); - return builder.take(); -} - -void SpdyFramer::SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers, - uint8_t* flags, - size_t* size, - SpdyString* hpack_encoding, - int* weight, - size_t* length_field) { - if (headers.fin()) { - *flags = *flags | CONTROL_FLAG_FIN; - } - // This will get overwritten if we overflow into a CONTINUATION frame. - *flags = *flags | HEADERS_FLAG_END_HEADERS; - if (headers.has_priority()) { - *flags = *flags | HEADERS_FLAG_PRIORITY; - } - if (headers.padded()) { - *flags = *flags | HEADERS_FLAG_PADDED; - } - - *size = kHeadersFrameMinimumSize; - - if (headers.padded()) { - *size = *size + kPadLengthFieldSize; - *size = *size + headers.padding_payload_len(); - } - - if (headers.has_priority()) { - *weight = ClampHttp2Weight(headers.weight()); - *size = *size + 5; - } - - GetHpackEncoder()->EncodeHeaderSet(headers.header_block(), hpack_encoding); - *size = *size + hpack_encoding->size(); - if (*size > kHttp2MaxControlFrameSendSize) { - *size = *size + GetNumberRequiredContinuationFrames(*size) * - kContinuationFrameMinimumSize; - *flags = *flags & ~HEADERS_FLAG_END_HEADERS; - } - // Compute frame length field. - if (headers.padded()) { - *length_field = *length_field + kPadLengthFieldSize; - } - if (headers.has_priority()) { - *length_field = *length_field + 4; // Dependency field. - *length_field = *length_field + 1; // Weight field. - } - *length_field = *length_field + headers.padding_payload_len(); - *length_field = *length_field + hpack_encoding->size(); - // If the HEADERS frame with payload would exceed the max frame size, then - // WritePayloadWithContinuation() will serialize CONTINUATION frames as - // necessary. - *length_field = - std::min(*length_field, kHttp2MaxControlFrameSendSize - kFrameHeaderSize); -} - -SpdySerializedFrame SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers) { - uint8_t flags = 0; - // The size of this frame, including padding (if there is any) and - // variable-length header block. - size_t size = 0; - SpdyString hpack_encoding; - int weight = 0; - size_t length_field = 0; - SerializeHeadersBuilderHelper(headers, &flags, &size, &hpack_encoding, - &weight, &length_field); - - SpdyFrameBuilder builder(size); - builder.BeginNewFrame(SpdyFrameType::HEADERS, flags, headers.stream_id(), - length_field); - - DCHECK_EQ(kHeadersFrameMinimumSize, builder.length()); - - int padding_payload_len = 0; - if (headers.padded()) { - builder.WriteUInt8(headers.padding_payload_len()); - padding_payload_len = headers.padding_payload_len(); - } - if (headers.has_priority()) { - builder.WriteUInt32(PackStreamDependencyValues(headers.exclusive(), - headers.parent_stream_id())); - // Per RFC 7540 section 6.3, serialized weight value is actual value - 1. - builder.WriteUInt8(weight - 1); - } - WritePayloadWithContinuation(&builder, hpack_encoding, headers.stream_id(), - SpdyFrameType::HEADERS, padding_payload_len); - - if (debug_visitor_) { - const size_t header_list_size = - GetUncompressedSerializedLength(headers.header_block()); - debug_visitor_->OnSendCompressedFrame(headers.stream_id(), - SpdyFrameType::HEADERS, - header_list_size, builder.length()); - } - - return builder.take(); -} - -SpdySerializedFrame SpdyFramer::SerializeWindowUpdate( - const SpdyWindowUpdateIR& window_update) { - SpdyFrameBuilder builder(kWindowUpdateFrameSize); - builder.BeginNewFrame(SpdyFrameType::WINDOW_UPDATE, kNoFlags, - window_update.stream_id()); - builder.WriteUInt32(window_update.delta()); - DCHECK_EQ(kWindowUpdateFrameSize, builder.length()); - return builder.take(); -} - -void SpdyFramer::SerializePushPromiseBuilderHelper( - const SpdyPushPromiseIR& push_promise, - uint8_t* flags, - SpdyString* hpack_encoding, - size_t* size) { - *flags = 0; - // This will get overwritten if we overflow into a CONTINUATION frame. - *flags = *flags | PUSH_PROMISE_FLAG_END_PUSH_PROMISE; - // The size of this frame, including variable-length name-value block. - *size = kPushPromiseFrameMinimumSize; - - if (push_promise.padded()) { - *flags = *flags | PUSH_PROMISE_FLAG_PADDED; - *size = *size + kPadLengthFieldSize; - *size = *size + push_promise.padding_payload_len(); - } - - GetHpackEncoder()->EncodeHeaderSet(push_promise.header_block(), - hpack_encoding); - *size = *size + hpack_encoding->size(); - if (*size > kHttp2MaxControlFrameSendSize) { - *size = *size + GetNumberRequiredContinuationFrames(*size) * - kContinuationFrameMinimumSize; - *flags = *flags & ~PUSH_PROMISE_FLAG_END_PUSH_PROMISE; - } -} - -SpdySerializedFrame SpdyFramer::SerializePushPromise( - const SpdyPushPromiseIR& push_promise) { - uint8_t flags = 0; - size_t size = 0; - SpdyString hpack_encoding; - SerializePushPromiseBuilderHelper(push_promise, &flags, &hpack_encoding, - &size); - - SpdyFrameBuilder builder(size); - size_t length = - std::min(size, kHttp2MaxControlFrameSendSize) - kFrameHeaderSize; - builder.BeginNewFrame(SpdyFrameType::PUSH_PROMISE, flags, - push_promise.stream_id(), length); - int padding_payload_len = 0; - if (push_promise.padded()) { - builder.WriteUInt8(push_promise.padding_payload_len()); - builder.WriteUInt32(push_promise.promised_stream_id()); - DCHECK_EQ(kPushPromiseFrameMinimumSize + kPadLengthFieldSize, - builder.length()); - - padding_payload_len = push_promise.padding_payload_len(); - } else { - builder.WriteUInt32(push_promise.promised_stream_id()); - DCHECK_EQ(kPushPromiseFrameMinimumSize, builder.length()); - } - - WritePayloadWithContinuation( - &builder, hpack_encoding, push_promise.stream_id(), - SpdyFrameType::PUSH_PROMISE, padding_payload_len); - - if (debug_visitor_) { - const size_t header_list_size = - GetUncompressedSerializedLength(push_promise.header_block()); - debug_visitor_->OnSendCompressedFrame(push_promise.stream_id(), - SpdyFrameType::PUSH_PROMISE, - header_list_size, builder.length()); - } - - return builder.take(); -} - -SpdySerializedFrame SpdyFramer::SerializeContinuation( - const SpdyContinuationIR& continuation) const { - const SpdyString& encoding = continuation.encoding(); - size_t frame_size = kContinuationFrameMinimumSize + encoding.size(); - SpdyFrameBuilder builder(frame_size); - uint8_t flags = continuation.end_headers() ? HEADERS_FLAG_END_HEADERS : 0; - builder.BeginNewFrame(SpdyFrameType::CONTINUATION, flags, - continuation.stream_id()); - DCHECK_EQ(kFrameHeaderSize, builder.length()); - - builder.WriteBytes(encoding.data(), encoding.size()); - return builder.take(); -} - -SpdySerializedFrame SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc_ir) { - SpdyString value; - size_t size = 0; - SerializeAltSvcBuilderHelper(altsvc_ir, &value, &size); - SpdyFrameBuilder builder(size); - builder.BeginNewFrame(SpdyFrameType::ALTSVC, kNoFlags, altsvc_ir.stream_id()); - - builder.WriteUInt16(altsvc_ir.origin().length()); - builder.WriteBytes(altsvc_ir.origin().data(), altsvc_ir.origin().length()); - builder.WriteBytes(value.data(), value.length()); - DCHECK_LT(kGetAltSvcFrameMinimumSize, builder.length()); - return builder.take(); -} - -SpdySerializedFrame SpdyFramer::SerializePriority( - const SpdyPriorityIR& priority) const { - SpdyFrameBuilder builder(kPriorityFrameSize); - builder.BeginNewFrame(SpdyFrameType::PRIORITY, kNoFlags, - priority.stream_id()); - - builder.WriteUInt32(PackStreamDependencyValues(priority.exclusive(), - priority.parent_stream_id())); - // Per RFC 7540 section 6.3, serialized weight value is actual value - 1. - builder.WriteUInt8(priority.weight() - 1); - DCHECK_EQ(kPriorityFrameSize, builder.length()); - return builder.take(); -} - -SpdySerializedFrame SpdyFramer::SerializeUnknown( - const SpdyUnknownIR& unknown) const { - const size_t total_size = kFrameHeaderSize + unknown.payload().size(); - SpdyFrameBuilder builder(total_size); - builder.BeginNewUncheckedFrame(unknown.type(), unknown.flags(), - unknown.stream_id(), unknown.length()); - builder.WriteBytes(unknown.payload().data(), unknown.payload().size()); - return builder.take(); -} - -namespace { - -class FrameSerializationVisitor : public SpdyFrameVisitor { - public: - explicit FrameSerializationVisitor(SpdyFramer* framer) - : framer_(framer), frame_() {} - ~FrameSerializationVisitor() override = default; - - SpdySerializedFrame ReleaseSerializedFrame() { return std::move(frame_); } - - void VisitData(const SpdyDataIR& data) override { - frame_ = framer_->SerializeData(data); - } - void VisitRstStream(const SpdyRstStreamIR& rst_stream) override { - frame_ = framer_->SerializeRstStream(rst_stream); - } - void VisitSettings(const SpdySettingsIR& settings) override { - frame_ = framer_->SerializeSettings(settings); - } - void VisitPing(const SpdyPingIR& ping) override { - frame_ = framer_->SerializePing(ping); - } - void VisitGoAway(const SpdyGoAwayIR& goaway) override { - frame_ = framer_->SerializeGoAway(goaway); - } - void VisitHeaders(const SpdyHeadersIR& headers) override { - frame_ = framer_->SerializeHeaders(headers); - } - void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) override { - frame_ = framer_->SerializeWindowUpdate(window_update); - } - void VisitPushPromise(const SpdyPushPromiseIR& push_promise) override { - frame_ = framer_->SerializePushPromise(push_promise); - } - void VisitContinuation(const SpdyContinuationIR& continuation) override { - frame_ = framer_->SerializeContinuation(continuation); - } - void VisitAltSvc(const SpdyAltSvcIR& altsvc) override { - frame_ = framer_->SerializeAltSvc(altsvc); - } - void VisitPriority(const SpdyPriorityIR& priority) override { - frame_ = framer_->SerializePriority(priority); - } - void VisitUnknown(const SpdyUnknownIR& unknown) override { - frame_ = framer_->SerializeUnknown(unknown); - } - - private: - SpdyFramer* framer_; - SpdySerializedFrame frame_; -}; - -// TODO(diannahu): Use also in frame serialization. -class FlagsSerializationVisitor : public SpdyFrameVisitor { - public: - void VisitData(const SpdyDataIR& data) override { - flags_ = DATA_FLAG_NONE; - if (data.fin()) { - flags_ |= DATA_FLAG_FIN; - } - if (data.padded()) { - flags_ |= DATA_FLAG_PADDED; - } - } - - void VisitRstStream(const SpdyRstStreamIR& rst_stream) override { - flags_ = kNoFlags; - } - - void VisitSettings(const SpdySettingsIR& settings) override { - flags_ = kNoFlags; - if (settings.is_ack()) { - flags_ |= SETTINGS_FLAG_ACK; - } - } - - void VisitPing(const SpdyPingIR& ping) override { - flags_ = kNoFlags; - if (ping.is_ack()) { - flags_ |= PING_FLAG_ACK; - } - } - - void VisitGoAway(const SpdyGoAwayIR& goaway) override { flags_ = kNoFlags; } - - // TODO(diannahu): The END_HEADERS flag is incorrect for HEADERS that require - // CONTINUATION frames. - void VisitHeaders(const SpdyHeadersIR& headers) override { - flags_ = HEADERS_FLAG_END_HEADERS; - if (headers.fin()) { - flags_ |= CONTROL_FLAG_FIN; - } - if (headers.padded()) { - flags_ |= HEADERS_FLAG_PADDED; - } - if (headers.has_priority()) { - flags_ |= HEADERS_FLAG_PRIORITY; - } - } - - void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) override { - flags_ = kNoFlags; - } - - // TODO(diannahu): The END_PUSH_PROMISE flag is incorrect for PUSH_PROMISEs - // that require CONTINUATION frames. - void VisitPushPromise(const SpdyPushPromiseIR& push_promise) override { - flags_ = PUSH_PROMISE_FLAG_END_PUSH_PROMISE; - if (push_promise.padded()) { - flags_ |= PUSH_PROMISE_FLAG_PADDED; - } - } - - // TODO(diannahu): The END_HEADERS flag is incorrect for CONTINUATIONs that - // require CONTINUATION frames. - void VisitContinuation(const SpdyContinuationIR& continuation) override { - flags_ = HEADERS_FLAG_END_HEADERS; - } - - void VisitAltSvc(const SpdyAltSvcIR& altsvc) override { flags_ = kNoFlags; } - - void VisitPriority(const SpdyPriorityIR& priority) override { - flags_ = kNoFlags; - } - - uint8_t flags() const { return flags_; } - - private: - uint8_t flags_ = kNoFlags; -}; - -} // namespace - -SpdySerializedFrame SpdyFramer::SerializeFrame(const SpdyFrameIR& frame) { - FrameSerializationVisitor visitor(this); - frame.Visit(&visitor); - return visitor.ReleaseSerializedFrame(); -} - -uint8_t SpdyFramer::GetSerializedFlags(const SpdyFrameIR& frame) { - FlagsSerializationVisitor visitor; - frame.Visit(&visitor); - return visitor.flags(); -} - -bool SpdyFramer::SerializeData(const SpdyDataIR& data_ir, - ZeroCopyOutputBuffer* output) const { - uint8_t flags = DATA_FLAG_NONE; - int num_padding_fields = 0; - size_t size_with_padding = 0; - SerializeDataBuilderHelper(data_ir, &flags, &num_padding_fields, - &size_with_padding); - SpdyFrameBuilder builder(size_with_padding, output); - - bool ok = - builder.BeginNewFrame(SpdyFrameType::DATA, flags, data_ir.stream_id()); - - if (data_ir.padded()) { - ok = ok && builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); - } - - ok = ok && builder.WriteBytes(data_ir.data(), data_ir.data_len()); - if (data_ir.padding_payload_len() > 0) { - SpdyString padding; - padding = SpdyString(data_ir.padding_payload_len(), 0); - ok = ok && builder.WriteBytes(padding.data(), padding.length()); - } - DCHECK_EQ(size_with_padding, builder.length()); - return ok; -} - -bool SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField( - const SpdyDataIR& data_ir, - ZeroCopyOutputBuffer* output) const { - uint8_t flags = DATA_FLAG_NONE; - size_t frame_size = 0; - size_t num_padding_fields = 0; - SerializeDataFrameHeaderWithPaddingLengthFieldBuilderHelper( - data_ir, &flags, &frame_size, &num_padding_fields); - - SpdyFrameBuilder builder(frame_size, output); - bool ok = true; - ok = ok && - builder.BeginNewFrame(SpdyFrameType::DATA, flags, data_ir.stream_id(), - num_padding_fields + data_ir.data_len() + - data_ir.padding_payload_len()); - if (data_ir.padded()) { - ok = ok && builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); - } - DCHECK_EQ(frame_size, builder.length()); - return ok; -} - -bool SpdyFramer::SerializeRstStream(const SpdyRstStreamIR& rst_stream, - ZeroCopyOutputBuffer* output) const { - size_t expected_length = kRstStreamFrameSize; - SpdyFrameBuilder builder(expected_length, output); - bool ok = builder.BeginNewFrame(SpdyFrameType::RST_STREAM, 0, - rst_stream.stream_id()); - ok = ok && builder.WriteUInt32(rst_stream.error_code()); - - DCHECK_EQ(expected_length, builder.length()); - return ok; -} - -bool SpdyFramer::SerializeSettings(const SpdySettingsIR& settings, - ZeroCopyOutputBuffer* output) const { - uint8_t flags = 0; - // Size, in bytes, of this SETTINGS frame. - size_t size = 0; - const SettingsMap* values = &(settings.values()); - SerializeSettingsBuilderHelper(settings, &flags, values, &size); - SpdyFrameBuilder builder(size, output); - bool ok = builder.BeginNewFrame(SpdyFrameType::SETTINGS, flags, 0); - - // If this is an ACK, payload should be empty. - if (settings.is_ack()) { - return ok; - } - - DCHECK_EQ(kSettingsFrameMinimumSize, builder.length()); - for (auto it = values->begin(); it != values->end(); ++it) { - int setting_id = it->first; - DCHECK_GE(setting_id, 0); - ok = ok && builder.WriteUInt16(static_cast<SpdySettingsId>(setting_id)) && - builder.WriteUInt32(it->second); - } - DCHECK_EQ(size, builder.length()); - return ok; -} - -bool SpdyFramer::SerializePing(const SpdyPingIR& ping, - ZeroCopyOutputBuffer* output) const { - SpdyFrameBuilder builder(kPingFrameSize, output); - uint8_t flags = 0; - if (ping.is_ack()) { - flags |= PING_FLAG_ACK; - } - bool ok = builder.BeginNewFrame(SpdyFrameType::PING, flags, 0); - ok = ok && builder.WriteUInt64(ping.id()); - DCHECK_EQ(kPingFrameSize, builder.length()); - return ok; -} - -bool SpdyFramer::SerializeGoAway(const SpdyGoAwayIR& goaway, - ZeroCopyOutputBuffer* output) const { - // Compute the output buffer size, take opaque data into account. - size_t expected_length = kGoawayFrameMinimumSize; - expected_length += goaway.description().size(); - SpdyFrameBuilder builder(expected_length, output); - - // Serialize the GOAWAY frame. - bool ok = builder.BeginNewFrame(SpdyFrameType::GOAWAY, 0, 0); - - // GOAWAY frames specify the last good stream id. - ok = ok && builder.WriteUInt32(goaway.last_good_stream_id()) && - // GOAWAY frames also specify the error status code. - builder.WriteUInt32(goaway.error_code()); - - // GOAWAY frames may also specify opaque data. - if (!goaway.description().empty()) { - ok = ok && builder.WriteBytes(goaway.description().data(), - goaway.description().size()); - } - - DCHECK_EQ(expected_length, builder.length()); - return ok; -} - -bool SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers, - ZeroCopyOutputBuffer* output) { - uint8_t flags = 0; - // The size of this frame, including padding (if there is any) and - // variable-length header block. - size_t size = 0; - SpdyString hpack_encoding; - int weight = 0; - size_t length_field = 0; - SerializeHeadersBuilderHelper(headers, &flags, &size, &hpack_encoding, - &weight, &length_field); - - bool ok = true; - SpdyFrameBuilder builder(size, output); - ok = ok && builder.BeginNewFrame(SpdyFrameType::HEADERS, flags, - headers.stream_id(), length_field); - DCHECK_EQ(kHeadersFrameMinimumSize, builder.length()); - - int padding_payload_len = 0; - if (headers.padded()) { - ok = ok && builder.WriteUInt8(headers.padding_payload_len()); - padding_payload_len = headers.padding_payload_len(); - } - if (headers.has_priority()) { - ok = ok && - builder.WriteUInt32(PackStreamDependencyValues( - headers.exclusive(), headers.parent_stream_id())) && - // Per RFC 7540 section 6.3, serialized weight value is weight - 1. - builder.WriteUInt8(weight - 1); - } - ok = ok && WritePayloadWithContinuation( - &builder, hpack_encoding, headers.stream_id(), - SpdyFrameType::HEADERS, padding_payload_len); - - if (debug_visitor_) { - const size_t header_list_size = - GetUncompressedSerializedLength(headers.header_block()); - debug_visitor_->OnSendCompressedFrame(headers.stream_id(), - SpdyFrameType::HEADERS, - header_list_size, builder.length()); - } - - return ok; -} - -bool SpdyFramer::SerializeWindowUpdate(const SpdyWindowUpdateIR& window_update, - ZeroCopyOutputBuffer* output) const { - SpdyFrameBuilder builder(kWindowUpdateFrameSize, output); - bool ok = builder.BeginNewFrame(SpdyFrameType::WINDOW_UPDATE, kNoFlags, - window_update.stream_id()); - ok = ok && builder.WriteUInt32(window_update.delta()); - DCHECK_EQ(kWindowUpdateFrameSize, builder.length()); - return ok; -} - -bool SpdyFramer::SerializePushPromise(const SpdyPushPromiseIR& push_promise, - ZeroCopyOutputBuffer* output) { - uint8_t flags = 0; - size_t size = 0; - SpdyString hpack_encoding; - SerializePushPromiseBuilderHelper(push_promise, &flags, &hpack_encoding, - &size); - - bool ok = true; - SpdyFrameBuilder builder(size, output); - size_t length = - std::min(size, kHttp2MaxControlFrameSendSize) - kFrameHeaderSize; - ok = builder.BeginNewFrame(SpdyFrameType::PUSH_PROMISE, flags, - push_promise.stream_id(), length); - - int padding_payload_len = 0; - if (push_promise.padded()) { - ok = ok && builder.WriteUInt8(push_promise.padding_payload_len()) && - builder.WriteUInt32(push_promise.promised_stream_id()); - DCHECK_EQ(kPushPromiseFrameMinimumSize + kPadLengthFieldSize, - builder.length()); - - padding_payload_len = push_promise.padding_payload_len(); - } else { - ok = ok && builder.WriteUInt32(push_promise.promised_stream_id()); - DCHECK_EQ(kPushPromiseFrameMinimumSize, builder.length()); - } - - ok = ok && WritePayloadWithContinuation( - &builder, hpack_encoding, push_promise.stream_id(), - SpdyFrameType::PUSH_PROMISE, padding_payload_len); - - if (debug_visitor_) { - const size_t header_list_size = - GetUncompressedSerializedLength(push_promise.header_block()); - debug_visitor_->OnSendCompressedFrame(push_promise.stream_id(), - SpdyFrameType::PUSH_PROMISE, - header_list_size, builder.length()); - } - - return ok; -} - -bool SpdyFramer::SerializeContinuation(const SpdyContinuationIR& continuation, - ZeroCopyOutputBuffer* output) const { - const SpdyString& encoding = continuation.encoding(); - size_t frame_size = kContinuationFrameMinimumSize + encoding.size(); - SpdyFrameBuilder builder(frame_size, output); - uint8_t flags = continuation.end_headers() ? HEADERS_FLAG_END_HEADERS : 0; - bool ok = builder.BeginNewFrame(SpdyFrameType::CONTINUATION, flags, - continuation.stream_id(), - frame_size - kFrameHeaderSize); - DCHECK_EQ(kFrameHeaderSize, builder.length()); - - ok = ok && builder.WriteBytes(encoding.data(), encoding.size()); - return ok; -} - -bool SpdyFramer::SerializeAltSvc(const SpdyAltSvcIR& altsvc_ir, - ZeroCopyOutputBuffer* output) { - SpdyString value; - size_t size = 0; - SerializeAltSvcBuilderHelper(altsvc_ir, &value, &size); - SpdyFrameBuilder builder(size, output); - bool ok = builder.BeginNewFrame(SpdyFrameType::ALTSVC, kNoFlags, - altsvc_ir.stream_id()) && - builder.WriteUInt16(altsvc_ir.origin().length()) && - builder.WriteBytes(altsvc_ir.origin().data(), - altsvc_ir.origin().length()) && - builder.WriteBytes(value.data(), value.length()); - DCHECK_LT(kGetAltSvcFrameMinimumSize, builder.length()); - return ok; -} - -bool SpdyFramer::SerializePriority(const SpdyPriorityIR& priority, - ZeroCopyOutputBuffer* output) const { - SpdyFrameBuilder builder(kPriorityFrameSize, output); - bool ok = builder.BeginNewFrame(SpdyFrameType::PRIORITY, kNoFlags, - priority.stream_id()); - ok = ok && - builder.WriteUInt32(PackStreamDependencyValues( - priority.exclusive(), priority.parent_stream_id())) && - // Per RFC 7540 section 6.3, serialized weight value is actual value - 1. - builder.WriteUInt8(priority.weight() - 1); - DCHECK_EQ(kPriorityFrameSize, builder.length()); - return ok; -} - -bool SpdyFramer::SerializeUnknown(const SpdyUnknownIR& unknown, - ZeroCopyOutputBuffer* output) const { - const size_t total_size = kFrameHeaderSize + unknown.payload().size(); - SpdyFrameBuilder builder(total_size, output); - bool ok = builder.BeginNewUncheckedFrame( - unknown.type(), unknown.flags(), unknown.stream_id(), unknown.length()); - ok = ok && - builder.WriteBytes(unknown.payload().data(), unknown.payload().size()); - return ok; -} - -namespace { - -class FrameSerializationVisitorWithOutput : public SpdyFrameVisitor { - public: - explicit FrameSerializationVisitorWithOutput(SpdyFramer* framer, - ZeroCopyOutputBuffer* output) - : framer_(framer), output_(output), result_(false) {} - ~FrameSerializationVisitorWithOutput() override = default; - - size_t Result() { return result_; } - - void VisitData(const SpdyDataIR& data) override { - result_ = framer_->SerializeData(data, output_); - } - void VisitRstStream(const SpdyRstStreamIR& rst_stream) override { - result_ = framer_->SerializeRstStream(rst_stream, output_); - } - void VisitSettings(const SpdySettingsIR& settings) override { - result_ = framer_->SerializeSettings(settings, output_); - } - void VisitPing(const SpdyPingIR& ping) override { - result_ = framer_->SerializePing(ping, output_); - } - void VisitGoAway(const SpdyGoAwayIR& goaway) override { - result_ = framer_->SerializeGoAway(goaway, output_); - } - void VisitHeaders(const SpdyHeadersIR& headers) override { - result_ = framer_->SerializeHeaders(headers, output_); - } - void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) override { - result_ = framer_->SerializeWindowUpdate(window_update, output_); - } - void VisitPushPromise(const SpdyPushPromiseIR& push_promise) override { - result_ = framer_->SerializePushPromise(push_promise, output_); - } - void VisitContinuation(const SpdyContinuationIR& continuation) override { - result_ = framer_->SerializeContinuation(continuation, output_); - } - void VisitAltSvc(const SpdyAltSvcIR& altsvc) override { - result_ = framer_->SerializeAltSvc(altsvc, output_); - } - void VisitPriority(const SpdyPriorityIR& priority) override { - result_ = framer_->SerializePriority(priority, output_); - } - void VisitUnknown(const SpdyUnknownIR& unknown) override { - result_ = framer_->SerializeUnknown(unknown, output_); - } - - private: - SpdyFramer* framer_; - ZeroCopyOutputBuffer* output_; - bool result_; -}; - -} // namespace - -size_t SpdyFramer::SerializeFrame(const SpdyFrameIR& frame, - ZeroCopyOutputBuffer* output) { - FrameSerializationVisitorWithOutput visitor(this, output); - size_t free_bytes_before = output->BytesFree(); - frame.Visit(&visitor); - return visitor.Result() ? free_bytes_before - output->BytesFree() : 0; -} - -HpackEncoder* SpdyFramer::GetHpackEncoder() { - if (hpack_encoder_ == nullptr) { - hpack_encoder_ = SpdyMakeUnique<HpackEncoder>(ObtainHpackHuffmanTable()); - if (!compression_enabled()) { - hpack_encoder_->DisableCompression(); - } - } - return hpack_encoder_.get(); -} - -void SpdyFramer::UpdateHeaderEncoderTableSize(uint32_t value) { - GetHpackEncoder()->ApplyHeaderTableSizeSetting(value); -} - -size_t SpdyFramer::header_encoder_table_size() const { - if (hpack_encoder_ == nullptr) { - return kDefaultHeaderTableSizeSetting; - } else { - return hpack_encoder_->CurrentHeaderTableSizeSetting(); - } -} - -void SpdyFramer::SetEncoderHeaderTableDebugVisitor( - std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) { - GetHpackEncoder()->SetHeaderTableDebugVisitor(std::move(visitor)); -} - -size_t SpdyFramer::EstimateMemoryUsage() const { - return SpdyEstimateMemoryUsage(hpack_encoder_); -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_framer.h b/net/third_party/spdy/core/spdy_framer.h deleted file mode 100644 index 215ad03..0000000 --- a/net/third_party/spdy/core/spdy_framer.h +++ /dev/null
@@ -1,365 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_FRAMER_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_FRAMER_H_ - -#include <stddef.h> - -#include <cstdint> -#include <map> -#include <memory> -#include <utility> - -#include "net/third_party/spdy/core/hpack/hpack_encoder.h" -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_headers_handler_interface.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/zero_copy_output_buffer.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { - -namespace test { - -class SpdyFramerPeer; -class SpdyFramerTest_MultipleContinuationFramesWithIterator_Test; -class SpdyFramerTest_PushPromiseFramesWithIterator_Test; - -} // namespace test - -class SPDY_EXPORT_PRIVATE SpdyFrameSequence { - public: - virtual ~SpdyFrameSequence() {} - - // Serializes the next frame in the sequence to |output|. Returns the number - // of bytes written to |output|. - virtual size_t NextFrame(ZeroCopyOutputBuffer* output) = 0; - - // Returns true iff there is at least one more frame in the sequence. - virtual bool HasNextFrame() const = 0; - - // Get SpdyFrameIR of the frame to be serialized. - virtual const SpdyFrameIR& GetIR() const = 0; -}; - -class SPDY_EXPORT_PRIVATE SpdyFramer { - public: - enum CompressionOption { - ENABLE_COMPRESSION, - DISABLE_COMPRESSION, - }; - - // Create a SpdyFrameSequence to serialize |frame_ir|. - static std::unique_ptr<SpdyFrameSequence> CreateIterator( - SpdyFramer* framer, - std::unique_ptr<const SpdyFrameIR> frame_ir); - - // Gets the serialized flags for the given |frame|. - static uint8_t GetSerializedFlags(const SpdyFrameIR& frame); - - // Serialize a data frame. - static SpdySerializedFrame SerializeData(const SpdyDataIR& data_ir); - // Serializes the data frame header and optionally padding length fields, - // excluding actual data payload and padding. - static SpdySerializedFrame SerializeDataFrameHeaderWithPaddingLengthField( - const SpdyDataIR& data_ir); - - // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE - // frame is used to implement per stream flow control. - static SpdySerializedFrame SerializeWindowUpdate( - const SpdyWindowUpdateIR& window_update); - - explicit SpdyFramer(CompressionOption option); - - virtual ~SpdyFramer(); - - // Set debug callbacks to be called from the framer. The debug visitor is - // completely optional and need not be set in order for normal operation. - // If this is called multiple times, only the last visitor will be used. - void set_debug_visitor(SpdyFramerDebugVisitorInterface* debug_visitor); - - SpdySerializedFrame SerializeRstStream( - const SpdyRstStreamIR& rst_stream) const; - - // Serializes a SETTINGS frame. The SETTINGS frame is - // used to communicate name/value pairs relevant to the communication channel. - SpdySerializedFrame SerializeSettings(const SpdySettingsIR& settings) const; - - // Serializes a PING frame. The unique_id is used to - // identify the ping request/response. - SpdySerializedFrame SerializePing(const SpdyPingIR& ping) const; - - // Serializes a GOAWAY frame. The GOAWAY frame is used - // prior to the shutting down of the TCP connection, and includes the - // stream_id of the last stream the sender of the frame is willing to process - // to completion. - SpdySerializedFrame SerializeGoAway(const SpdyGoAwayIR& goaway) const; - - // Serializes a HEADERS frame. The HEADERS frame is used - // for sending headers. - SpdySerializedFrame SerializeHeaders(const SpdyHeadersIR& headers); - - // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used - // to inform the client that it will be receiving an additional stream - // in response to the original request. The frame includes synthesized - // headers to explain the upcoming data. - SpdySerializedFrame SerializePushPromise( - const SpdyPushPromiseIR& push_promise); - - // Serializes a CONTINUATION frame. The CONTINUATION frame is used - // to continue a sequence of header block fragments. - SpdySerializedFrame SerializeContinuation( - const SpdyContinuationIR& continuation) const; - - // Serializes an ALTSVC frame. The ALTSVC frame advertises the - // availability of an alternative service to the client. - SpdySerializedFrame SerializeAltSvc(const SpdyAltSvcIR& altsvc); - - // Serializes a PRIORITY frame. The PRIORITY frame advises a change in - // the relative priority of the given stream. - SpdySerializedFrame SerializePriority(const SpdyPriorityIR& priority) const; - - // Serializes an unknown frame given a frame header and payload. - SpdySerializedFrame SerializeUnknown(const SpdyUnknownIR& unknown) const; - - // Serialize a frame of unknown type. - SpdySerializedFrame SerializeFrame(const SpdyFrameIR& frame); - - // Serialize a data frame. - bool SerializeData(const SpdyDataIR& data, - ZeroCopyOutputBuffer* output) const; - - // Serializes the data frame header and optionally padding length fields, - // excluding actual data payload and padding. - bool SerializeDataFrameHeaderWithPaddingLengthField( - const SpdyDataIR& data, - ZeroCopyOutputBuffer* output) const; - - bool SerializeRstStream(const SpdyRstStreamIR& rst_stream, - ZeroCopyOutputBuffer* output) const; - - // Serializes a SETTINGS frame. The SETTINGS frame is - // used to communicate name/value pairs relevant to the communication channel. - bool SerializeSettings(const SpdySettingsIR& settings, - ZeroCopyOutputBuffer* output) const; - - // Serializes a PING frame. The unique_id is used to - // identify the ping request/response. - bool SerializePing(const SpdyPingIR& ping, - ZeroCopyOutputBuffer* output) const; - - // Serializes a GOAWAY frame. The GOAWAY frame is used - // prior to the shutting down of the TCP connection, and includes the - // stream_id of the last stream the sender of the frame is willing to process - // to completion. - bool SerializeGoAway(const SpdyGoAwayIR& goaway, - ZeroCopyOutputBuffer* output) const; - - // Serializes a HEADERS frame. The HEADERS frame is used - // for sending headers. - bool SerializeHeaders(const SpdyHeadersIR& headers, - ZeroCopyOutputBuffer* output); - - // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE - // frame is used to implement per stream flow control. - bool SerializeWindowUpdate(const SpdyWindowUpdateIR& window_update, - ZeroCopyOutputBuffer* output) const; - - // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used - // to inform the client that it will be receiving an additional stream - // in response to the original request. The frame includes synthesized - // headers to explain the upcoming data. - bool SerializePushPromise(const SpdyPushPromiseIR& push_promise, - ZeroCopyOutputBuffer* output); - - // Serializes a CONTINUATION frame. The CONTINUATION frame is used - // to continue a sequence of header block fragments. - bool SerializeContinuation(const SpdyContinuationIR& continuation, - ZeroCopyOutputBuffer* output) const; - - // Serializes an ALTSVC frame. The ALTSVC frame advertises the - // availability of an alternative service to the client. - bool SerializeAltSvc(const SpdyAltSvcIR& altsvc, - ZeroCopyOutputBuffer* output); - - // Serializes a PRIORITY frame. The PRIORITY frame advises a change in - // the relative priority of the given stream. - bool SerializePriority(const SpdyPriorityIR& priority, - ZeroCopyOutputBuffer* output) const; - - // Serializes an unknown frame given a frame header and payload. - bool SerializeUnknown(const SpdyUnknownIR& unknown, - ZeroCopyOutputBuffer* output) const; - - // Serialize a frame of unknown type. - size_t SerializeFrame(const SpdyFrameIR& frame, ZeroCopyOutputBuffer* output); - - // Returns whether this SpdyFramer will compress header blocks using HPACK. - bool compression_enabled() const { - return compression_option_ == ENABLE_COMPRESSION; - } - - void SetHpackIndexingPolicy(HpackEncoder::IndexingPolicy policy) { - GetHpackEncoder()->SetIndexingPolicy(std::move(policy)); - } - - // Updates the maximum size of the header encoder compression table. - void UpdateHeaderEncoderTableSize(uint32_t value); - - // Returns the maximum size of the header encoder compression table. - size_t header_encoder_table_size() const; - - void SetEncoderHeaderTableDebugVisitor( - std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor); - - // Get (and lazily initialize) the HPACK encoder state. - HpackEncoder* GetHpackEncoder(); - - // Returns the estimate of dynamically allocated memory in bytes. - size_t EstimateMemoryUsage() const; - - protected: - friend class test::SpdyFramerPeer; - friend class test::SpdyFramerTest_MultipleContinuationFramesWithIterator_Test; - friend class test::SpdyFramerTest_PushPromiseFramesWithIterator_Test; - - // Iteratively converts a SpdyFrameIR into an appropriate sequence of Spdy - // frames. - // Example usage: - // std::unique_ptr<SpdyFrameSequence> it = CreateIterator(framer, frame_ir); - // while (it->HasNextFrame()) { - // if(it->NextFrame(output) == 0) { - // // Write failed; - // } - // } - class SPDY_EXPORT_PRIVATE SpdyFrameIterator : public SpdyFrameSequence { - public: - // Creates an iterator with the provided framer. - // Does not take ownership of |framer|. - // |framer| must outlive this instance. - explicit SpdyFrameIterator(SpdyFramer* framer); - ~SpdyFrameIterator() override; - - // Serializes the next frame in the sequence to |output|. Returns the number - // of bytes written to |output|. - size_t NextFrame(ZeroCopyOutputBuffer* output) override; - - // Returns true iff there is at least one more frame in the sequence. - bool HasNextFrame() const override; - - // SpdyFrameIterator is neither copyable nor movable. - SpdyFrameIterator(const SpdyFrameIterator&) = delete; - SpdyFrameIterator& operator=(const SpdyFrameIterator&) = delete; - - protected: - virtual size_t GetFrameSizeSansBlock() const = 0; - virtual bool SerializeGivenEncoding(const SpdyString& encoding, - ZeroCopyOutputBuffer* output) const = 0; - - SpdyFramer* GetFramer() const { return framer_; } - - void SetEncoder(const SpdyFrameWithHeaderBlockIR* ir) { - encoder_ = - framer_->GetHpackEncoder()->EncodeHeaderSet(ir->header_block()); - } - - bool has_next_frame() const { return has_next_frame_; } - - private: - SpdyFramer* const framer_; - std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoder_; - bool is_first_frame_; - bool has_next_frame_; - }; - - // Iteratively converts a SpdyHeadersIR (with a possibly huge - // SpdyHeaderBlock) into an appropriate sequence of SpdySerializedFrames, and - // write to the output. - class SPDY_EXPORT_PRIVATE SpdyHeaderFrameIterator : public SpdyFrameIterator { - public: - // Does not take ownership of |framer|. Take ownership of |headers_ir|. - SpdyHeaderFrameIterator(SpdyFramer* framer, - std::unique_ptr<const SpdyHeadersIR> headers_ir); - - ~SpdyHeaderFrameIterator() override; - - private: - const SpdyFrameIR& GetIR() const override; - size_t GetFrameSizeSansBlock() const override; - bool SerializeGivenEncoding(const SpdyString& encoding, - ZeroCopyOutputBuffer* output) const override; - - const std::unique_ptr<const SpdyHeadersIR> headers_ir_; - }; - - // Iteratively converts a SpdyPushPromiseIR (with a possibly huge - // SpdyHeaderBlock) into an appropriate sequence of SpdySerializedFrames, and - // write to the output. - class SPDY_EXPORT_PRIVATE SpdyPushPromiseFrameIterator - : public SpdyFrameIterator { - public: - // Does not take ownership of |framer|. Take ownership of |push_promise_ir|. - SpdyPushPromiseFrameIterator( - SpdyFramer* framer, - std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir); - - ~SpdyPushPromiseFrameIterator() override; - - private: - const SpdyFrameIR& GetIR() const override; - size_t GetFrameSizeSansBlock() const override; - bool SerializeGivenEncoding(const SpdyString& encoding, - ZeroCopyOutputBuffer* output) const override; - - const std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir_; - }; - - // Converts a SpdyFrameIR into one Spdy frame (a sequence of length 1), and - // write it to the output. - class SPDY_EXPORT_PRIVATE SpdyControlFrameIterator - : public SpdyFrameSequence { - public: - SpdyControlFrameIterator(SpdyFramer* framer, - std::unique_ptr<const SpdyFrameIR> frame_ir); - ~SpdyControlFrameIterator() override; - - size_t NextFrame(ZeroCopyOutputBuffer* output) override; - - bool HasNextFrame() const override; - - const SpdyFrameIR& GetIR() const override; - - private: - SpdyFramer* const framer_; - std::unique_ptr<const SpdyFrameIR> frame_ir_; - bool has_next_frame_ = true; - }; - - private: - void SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers, - uint8_t* flags, - size_t* size, - SpdyString* hpack_encoding, - int* weight, - size_t* length_field); - void SerializePushPromiseBuilderHelper(const SpdyPushPromiseIR& push_promise, - uint8_t* flags, - SpdyString* hpack_encoding, - size_t* size); - - std::unique_ptr<HpackEncoder> hpack_encoder_; - - SpdyFramerDebugVisitorInterface* debug_visitor_; - - // Determines whether HPACK compression is used. - const CompressionOption compression_option_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_FRAMER_H_
diff --git a/net/third_party/spdy/core/spdy_framer_test.cc b/net/third_party/spdy/core/spdy_framer_test.cc deleted file mode 100644 index f3d5dc3..0000000 --- a/net/third_party/spdy/core/spdy_framer_test.cc +++ /dev/null
@@ -1,4833 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_framer.h" - -#include <stdlib.h> - -#include <algorithm> -#include <cstdint> -#include <limits> -#include <tuple> -#include <vector> - -#include "base/logging.h" -#include "base/macros.h" -#include "net/third_party/spdy/core/array_output_buffer.h" -#include "net/third_party/spdy/core/hpack/hpack_constants.h" -#include "net/third_party/spdy/core/mock_spdy_framer_visitor.h" -#include "net/third_party/spdy/core/spdy_bitmasks.h" -#include "net/third_party/spdy/core/spdy_frame_builder.h" -#include "net/third_party/spdy/core/spdy_frame_reader.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" -#include "net/third_party/spdy/platform/api/spdy_arraysize.h" -#include "net/third_party/spdy/platform/api/spdy_flags.h" -#include "net/third_party/spdy/platform/api/spdy_ptr_util.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::http2::Http2DecoderAdapter; -using ::testing::_; - -namespace spdy { - -namespace test { - -namespace { - -const int64_t kSize = 1024 * 1024; -char output_buffer[kSize] = ""; - -// frame_list_char is used to hold frames to be compared with output_buffer. -const int64_t buffer_size = 64 * 1024; -char frame_list_char[buffer_size] = ""; -} // namespace - -class MockDebugVisitor : public SpdyFramerDebugVisitorInterface { - public: - MOCK_METHOD4(OnSendCompressedFrame, - void(SpdyStreamId stream_id, - SpdyFrameType type, - size_t payload_len, - size_t frame_len)); - - MOCK_METHOD3(OnReceiveCompressedFrame, - void(SpdyStreamId stream_id, - SpdyFrameType type, - size_t frame_len)); -}; - -MATCHER_P(IsFrameUnionOf, frame_list, "") { - size_t size_verified = 0; - for (const auto& frame : *frame_list) { - if (arg.size() < size_verified + frame.size()) { - LOG(FATAL) << "Incremental header serialization should not lead to a " - << "higher total frame length than non-incremental method."; - return false; - } - if (memcmp(arg.data() + size_verified, frame.data(), frame.size())) { - CompareCharArraysWithHexError( - "Header serialization methods should be equivalent: ", - reinterpret_cast<unsigned char*>(arg.data() + size_verified), - frame.size(), reinterpret_cast<unsigned char*>(frame.data()), - frame.size()); - return false; - } - size_verified += frame.size(); - } - return size_verified == arg.size(); -} - -class SpdyFramerPeer { - public: - // TODO(dahollings): Remove these methods when deprecating non-incremental - // header serialization path. - static std::unique_ptr<SpdyHeadersIR> CloneSpdyHeadersIR( - const SpdyHeadersIR& headers) { - auto new_headers = SpdyMakeUnique<SpdyHeadersIR>( - headers.stream_id(), headers.header_block().Clone()); - new_headers->set_fin(headers.fin()); - new_headers->set_has_priority(headers.has_priority()); - new_headers->set_weight(headers.weight()); - new_headers->set_parent_stream_id(headers.parent_stream_id()); - new_headers->set_exclusive(headers.exclusive()); - if (headers.padded()) { - new_headers->set_padding_len(headers.padding_payload_len() + 1); - } - return new_headers; - } - - static SpdySerializedFrame SerializeHeaders(SpdyFramer* framer, - const SpdyHeadersIR& headers) { - SpdySerializedFrame serialized_headers_old_version( - framer->SerializeHeaders(headers)); - framer->hpack_encoder_.reset(nullptr); - auto* saved_debug_visitor = framer->debug_visitor_; - framer->debug_visitor_ = nullptr; - - std::vector<SpdySerializedFrame> frame_list; - ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size); - SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers)); - while (it.HasNextFrame()) { - size_t size_before = frame_list_buffer.Size(); - EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u); - frame_list.emplace_back( - SpdySerializedFrame(frame_list_buffer.Begin() + size_before, - frame_list_buffer.Size() - size_before, false)); - } - framer->debug_visitor_ = saved_debug_visitor; - - EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list)); - return serialized_headers_old_version; - } - - static SpdySerializedFrame SerializeHeaders(SpdyFramer* framer, - const SpdyHeadersIR& headers, - ArrayOutputBuffer* output) { - if (output == nullptr) { - return SerializeHeaders(framer, headers); - } - output->Reset(); - EXPECT_TRUE(framer->SerializeHeaders(headers, output)); - SpdySerializedFrame serialized_headers_old_version(output->Begin(), - output->Size(), false); - framer->hpack_encoder_.reset(nullptr); - auto* saved_debug_visitor = framer->debug_visitor_; - framer->debug_visitor_ = nullptr; - - std::vector<SpdySerializedFrame> frame_list; - ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size); - SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers)); - while (it.HasNextFrame()) { - size_t size_before = frame_list_buffer.Size(); - EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u); - frame_list.emplace_back( - SpdySerializedFrame(frame_list_buffer.Begin() + size_before, - frame_list_buffer.Size() - size_before, false)); - } - framer->debug_visitor_ = saved_debug_visitor; - - EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list)); - return serialized_headers_old_version; - } - - static std::unique_ptr<SpdyPushPromiseIR> CloneSpdyPushPromiseIR( - const SpdyPushPromiseIR& push_promise) { - auto new_push_promise = SpdyMakeUnique<SpdyPushPromiseIR>( - push_promise.stream_id(), push_promise.promised_stream_id(), - push_promise.header_block().Clone()); - new_push_promise->set_fin(push_promise.fin()); - if (push_promise.padded()) { - new_push_promise->set_padding_len(push_promise.padding_payload_len() + 1); - } - return new_push_promise; - } - - static SpdySerializedFrame SerializePushPromise( - SpdyFramer* framer, - const SpdyPushPromiseIR& push_promise) { - SpdySerializedFrame serialized_headers_old_version = - framer->SerializePushPromise(push_promise); - framer->hpack_encoder_.reset(nullptr); - auto* saved_debug_visitor = framer->debug_visitor_; - framer->debug_visitor_ = nullptr; - - std::vector<SpdySerializedFrame> frame_list; - ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size); - frame_list_buffer.Reset(); - SpdyFramer::SpdyPushPromiseFrameIterator it( - framer, CloneSpdyPushPromiseIR(push_promise)); - while (it.HasNextFrame()) { - size_t size_before = frame_list_buffer.Size(); - EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u); - frame_list.emplace_back( - SpdySerializedFrame(frame_list_buffer.Begin() + size_before, - frame_list_buffer.Size() - size_before, false)); - } - framer->debug_visitor_ = saved_debug_visitor; - - EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list)); - return serialized_headers_old_version; - } - - static SpdySerializedFrame SerializePushPromise( - SpdyFramer* framer, - const SpdyPushPromiseIR& push_promise, - ArrayOutputBuffer* output) { - if (output == nullptr) { - return SerializePushPromise(framer, push_promise); - } - output->Reset(); - EXPECT_TRUE(framer->SerializePushPromise(push_promise, output)); - SpdySerializedFrame serialized_headers_old_version(output->Begin(), - output->Size(), false); - framer->hpack_encoder_.reset(nullptr); - auto* saved_debug_visitor = framer->debug_visitor_; - framer->debug_visitor_ = nullptr; - - std::vector<SpdySerializedFrame> frame_list; - ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size); - frame_list_buffer.Reset(); - SpdyFramer::SpdyPushPromiseFrameIterator it( - framer, CloneSpdyPushPromiseIR(push_promise)); - while (it.HasNextFrame()) { - size_t size_before = frame_list_buffer.Size(); - EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u); - frame_list.emplace_back( - SpdySerializedFrame(frame_list_buffer.Begin() + size_before, - frame_list_buffer.Size() - size_before, false)); - } - framer->debug_visitor_ = saved_debug_visitor; - - EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list)); - return serialized_headers_old_version; - } -}; - -class TestSpdyVisitor : public SpdyFramerVisitorInterface, - public SpdyFramerDebugVisitorInterface { - public: - // This is larger than our max frame size because header blocks that - // are too long can spill over into CONTINUATION frames. - static const size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024; - - explicit TestSpdyVisitor(SpdyFramer::CompressionOption option) - : framer_(option), - error_count_(0), - headers_frame_count_(0), - push_promise_frame_count_(0), - goaway_count_(0), - setting_count_(0), - settings_ack_sent_(0), - settings_ack_received_(0), - continuation_count_(0), - altsvc_count_(0), - priority_count_(0), - on_unknown_frame_result_(false), - last_window_update_stream_(0), - last_window_update_delta_(0), - last_push_promise_stream_(0), - last_push_promise_promised_stream_(0), - data_bytes_(0), - fin_frame_count_(0), - fin_flag_count_(0), - end_of_stream_count_(0), - control_frame_header_data_count_(0), - zero_length_control_frame_header_data_count_(0), - data_frame_count_(0), - last_payload_len_(0), - last_frame_len_(0), - header_buffer_(new char[kDefaultHeaderBufferSize]), - header_buffer_length_(0), - header_buffer_size_(kDefaultHeaderBufferSize), - header_stream_id_(static_cast<SpdyStreamId>(-1)), - header_control_type_(SpdyFrameType::DATA), - header_buffer_valid_(false) {} - - void OnError(Http2DecoderAdapter::SpdyFramerError error) override { - VLOG(1) << "SpdyFramer Error: " - << Http2DecoderAdapter::SpdyFramerErrorToString(error); - ++error_count_; - } - - void OnDataFrameHeader(SpdyStreamId stream_id, - size_t length, - bool fin) override { - VLOG(1) << "OnDataFrameHeader(" << stream_id << ", " << length << ", " - << fin << ")"; - ++data_frame_count_; - header_stream_id_ = stream_id; - } - - void OnStreamFrameData(SpdyStreamId stream_id, - const char* data, - size_t len) override { - VLOG(1) << "OnStreamFrameData(" << stream_id << ", data, " << len << ", " - << ") data:\n" - << SpdyHexDump(SpdyStringPiece(data, len)); - EXPECT_EQ(header_stream_id_, stream_id); - - data_bytes_ += len; - } - - void OnStreamEnd(SpdyStreamId stream_id) override { - VLOG(1) << "OnStreamEnd(" << stream_id << ")"; - EXPECT_EQ(header_stream_id_, stream_id); - ++end_of_stream_count_; - } - - void OnStreamPadLength(SpdyStreamId stream_id, size_t value) override { - VLOG(1) << "OnStreamPadding(" << stream_id << ", " << value << ")\n"; - EXPECT_EQ(header_stream_id_, stream_id); - // Count the padding length field byte against total data bytes. - data_bytes_ += 1; - } - - void OnStreamPadding(SpdyStreamId stream_id, size_t len) override { - VLOG(1) << "OnStreamPadding(" << stream_id << ", " << len << ")\n"; - EXPECT_EQ(header_stream_id_, stream_id); - data_bytes_ += len; - } - - SpdyHeadersHandlerInterface* OnHeaderFrameStart( - SpdyStreamId stream_id) override { - if (headers_handler_ == nullptr) { - headers_handler_ = SpdyMakeUnique<TestHeadersHandler>(); - } - return headers_handler_.get(); - } - - void OnHeaderFrameEnd(SpdyStreamId stream_id) override { - CHECK(headers_handler_ != nullptr); - headers_ = headers_handler_->decoded_block().Clone(); - header_bytes_received_ = headers_handler_->header_bytes_parsed(); - headers_handler_.reset(); - } - - void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override { - VLOG(1) << "OnRstStream(" << stream_id << ", " << error_code << ")"; - ++fin_frame_count_; - } - - void OnSetting(SpdySettingsId id, uint32_t value) override { - VLOG(1) << "OnSetting(" << id << ", " << std::hex << value << ")"; - ++setting_count_; - } - - void OnSettingsAck() override { - VLOG(1) << "OnSettingsAck"; - ++settings_ack_received_; - } - - void OnSettingsEnd() override { - VLOG(1) << "OnSettingsEnd"; - ++settings_ack_sent_; - } - - void OnPing(SpdyPingId unique_id, bool is_ack) override { - LOG(DFATAL) << "OnPing(" << unique_id << ", " << (is_ack ? 1 : 0) << ")"; - } - - void OnGoAway(SpdyStreamId last_accepted_stream_id, - SpdyErrorCode error_code) override { - VLOG(1) << "OnGoAway(" << last_accepted_stream_id << ", " << error_code - << ")"; - ++goaway_count_; - } - - void OnHeaders(SpdyStreamId stream_id, - bool has_priority, - int weight, - SpdyStreamId parent_stream_id, - bool exclusive, - bool fin, - bool end) override { - VLOG(1) << "OnHeaders(" << stream_id << ", " << has_priority << ", " - << weight << ", " << parent_stream_id << ", " << exclusive << ", " - << fin << ", " << end << ")"; - ++headers_frame_count_; - InitHeaderStreaming(SpdyFrameType::HEADERS, stream_id); - if (fin) { - ++fin_flag_count_; - } - header_has_priority_ = has_priority; - header_parent_stream_id_ = parent_stream_id; - header_exclusive_ = exclusive; - } - - void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override { - VLOG(1) << "OnWindowUpdate(" << stream_id << ", " << delta_window_size - << ")"; - last_window_update_stream_ = stream_id; - last_window_update_delta_ = delta_window_size; - } - - void OnPushPromise(SpdyStreamId stream_id, - SpdyStreamId promised_stream_id, - bool end) override { - VLOG(1) << "OnPushPromise(" << stream_id << ", " << promised_stream_id - << ", " << end << ")"; - ++push_promise_frame_count_; - InitHeaderStreaming(SpdyFrameType::PUSH_PROMISE, stream_id); - last_push_promise_stream_ = stream_id; - last_push_promise_promised_stream_ = promised_stream_id; - } - - void OnContinuation(SpdyStreamId stream_id, bool end) override { - VLOG(1) << "OnContinuation(" << stream_id << ", " << end << ")"; - ++continuation_count_; - } - - void OnAltSvc(SpdyStreamId stream_id, - SpdyStringPiece origin, - const SpdyAltSvcWireFormat::AlternativeServiceVector& - altsvc_vector) override { - VLOG(1) << "OnAltSvc(" << stream_id << ", \"" << origin - << "\", altsvc_vector)"; - test_altsvc_ir_ = SpdyMakeUnique<SpdyAltSvcIR>(stream_id); - if (origin.length() > 0) { - test_altsvc_ir_->set_origin(SpdyString(origin)); - } - for (const auto& altsvc : altsvc_vector) { - test_altsvc_ir_->add_altsvc(altsvc); - } - ++altsvc_count_; - } - - void OnPriority(SpdyStreamId stream_id, - SpdyStreamId parent_stream_id, - int weight, - bool exclusive) override { - VLOG(1) << "OnPriority(" << stream_id << ", " << parent_stream_id << ", " - << weight << ", " << (exclusive ? 1 : 0) << ")"; - ++priority_count_; - } - - bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override { - VLOG(1) << "OnUnknownFrame(" << stream_id << ", " << frame_type << ")"; - return on_unknown_frame_result_; - } - - void OnSendCompressedFrame(SpdyStreamId stream_id, - SpdyFrameType type, - size_t payload_len, - size_t frame_len) override { - VLOG(1) << "OnSendCompressedFrame(" << stream_id << ", " << type << ", " - << payload_len << ", " << frame_len << ")"; - last_payload_len_ = payload_len; - last_frame_len_ = frame_len; - } - - void OnReceiveCompressedFrame(SpdyStreamId stream_id, - SpdyFrameType type, - size_t frame_len) override { - VLOG(1) << "OnReceiveCompressedFrame(" << stream_id << ", " << type << ", " - << frame_len << ")"; - last_frame_len_ = frame_len; - } - - // Convenience function which runs a framer simulation with particular input. - void SimulateInFramer(const unsigned char* input, size_t size) { - deframer_.set_visitor(this); - size_t input_remaining = size; - const char* input_ptr = reinterpret_cast<const char*>(input); - while (input_remaining > 0 && deframer_.spdy_framer_error() == - Http2DecoderAdapter::SPDY_NO_ERROR) { - // To make the tests more interesting, we feed random (and small) chunks - // into the framer. This simulates getting strange-sized reads from - // the socket. - const size_t kMaxReadSize = 32; - size_t bytes_read = - (rand() % std::min(input_remaining, kMaxReadSize)) + 1; - size_t bytes_processed = deframer_.ProcessInput(input_ptr, bytes_read); - input_remaining -= bytes_processed; - input_ptr += bytes_processed; - } - } - - void InitHeaderStreaming(SpdyFrameType header_control_type, - SpdyStreamId stream_id) { - if (!IsDefinedFrameType(SerializeFrameType(header_control_type))) { - DLOG(FATAL) << "Attempted to init header streaming with " - << "invalid control frame type: " << header_control_type; - } - memset(header_buffer_.get(), 0, header_buffer_size_); - header_buffer_length_ = 0; - header_stream_id_ = stream_id; - header_control_type_ = header_control_type; - header_buffer_valid_ = true; - } - - void set_extension_visitor(ExtensionVisitorInterface* extension) { - deframer_.set_extension_visitor(extension); - } - - // Override the default buffer size (16K). Call before using the framer! - void set_header_buffer_size(size_t header_buffer_size) { - header_buffer_size_ = header_buffer_size; - header_buffer_.reset(new char[header_buffer_size]); - } - - SpdyFramer framer_; - Http2DecoderAdapter deframer_; - - // Counters from the visitor callbacks. - int error_count_; - int headers_frame_count_; - int push_promise_frame_count_; - int goaway_count_; - int setting_count_; - int settings_ack_sent_; - int settings_ack_received_; - int continuation_count_; - int altsvc_count_; - int priority_count_; - std::unique_ptr<SpdyAltSvcIR> test_altsvc_ir_; - bool on_unknown_frame_result_; - SpdyStreamId last_window_update_stream_; - int last_window_update_delta_; - SpdyStreamId last_push_promise_stream_; - SpdyStreamId last_push_promise_promised_stream_; - int data_bytes_; - int fin_frame_count_; // The count of RST_STREAM type frames received. - int fin_flag_count_; // The count of frames with the FIN flag set. - int end_of_stream_count_; // The count of zero-length data frames. - int control_frame_header_data_count_; // The count of chunks received. - // The count of zero-length control frame header data chunks received. - int zero_length_control_frame_header_data_count_; - int data_frame_count_; - size_t last_payload_len_; - size_t last_frame_len_; - - // Header block streaming state: - std::unique_ptr<char[]> header_buffer_; - size_t header_buffer_length_; - size_t header_buffer_size_; - size_t header_bytes_received_; - SpdyStreamId header_stream_id_; - SpdyFrameType header_control_type_; - bool header_buffer_valid_; - std::unique_ptr<TestHeadersHandler> headers_handler_; - SpdyHeaderBlock headers_; - bool header_has_priority_; - SpdyStreamId header_parent_stream_id_; - bool header_exclusive_; -}; - -class TestExtension : public ExtensionVisitorInterface { - public: - void OnSetting(SpdySettingsId id, uint32_t value) override { - settings_received_.push_back({id, value}); - } - - // Called when non-standard frames are received. - bool OnFrameHeader(SpdyStreamId stream_id, - size_t length, - uint8_t type, - uint8_t flags) override { - stream_id_ = stream_id; - length_ = length; - type_ = type; - flags_ = flags; - return true; - } - - // The payload for a single frame may be delivered as multiple calls to - // OnFramePayload. - void OnFramePayload(const char* data, size_t len) override { - payload_.append(data, len); - } - - std::vector<std::pair<SpdySettingsId, uint32_t>> settings_received_; - SpdyStreamId stream_id_ = 0; - size_t length_ = 0; - uint8_t type_ = 0; - uint8_t flags_ = 0; - SpdyString payload_; -}; - -// Exposes SpdyUnknownIR::set_length() for testing purposes. -class TestSpdyUnknownIR : public SpdyUnknownIR { - public: - using SpdyUnknownIR::set_length; - using SpdyUnknownIR::SpdyUnknownIR; -}; - -enum Output { USE, NOT_USE }; - -class SpdyFramerTest : public ::testing::TestWithParam<Output> { - public: - SpdyFramerTest() - : output_(output_buffer, kSize), - framer_(SpdyFramer::ENABLE_COMPRESSION) {} - - protected: - void SetUp() override { - switch (GetParam()) { - case USE: - use_output_ = true; - break; - case NOT_USE: - // TODO(yasong): remove this case after - // FLAGS_chromium_http2_flag_remove_rewritelength deprecates. - use_output_ = false; - break; - } - } - - void CompareFrame(const SpdyString& description, - const SpdySerializedFrame& actual_frame, - const unsigned char* expected, - const int expected_len) { - const unsigned char* actual = - reinterpret_cast<const unsigned char*>(actual_frame.data()); - CompareCharArraysWithHexError(description, actual, actual_frame.size(), - expected, expected_len); - } - - bool use_output_ = false; - ArrayOutputBuffer output_; - SpdyFramer framer_; - Http2DecoderAdapter deframer_; -}; - -INSTANTIATE_TEST_CASE_P(SpdyFramerTests, - SpdyFramerTest, - ::testing::Values(USE, NOT_USE)); - -// Test that we can encode and decode a SpdyHeaderBlock in serialized form. -TEST_P(SpdyFramerTest, HeaderBlockInBuffer) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - - // Encode the header block into a Headers frame. - SpdyHeadersIR headers(/* stream_id = */ 1); - headers.SetHeader("alpha", "beta"); - headers.SetHeader("gamma", "charlie"); - headers.SetHeader("cookie", "key1=value1; key2=value2"); - SpdySerializedFrame frame( - SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_)); - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()), - frame.size()); - - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - EXPECT_EQ(headers.header_block(), visitor.headers_); -} - -// Test that if there's not a full frame, we fail to parse it. -TEST_P(SpdyFramerTest, UndersizedHeaderBlockInBuffer) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - - // Encode the header block into a Headers frame. - SpdyHeadersIR headers(/* stream_id = */ 1); - headers.SetHeader("alpha", "beta"); - headers.SetHeader("gamma", "charlie"); - SpdySerializedFrame frame( - SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_)); - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()), - frame.size() - 2); - - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - EXPECT_THAT(visitor.headers_, testing::IsEmpty()); -} - -// Test that we can encode and decode stream dependency values in a header -// frame. -TEST_P(SpdyFramerTest, HeaderStreamDependencyValues) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - - const SpdyStreamId parent_stream_id_test_array[] = {0, 3}; - for (SpdyStreamId parent_stream_id : parent_stream_id_test_array) { - const bool exclusive_test_array[] = {true, false}; - for (bool exclusive : exclusive_test_array) { - SpdyHeadersIR headers(1); - headers.set_has_priority(true); - headers.set_parent_stream_id(parent_stream_id); - headers.set_exclusive(exclusive); - SpdySerializedFrame frame( - SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_)); - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()), - frame.size()); - - EXPECT_TRUE(visitor.header_has_priority_); - EXPECT_EQ(parent_stream_id, visitor.header_parent_stream_id_); - EXPECT_EQ(exclusive, visitor.header_exclusive_); - } - } -} - -// Test that if we receive a frame with payload length field at the -// advertised max size, we do not set an error in ProcessInput. -TEST_P(SpdyFramerTest, AcceptMaxFrameSizeSetting) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - deframer_.set_visitor(&visitor); - - // DATA frame with maximum allowed payload length. - unsigned char kH2FrameData[] = { - 0x00, 0x40, 0x00, // Length: 2^14 - 0x00, // Type: HEADERS - 0x00, // Flags: None - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0x00, // Junk payload - }; - - SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData), - sizeof(kH2FrameData), false); - - EXPECT_CALL(visitor, OnDataFrameHeader(1, 1 << 14, false)); - EXPECT_CALL(visitor, OnStreamFrameData(1, _, 4)); - deframer_.ProcessInput(frame.data(), frame.size()); - EXPECT_FALSE(deframer_.HasError()); -} - -// Test that if we receive a frame with payload length larger than the -// advertised max size, we set an error of SPDY_INVALID_CONTROL_FRAME_SIZE. -TEST_P(SpdyFramerTest, ExceedMaxFrameSizeSetting) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - deframer_.set_visitor(&visitor); - - // DATA frame with too large payload length. - unsigned char kH2FrameData[] = { - 0x00, 0x40, 0x01, // Length: 2^14 + 1 - 0x00, // Type: HEADERS - 0x00, // Flags: None - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0x00, // Junk payload - }; - - SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData), - sizeof(kH2FrameData), false); - - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_OVERSIZED_PAYLOAD)); - deframer_.ProcessInput(frame.data(), frame.size()); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_OVERSIZED_PAYLOAD, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a DATA frame with padding length larger than the -// payload length, we set an error of SPDY_INVALID_PADDING -TEST_P(SpdyFramerTest, OversizedDataPaddingError) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - deframer_.set_visitor(&visitor); - - // DATA frame with invalid padding length. - // |kH2FrameData| has to be |unsigned char|, because Chromium on Windows uses - // MSVC, where |char| is signed by default, which would not compile because of - // the element exceeding 127. - unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x00, // Type: DATA - 0x09, // Flags: END_STREAM|PADDED - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0xff, // PadLen: 255 trailing bytes (Too Long) - 0x00, 0x00, 0x00, 0x00, // Padding - }; - - SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData), - sizeof(kH2FrameData), false); - - { - testing::InSequence seq; - EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, 1)); - EXPECT_CALL(visitor, OnStreamPadding(1, 1)); - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_INVALID_PADDING)); - } - EXPECT_GT(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_PADDING, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a DATA frame with padding length not larger than the -// payload length, we do not set an error of SPDY_INVALID_PADDING -TEST_P(SpdyFramerTest, CorrectlySizedDataPaddingNoError) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - // DATA frame with valid Padding length - char kH2FrameData[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x00, // Type: DATA - 0x08, // Flags: PADDED - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x04, // PadLen: 4 trailing bytes - 0x00, 0x00, 0x00, 0x00, // Padding - }; - - SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false); - - { - testing::InSequence seq; - EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, false)); - EXPECT_CALL(visitor, OnStreamPadLength(1, 4)); - EXPECT_CALL(visitor, OnError(_)).Times(0); - // Note that OnStreamFrameData(1, _, 1)) is never called - // since there is no data, only padding - EXPECT_CALL(visitor, OnStreamPadding(1, 4)); - } - - EXPECT_EQ(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_FALSE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a HEADERS frame with padding length larger than the -// payload length, we set an error of SPDY_INVALID_PADDING -TEST_P(SpdyFramerTest, OversizedHeadersPaddingError) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - // HEADERS frame with invalid padding length. - // |kH2FrameData| has to be |unsigned char|, because Chromium on Windows uses - // MSVC, where |char| is signed by default, which would not compile because of - // the element exceeding 127. - unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x01, // Type: HEADERS - 0x08, // Flags: PADDED - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0xff, // PadLen: 255 trailing bytes (Too Long) - 0x00, 0x00, 0x00, 0x00, // Padding - }; - - SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData), - sizeof(kH2FrameData), false); - - EXPECT_CALL(visitor, OnHeaders(1, false, 0, 0, false, false, false)); - EXPECT_CALL(visitor, OnHeaderFrameStart(1)).Times(1); - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_INVALID_PADDING)); - EXPECT_EQ(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_PADDING, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a HEADERS frame with padding length not larger -// than the payload length, we do not set an error of SPDY_INVALID_PADDING -TEST_P(SpdyFramerTest, CorrectlySizedHeadersPaddingNoError) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - // HEADERS frame with invalid Padding length - char kH2FrameData[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x01, // Type: HEADERS - 0x08, // Flags: PADDED - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x04, // PadLen: 4 trailing bytes - 0x00, 0x00, 0x00, 0x00, // Padding - }; - - SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false); - - EXPECT_CALL(visitor, OnHeaders(1, false, 0, 0, false, false, false)); - EXPECT_CALL(visitor, OnHeaderFrameStart(1)).Times(1); - - EXPECT_EQ(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_FALSE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a DATA with stream ID zero, we signal an error -// (but don't crash). -TEST_P(SpdyFramerTest, DataWithStreamIdZero) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - const char bytes[] = "hello"; - SpdyDataIR data_ir(/* stream_id = */ 0, bytes); - SpdySerializedFrame frame(framer_.SerializeData(data_ir)); - - // We shouldn't have to read the whole frame before we signal an error. - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID)); - EXPECT_GT(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a HEADERS with stream ID zero, we signal an error -// (but don't crash). -TEST_P(SpdyFramerTest, HeadersWithStreamIdZero) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - SpdyHeadersIR headers(/* stream_id = */ 0); - headers.SetHeader("alpha", "beta"); - SpdySerializedFrame frame( - SpdyFramerPeer::SerializeHeaders(&framer_, headers, &output_)); - - // We shouldn't have to read the whole frame before we signal an error. - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID)); - EXPECT_GT(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a PRIORITY with stream ID zero, we signal an error -// (but don't crash). -TEST_P(SpdyFramerTest, PriorityWithStreamIdZero) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - SpdyPriorityIR priority_ir(/* stream_id = */ 0, - /* parent_stream_id = */ 1, - /* weight = */ 16, - /* exclusive = */ true); - SpdySerializedFrame frame(framer_.SerializeFrame(priority_ir)); - if (use_output_) { - EXPECT_EQ(framer_.SerializeFrame(priority_ir, &output_), frame.size()); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - - // We shouldn't have to read the whole frame before we signal an error. - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID)); - EXPECT_GT(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a RST_STREAM with stream ID zero, we signal an error -// (but don't crash). -TEST_P(SpdyFramerTest, RstStreamWithStreamIdZero) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - SpdyRstStreamIR rst_stream_ir(/* stream_id = */ 0, ERROR_CODE_PROTOCOL_ERROR); - SpdySerializedFrame frame(framer_.SerializeRstStream(rst_stream_ir)); - if (use_output_) { - EXPECT_TRUE(framer_.SerializeRstStream(rst_stream_ir, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - - // We shouldn't have to read the whole frame before we signal an error. - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID)); - EXPECT_GT(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a SETTINGS with stream ID other than zero, -// we signal an error (but don't crash). -TEST_P(SpdyFramerTest, SettingsWithStreamIdNotZero) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - // Settings frame with invalid StreamID of 0x01 - char kH2FrameData[] = { - 0x00, 0x00, 0x06, // Length: 6 - 0x04, // Type: SETTINGS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x04, // Param: INITIAL_WINDOW_SIZE - 0x0a, 0x0b, 0x0c, 0x0d, // Value: 168496141 - }; - - SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false); - - // We shouldn't have to read the whole frame before we signal an error. - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID)); - EXPECT_GT(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a GOAWAY with stream ID other than zero, -// we signal an error (but don't crash). -TEST_P(SpdyFramerTest, GoawayWithStreamIdNotZero) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - // GOAWAY frame with invalid StreamID of 0x01 - char kH2FrameData[] = { - 0x00, 0x00, 0x0a, // Length: 10 - 0x07, // Type: GOAWAY - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0x00, // Last: 0 - 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR - 0x47, 0x41, // Description - }; - - SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false); - - // We shouldn't have to read the whole frame before we signal an error. - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID)); - EXPECT_GT(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a CONTINUATION with stream ID zero, we signal -// SPDY_INVALID_STREAM_ID. -TEST_P(SpdyFramerTest, ContinuationWithStreamIdZero) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - SpdyContinuationIR continuation(/* stream_id = */ 0); - auto some_nonsense_encoding = - SpdyMakeUnique<SpdyString>("some nonsense encoding"); - continuation.take_encoding(std::move(some_nonsense_encoding)); - continuation.set_end_headers(true); - SpdySerializedFrame frame(framer_.SerializeContinuation(continuation)); - if (use_output_) { - ASSERT_TRUE(framer_.SerializeContinuation(continuation, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - - // We shouldn't have to read the whole frame before we signal an error. - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID)); - EXPECT_GT(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a PUSH_PROMISE with stream ID zero, we signal -// SPDY_INVALID_STREAM_ID. -TEST_P(SpdyFramerTest, PushPromiseWithStreamIdZero) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - SpdyPushPromiseIR push_promise(/* stream_id = */ 0, - /* promised_stream_id = */ 4); - push_promise.SetHeader("alpha", "beta"); - SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( - &framer_, push_promise, use_output_ ? &output_ : nullptr)); - - // We shouldn't have to read the whole frame before we signal an error. - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID)); - EXPECT_GT(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_STREAM_ID, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test that if we receive a PUSH_PROMISE with promised stream ID zero, we -// signal SPDY_INVALID_CONTROL_FRAME. -TEST_P(SpdyFramerTest, PushPromiseWithPromisedStreamIdZero) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - SpdyPushPromiseIR push_promise(/* stream_id = */ 3, - /* promised_stream_id = */ 0); - push_promise.SetHeader("alpha", "beta"); - SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( - &framer_, push_promise, use_output_ ? &output_ : nullptr)); - - EXPECT_CALL(visitor, - OnError(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME)); - deframer_.ProcessInput(frame.data(), frame.size()); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -TEST_P(SpdyFramerTest, MultiValueHeader) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - SpdyString value("value1\0value2", 13); - // TODO(jgraettinger): If this pattern appears again, move to test class. - SpdyHeaderBlock header_set; - header_set["name"] = value; - SpdyString buffer; - HpackEncoder encoder(ObtainHpackHuffmanTable()); - encoder.DisableCompression(); - encoder.EncodeHeaderSet(header_set, &buffer); - // Frame builder with plentiful buffer size. - SpdyFrameBuilder frame(1024); - frame.BeginNewFrame(SpdyFrameType::HEADERS, - HEADERS_FLAG_PRIORITY | HEADERS_FLAG_END_HEADERS, 3, - buffer.size() + 5 /* priority */); - frame.WriteUInt32(0); // Priority exclusivity and dependent stream. - frame.WriteUInt8(255); // Priority weight. - frame.WriteBytes(&buffer[0], buffer.size()); - - SpdySerializedFrame control_frame(frame.take()); - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - control_frame.size()); - - EXPECT_THAT(visitor.headers_, testing::ElementsAre(testing::Pair( - "name", SpdyStringPiece(value)))); -} - -TEST_P(SpdyFramerTest, CompressEmptyHeaders) { - // See https://crbug.com/172383/ - SpdyHeadersIR headers(1); - headers.SetHeader("server", "SpdyServer 1.0"); - headers.SetHeader("date", "Mon 12 Jan 2009 12:12:12 PST"); - headers.SetHeader("status", "200"); - headers.SetHeader("version", "HTTP/1.1"); - headers.SetHeader("content-type", "text/html"); - headers.SetHeader("content-length", "12"); - headers.SetHeader("x-empty-header", ""); - - SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); - SpdySerializedFrame frame1( - SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_)); -} - -TEST_P(SpdyFramerTest, Basic) { - // Send HEADERS frames with PRIORITY and END_HEADERS set. - // frame-format off - const unsigned char kH2Input[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x01, // Type: HEADERS - 0x24, // Flags: END_HEADERS|PRIORITY - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0x00, // Parent: 0 - 0x82, // Weight: 131 - - 0x00, 0x00, 0x01, // Length: 1 - 0x01, // Type: HEADERS - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x8c, // :status: 200 - - 0x00, 0x00, 0x0c, // Length: 12 - 0x00, // Type: DATA - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0xde, 0xad, 0xbe, 0xef, // Payload - 0xde, 0xad, 0xbe, 0xef, // - 0xde, 0xad, 0xbe, 0xef, // - - 0x00, 0x00, 0x05, // Length: 5 - 0x01, // Type: HEADERS - 0x24, // Flags: END_HEADERS|PRIORITY - 0x00, 0x00, 0x00, 0x03, // Stream: 3 - 0x00, 0x00, 0x00, 0x00, // Parent: 0 - 0x82, // Weight: 131 - - 0x00, 0x00, 0x08, // Length: 8 - 0x00, // Type: DATA - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x03, // Stream: 3 - 0xde, 0xad, 0xbe, 0xef, // Payload - 0xde, 0xad, 0xbe, 0xef, // - - 0x00, 0x00, 0x04, // Length: 4 - 0x00, // Type: DATA - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0xde, 0xad, 0xbe, 0xef, // Payload - - 0x00, 0x00, 0x04, // Length: 4 - 0x03, // Type: RST_STREAM - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0x08, // Error: CANCEL - - 0x00, 0x00, 0x00, // Length: 0 - 0x00, // Type: DATA - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x03, // Stream: 3 - - 0x00, 0x00, 0x04, // Length: 4 - 0x03, // Type: RST_STREAM - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x03, // Stream: 3 - 0x00, 0x00, 0x00, 0x08, // Error: CANCEL - }; - // frame-format on - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kH2Input, sizeof(kH2Input)); - - EXPECT_EQ(24, visitor.data_bytes_); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(2, visitor.fin_frame_count_); - - EXPECT_EQ(3, visitor.headers_frame_count_); - - EXPECT_EQ(0, visitor.fin_flag_count_); - EXPECT_EQ(0, visitor.end_of_stream_count_); - EXPECT_EQ(4, visitor.data_frame_count_); -} - -// Test that the FIN flag on a data frame signifies EOF. -TEST_P(SpdyFramerTest, FinOnDataFrame) { - // Send HEADERS frames with END_HEADERS set. - // frame-format off - const unsigned char kH2Input[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x01, // Type: HEADERS - 0x24, // Flags: END_HEADERS|PRIORITY - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0x00, // Parent: 0 - 0x82, // Weight: 131 - - 0x00, 0x00, 0x01, // Length: 1 - 0x01, // Type: HEADERS - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x8c, // :status: 200 - - 0x00, 0x00, 0x0c, // Length: 12 - 0x00, // Type: DATA - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0xde, 0xad, 0xbe, 0xef, // Payload - 0xde, 0xad, 0xbe, 0xef, // - 0xde, 0xad, 0xbe, 0xef, // - - 0x00, 0x00, 0x04, // Length: 4 - 0x00, // Type: DATA - 0x01, // Flags: END_STREAM - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0xde, 0xad, 0xbe, 0xef, // Payload - }; - // frame-format on - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kH2Input, sizeof(kH2Input)); - - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(2, visitor.headers_frame_count_); - EXPECT_EQ(16, visitor.data_bytes_); - EXPECT_EQ(0, visitor.fin_frame_count_); - EXPECT_EQ(0, visitor.fin_flag_count_); - EXPECT_EQ(1, visitor.end_of_stream_count_); - EXPECT_EQ(2, visitor.data_frame_count_); -} - -TEST_P(SpdyFramerTest, FinOnHeadersFrame) { - // Send HEADERS frames with END_HEADERS set. - // frame-format off - const unsigned char kH2Input[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x01, // Type: HEADERS - 0x24, // Flags: END_HEADERS|PRIORITY - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0x00, // Parent: 0 - 0x82, // Weight: 131 - - 0x00, 0x00, 0x01, // Length: 1 - 0x01, // Type: HEADERS - 0x05, // Flags: END_STREAM|END_HEADERS - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x8c, // :status: 200 - }; - // frame-format on - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kH2Input, sizeof(kH2Input)); - - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(2, visitor.headers_frame_count_); - EXPECT_EQ(0, visitor.data_bytes_); - EXPECT_EQ(0, visitor.fin_frame_count_); - EXPECT_EQ(1, visitor.fin_flag_count_); - EXPECT_EQ(1, visitor.end_of_stream_count_); - EXPECT_EQ(0, visitor.data_frame_count_); -} - -// Verify we can decompress the stream even if handed over to the -// framer 1 byte at a time. -TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) { - const char kHeader1[] = "header1"; - const char kHeader2[] = "header2"; - const char kValue1[] = "value1"; - const char kValue2[] = "value2"; - - SpdyHeadersIR headers(/* stream_id = */ 1); - headers.SetHeader(kHeader1, kValue1); - headers.SetHeader(kHeader2, kValue2); - SpdySerializedFrame headers_frame(SpdyFramerPeer::SerializeHeaders( - &framer_, headers, use_output_ ? &output_ : nullptr)); - - const char bytes[] = "this is a test test test test test!"; - SpdyDataIR data_ir(/* stream_id = */ 1, - SpdyStringPiece(bytes, SPDY_ARRAYSIZE(bytes))); - data_ir.set_fin(true); - SpdySerializedFrame send_frame(framer_.SerializeData(data_ir)); - - // Run the inputs through the framer. - TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); - const unsigned char* data; - data = reinterpret_cast<const unsigned char*>(headers_frame.data()); - for (size_t idx = 0; idx < headers_frame.size(); ++idx) { - visitor.SimulateInFramer(data + idx, 1); - ASSERT_EQ(0, visitor.error_count_); - } - data = reinterpret_cast<const unsigned char*>(send_frame.data()); - for (size_t idx = 0; idx < send_frame.size(); ++idx) { - visitor.SimulateInFramer(data + idx, 1); - ASSERT_EQ(0, visitor.error_count_); - } - - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(SPDY_ARRAYSIZE(bytes), static_cast<unsigned>(visitor.data_bytes_)); - EXPECT_EQ(0, visitor.fin_frame_count_); - EXPECT_EQ(0, visitor.fin_flag_count_); - EXPECT_EQ(1, visitor.end_of_stream_count_); - EXPECT_EQ(1, visitor.data_frame_count_); -} - -TEST_P(SpdyFramerTest, WindowUpdateFrame) { - SpdyWindowUpdateIR window_update(/* stream_id = */ 1, - /* delta = */ 0x12345678); - SpdySerializedFrame frame(framer_.SerializeWindowUpdate(window_update)); - if (use_output_) { - ASSERT_TRUE(framer_.SerializeWindowUpdate(window_update, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - - const char kDescription[] = "WINDOW_UPDATE frame, stream 1, delta 0x12345678"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x04, // Length: 4 - 0x08, // Type: WINDOW_UPDATE - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x12, 0x34, 0x56, 0x78, // Increment: 305419896 - }; - - CompareFrame(kDescription, frame, kH2FrameData, SPDY_ARRAYSIZE(kH2FrameData)); -} - -TEST_P(SpdyFramerTest, CreateDataFrame) { - { - const char kDescription[] = "'hello' data frame, no FIN"; - // frame-format off - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x00, // Type: DATA - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 'h', 'e', 'l', 'l', // Payload - 'o', // - }; - // frame-format on - const char bytes[] = "hello"; - - SpdyDataIR data_ir(/* stream_id = */ 1, bytes); - SpdySerializedFrame frame(framer_.SerializeData(data_ir)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - - SpdyDataIR data_header_ir(/* stream_id = */ 1); - data_header_ir.SetDataShallow(bytes); - frame = - framer_.SerializeDataFrameHeaderWithPaddingLengthField(data_header_ir); - CompareCharArraysWithHexError( - kDescription, reinterpret_cast<const unsigned char*>(frame.data()), - kDataFrameMinimumSize, kH2FrameData, kDataFrameMinimumSize); - } - - { - const char kDescription[] = "'hello' data frame with more padding, no FIN"; - // clang-format off - // frame-format off - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0xfd, // Length: 253 - 0x00, // Type: DATA - 0x08, // Flags: PADDED - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0xf7, // PadLen: 247 trailing bytes - 'h', 'e', 'l', 'l', // Payload - 'o', // - // Padding of 247 0x00(s). - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - // frame-format on - // clang-format on - const char bytes[] = "hello"; - - SpdyDataIR data_ir(/* stream_id = */ 1, bytes); - // 247 zeros and the pad length field make the overall padding to be 248 - // bytes. - data_ir.set_padding_len(248); - SpdySerializedFrame frame(framer_.SerializeData(data_ir)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - - frame = framer_.SerializeDataFrameHeaderWithPaddingLengthField(data_ir); - CompareCharArraysWithHexError( - kDescription, reinterpret_cast<const unsigned char*>(frame.data()), - kDataFrameMinimumSize, kH2FrameData, kDataFrameMinimumSize); - } - - { - const char kDescription[] = "'hello' data frame with few padding, no FIN"; - // frame-format off - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x0d, // Length: 13 - 0x00, // Type: DATA - 0x08, // Flags: PADDED - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x07, // PadLen: 7 trailing bytes - 'h', 'e', 'l', 'l', // Payload - 'o', // - 0x00, 0x00, 0x00, 0x00, // Padding - 0x00, 0x00, 0x00, // Padding - }; - // frame-format on - const char bytes[] = "hello"; - - SpdyDataIR data_ir(/* stream_id = */ 1, bytes); - // 7 zeros and the pad length field make the overall padding to be 8 bytes. - data_ir.set_padding_len(8); - SpdySerializedFrame frame(framer_.SerializeData(data_ir)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - - frame = framer_.SerializeDataFrameHeaderWithPaddingLengthField(data_ir); - CompareCharArraysWithHexError( - kDescription, reinterpret_cast<const unsigned char*>(frame.data()), - kDataFrameMinimumSize, kH2FrameData, kDataFrameMinimumSize); - } - - { - const char kDescription[] = - "'hello' data frame with 1 byte padding, no FIN"; - // frame-format off - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x06, // Length: 6 - 0x00, // Type: DATA - 0x08, // Flags: PADDED - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, // PadLen: 0 trailing bytes - 'h', 'e', 'l', 'l', // Payload - 'o', // - }; - // frame-format on - const char bytes[] = "hello"; - - SpdyDataIR data_ir(/* stream_id = */ 1, bytes); - // The pad length field itself is used for the 1-byte padding and no padding - // payload is needed. - data_ir.set_padding_len(1); - SpdySerializedFrame frame(framer_.SerializeData(data_ir)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - - frame = framer_.SerializeDataFrameHeaderWithPaddingLengthField(data_ir); - CompareCharArraysWithHexError( - kDescription, reinterpret_cast<const unsigned char*>(frame.data()), - kDataFrameMinimumSize, kH2FrameData, kDataFrameMinimumSize); - } - - { - const char kDescription[] = "Data frame with negative data byte, no FIN"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x01, // Length: 1 - 0x00, // Type: DATA - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0xff, // Payload - }; - SpdyDataIR data_ir(/* stream_id = */ 1, "\xff"); - SpdySerializedFrame frame(framer_.SerializeData(data_ir)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = "'hello' data frame, with FIN"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x00, // Type: DATA - 0x01, // Flags: END_STREAM - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x68, 0x65, 0x6c, 0x6c, // Payload - 0x6f, // - }; - SpdyDataIR data_ir(/* stream_id = */ 1, "hello"); - data_ir.set_fin(true); - SpdySerializedFrame frame(framer_.SerializeData(data_ir)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = "Empty data frame"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x00, // Length: 0 - 0x00, // Type: DATA - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - }; - SpdyDataIR data_ir(/* stream_id = */ 1, ""); - SpdySerializedFrame frame(framer_.SerializeData(data_ir)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - - frame = framer_.SerializeDataFrameHeaderWithPaddingLengthField(data_ir); - CompareCharArraysWithHexError( - kDescription, reinterpret_cast<const unsigned char*>(frame.data()), - kDataFrameMinimumSize, kH2FrameData, kDataFrameMinimumSize); - } - - { - const char kDescription[] = "Data frame with max stream ID"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x00, // Type: DATA - 0x01, // Flags: END_STREAM - 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff - 0x68, 0x65, 0x6c, 0x6c, // Payload - 0x6f, // - }; - SpdyDataIR data_ir(/* stream_id = */ 0x7fffffff, "hello"); - data_ir.set_fin(true); - SpdySerializedFrame frame(framer_.SerializeData(data_ir)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } -} - -TEST_P(SpdyFramerTest, CreateRstStream) { - { - const char kDescription[] = "RST_STREAM frame"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x04, // Length: 4 - 0x03, // Type: RST_STREAM - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0x01, // Error: PROTOCOL_ERROR - }; - SpdyRstStreamIR rst_stream(/* stream_id = */ 1, ERROR_CODE_PROTOCOL_ERROR); - SpdySerializedFrame frame(framer_.SerializeRstStream(rst_stream)); - if (use_output_) { - ASSERT_TRUE(framer_.SerializeRstStream(rst_stream, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = "RST_STREAM frame with max stream ID"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x04, // Length: 4 - 0x03, // Type: RST_STREAM - 0x00, // Flags: none - 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff - 0x00, 0x00, 0x00, 0x01, // Error: PROTOCOL_ERROR - }; - SpdyRstStreamIR rst_stream(/* stream_id = */ 0x7FFFFFFF, - ERROR_CODE_PROTOCOL_ERROR); - SpdySerializedFrame frame(framer_.SerializeRstStream(rst_stream)); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializeRstStream(rst_stream, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = "RST_STREAM frame with max status code"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x04, // Length: 4 - 0x03, // Type: RST_STREAM - 0x00, // Flags: none - 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff - 0x00, 0x00, 0x00, 0x02, // Error: INTERNAL_ERROR - }; - SpdyRstStreamIR rst_stream(/* stream_id = */ 0x7FFFFFFF, - ERROR_CODE_INTERNAL_ERROR); - SpdySerializedFrame frame(framer_.SerializeRstStream(rst_stream)); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializeRstStream(rst_stream, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } -} - -TEST_P(SpdyFramerTest, CreateSettings) { - { - const char kDescription[] = "Network byte order SETTINGS frame"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x06, // Length: 6 - 0x04, // Type: SETTINGS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x00, 0x04, // Param: INITIAL_WINDOW_SIZE - 0x0a, 0x0b, 0x0c, 0x0d, // Value: 168496141 - }; - - uint32_t kValue = 0x0a0b0c0d; - SpdySettingsIR settings_ir; - - SpdyKnownSettingsId kId = SETTINGS_INITIAL_WINDOW_SIZE; - settings_ir.AddSetting(kId, kValue); - - SpdySerializedFrame frame(framer_.SerializeSettings(settings_ir)); - if (use_output_) { - ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = "Basic SETTINGS frame"; - // These end up seemingly out of order because of the way that our internal - // ordering for settings_ir works. HTTP2 has no requirement on ordering on - // the wire. - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x18, // Length: 24 - 0x04, // Type: SETTINGS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x00, 0x01, // Param: HEADER_TABLE_SIZE - 0x00, 0x00, 0x00, 0x05, // Value: 5 - 0x00, 0x02, // Param: ENABLE_PUSH - 0x00, 0x00, 0x00, 0x06, // Value: 6 - 0x00, 0x03, // Param: MAX_CONCURRENT_STREAMS - 0x00, 0x00, 0x00, 0x07, // Value: 7 - 0x00, 0x04, // Param: INITIAL_WINDOW_SIZE - 0x00, 0x00, 0x00, 0x08, // Value: 8 - }; - - SpdySettingsIR settings_ir; - settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 5); - settings_ir.AddSetting(SETTINGS_ENABLE_PUSH, 6); - settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 7); - settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 8); - SpdySerializedFrame frame(framer_.SerializeSettings(settings_ir)); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = "Empty SETTINGS frame"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x00, // Length: 0 - 0x04, // Type: SETTINGS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - }; - SpdySettingsIR settings_ir; - SpdySerializedFrame frame(framer_.SerializeSettings(settings_ir)); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } -} - -TEST_P(SpdyFramerTest, CreatePingFrame) { - { - const char kDescription[] = "PING frame"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x08, // Length: 8 - 0x06, // Type: PING - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x12, 0x34, 0x56, 0x78, // Opaque - 0x9a, 0xbc, 0xde, 0xff, // Data - }; - const unsigned char kH2FrameDataWithAck[] = { - 0x00, 0x00, 0x08, // Length: 8 - 0x06, // Type: PING - 0x01, // Flags: ACK - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x12, 0x34, 0x56, 0x78, // Opaque - 0x9a, 0xbc, 0xde, 0xff, // Data - }; - const SpdyPingId kPingId = 0x123456789abcdeffULL; - SpdyPingIR ping_ir(kPingId); - // Tests SpdyPingIR when the ping is not an ack. - ASSERT_FALSE(ping_ir.is_ack()); - SpdySerializedFrame frame(framer_.SerializePing(ping_ir)); - if (use_output_) { - ASSERT_TRUE(framer_.SerializePing(ping_ir, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - - // Tests SpdyPingIR when the ping is an ack. - ping_ir.set_is_ack(true); - frame = framer_.SerializePing(ping_ir); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializePing(ping_ir, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kH2FrameDataWithAck, - SPDY_ARRAYSIZE(kH2FrameDataWithAck)); - } -} - -TEST_P(SpdyFramerTest, CreateGoAway) { - { - const char kDescription[] = "GOAWAY frame"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x0a, // Length: 10 - 0x07, // Type: GOAWAY - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x00, 0x00, 0x00, 0x00, // Last: 0 - 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR - 0x47, 0x41, // Description - }; - SpdyGoAwayIR goaway_ir(/* last_good_stream_id = */ 0, ERROR_CODE_NO_ERROR, - "GA"); - SpdySerializedFrame frame(framer_.SerializeGoAway(goaway_ir)); - if (use_output_) { - ASSERT_TRUE(framer_.SerializeGoAway(goaway_ir, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = "GOAWAY frame with max stream ID, status"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x0a, // Length: 10 - 0x07, // Type: GOAWAY - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x7f, 0xff, 0xff, 0xff, // Last: 0x7fffffff - 0x00, 0x00, 0x00, 0x02, // Error: INTERNAL_ERROR - 0x47, 0x41, // Description - }; - SpdyGoAwayIR goaway_ir(/* last_good_stream_id = */ 0x7FFFFFFF, - ERROR_CODE_INTERNAL_ERROR, "GA"); - SpdySerializedFrame frame(framer_.SerializeGoAway(goaway_ir)); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializeGoAway(goaway_ir, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } -} - -TEST_P(SpdyFramerTest, CreateHeadersUncompressed) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - - { - const char kDescription[] = "HEADERS frame, no FIN"; - // frame-format off - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x12, // Length: 18 - 0x01, // Type: HEADERS - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x62, 0x61, 0x72, // bar - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x03, // Value Len: 3 - 0x62, 0x61, 0x72, // bar - }; - // frame-format on - SpdyHeadersIR headers(/* stream_id = */ 1); - headers.SetHeader("bar", "foo"); - headers.SetHeader("foo", "bar"); - SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( - &framer, headers, use_output_ ? &output_ : nullptr)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = - "HEADERS frame with a 0-length header name, FIN, max stream ID"; - // frame-format off - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x0f, // Length: 15 - 0x01, // Type: HEADERS - 0x05, // Flags: END_STREAM|END_HEADERS - 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 - - 0x00, // Unindexed Entry - 0x00, // Name Len: 0 - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x03, // Value Len: 3 - 0x62, 0x61, 0x72, // bar - }; - // frame-format on - SpdyHeadersIR headers(/* stream_id = */ 0x7fffffff); - headers.set_fin(true); - headers.SetHeader("", "foo"); - headers.SetHeader("foo", "bar"); - SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( - &framer, headers, use_output_ ? &output_ : nullptr)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = - "HEADERS frame with a 0-length header val, FIN, max stream ID"; - // frame-format off - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x0f, // Length: 15 - 0x01, // Type: HEADERS - 0x05, // Flags: END_STREAM|END_HEADERS - 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x62, 0x61, 0x72, // bar - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x00, // Value Len: 0 - }; - // frame-format on - SpdyHeadersIR headers_ir(/* stream_id = */ 0x7fffffff); - headers_ir.set_fin(true); - headers_ir.SetHeader("bar", "foo"); - headers_ir.SetHeader("foo", ""); - SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( - &framer, headers_ir, use_output_ ? &output_ : nullptr)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = - "HEADERS frame with a 0-length header val, FIN, max stream ID, pri"; - - // frame-format off - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x14, // Length: 20 - 0x01, // Type: HEADERS - 0x25, // Flags: END_STREAM|END_HEADERS|PRIORITY - 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 - 0x00, 0x00, 0x00, 0x00, // Parent: 0 - 0xdb, // Weight: 220 - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x62, 0x61, 0x72, // bar - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x00, // Value Len: 0 - }; - // frame-format on - SpdyHeadersIR headers_ir(/* stream_id = */ 0x7fffffff); - headers_ir.set_fin(true); - headers_ir.set_has_priority(true); - headers_ir.set_weight(220); - headers_ir.SetHeader("bar", "foo"); - headers_ir.SetHeader("foo", ""); - SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( - &framer, headers_ir, use_output_ ? &output_ : nullptr)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = - "HEADERS frame with a 0-length header val, FIN, max stream ID, pri, " - "exclusive=true, parent_stream=0"; - - // frame-format off - const unsigned char kV4FrameData[] = { - 0x00, 0x00, 0x14, // Length: 20 - 0x01, // Type: HEADERS - 0x25, // Flags: END_STREAM|END_HEADERS|PRIORITY - 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 - 0x80, 0x00, 0x00, 0x00, // Parent: 0 (Exclusive) - 0xdb, // Weight: 220 - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x62, 0x61, 0x72, // bar - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x00, // Value Len: 0 - }; - // frame-format on - SpdyHeadersIR headers_ir(/* stream_id = */ 0x7fffffff); - headers_ir.set_fin(true); - headers_ir.set_has_priority(true); - headers_ir.set_weight(220); - headers_ir.set_exclusive(true); - headers_ir.set_parent_stream_id(0); - headers_ir.SetHeader("bar", "foo"); - headers_ir.SetHeader("foo", ""); - SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( - &framer, headers_ir, use_output_ ? &output_ : nullptr)); - CompareFrame(kDescription, frame, kV4FrameData, - SPDY_ARRAYSIZE(kV4FrameData)); - } - - { - const char kDescription[] = - "HEADERS frame with a 0-length header val, FIN, max stream ID, pri, " - "exclusive=false, parent_stream=max stream ID"; - - // frame-format off - const unsigned char kV4FrameData[] = { - 0x00, 0x00, 0x14, // Length: 20 - 0x01, // Type: HEADERS - 0x25, // Flags: END_STREAM|END_HEADERS|PRIORITY - 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 - 0x7f, 0xff, 0xff, 0xff, // Parent: 2147483647 - 0xdb, // Weight: 220 - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x62, 0x61, 0x72, // bar - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x00, // Value Len: 0 - }; - // frame-format on - SpdyHeadersIR headers_ir(/* stream_id = */ 0x7fffffff); - headers_ir.set_fin(true); - headers_ir.set_has_priority(true); - headers_ir.set_weight(220); - headers_ir.set_exclusive(false); - headers_ir.set_parent_stream_id(0x7fffffff); - headers_ir.SetHeader("bar", "foo"); - headers_ir.SetHeader("foo", ""); - SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( - &framer, headers_ir, use_output_ ? &output_ : nullptr)); - CompareFrame(kDescription, frame, kV4FrameData, - SPDY_ARRAYSIZE(kV4FrameData)); - } - - { - const char kDescription[] = - "HEADERS frame with a 0-length header name, FIN, max stream ID, padded"; - - // frame-format off - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x15, // Length: 21 - 0x01, // Type: HEADERS - 0x0d, // Flags: END_STREAM|END_HEADERS|PADDED - 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 - 0x05, // PadLen: 5 trailing bytes - - 0x00, // Unindexed Entry - 0x00, // Name Len: 0 - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x03, // Value Len: 3 - 0x62, 0x61, 0x72, // bar - - 0x00, 0x00, 0x00, 0x00, // Padding - 0x00, // Padding - }; - // frame-format on - SpdyHeadersIR headers_ir(/* stream_id = */ 0x7fffffff); - headers_ir.set_fin(true); - headers_ir.SetHeader("", "foo"); - headers_ir.SetHeader("foo", "bar"); - headers_ir.set_padding_len(6); - SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( - &framer, headers_ir, use_output_ ? &output_ : nullptr)); - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } -} - -TEST_P(SpdyFramerTest, CreateWindowUpdate) { - { - const char kDescription[] = "WINDOW_UPDATE frame"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x04, // Length: 4 - 0x08, // Type: WINDOW_UPDATE - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0x01, // Increment: 1 - }; - SpdySerializedFrame frame(framer_.SerializeWindowUpdate( - SpdyWindowUpdateIR(/* stream_id = */ 1, /* delta = */ 1))); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializeWindowUpdate( - SpdyWindowUpdateIR(/* stream_id = */ 1, /* delta = */ 1), &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = "WINDOW_UPDATE frame with max stream ID"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x04, // Length: 4 - 0x08, // Type: WINDOW_UPDATE - 0x00, // Flags: none - 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff - 0x00, 0x00, 0x00, 0x01, // Increment: 1 - }; - SpdySerializedFrame frame(framer_.SerializeWindowUpdate( - SpdyWindowUpdateIR(/* stream_id = */ 0x7FFFFFFF, /* delta = */ 1))); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializeWindowUpdate( - SpdyWindowUpdateIR(/* stream_id = */ 0x7FFFFFFF, /* delta = */ 1), - &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } - - { - const char kDescription[] = "WINDOW_UPDATE frame with max window delta"; - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x04, // Length: 4 - 0x08, // Type: WINDOW_UPDATE - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x7f, 0xff, 0xff, 0xff, // Increment: 0x7fffffff - }; - SpdySerializedFrame frame(framer_.SerializeWindowUpdate( - SpdyWindowUpdateIR(/* stream_id = */ 1, /* delta = */ 0x7FFFFFFF))); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializeWindowUpdate( - SpdyWindowUpdateIR(/* stream_id = */ 1, /* delta = */ 0x7FFFFFFF), - &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kH2FrameData, - SPDY_ARRAYSIZE(kH2FrameData)); - } -} - -TEST_P(SpdyFramerTest, CreatePushPromiseUncompressed) { - { - // Test framing PUSH_PROMISE without padding. - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - const char kDescription[] = "PUSH_PROMISE frame without padding"; - - // frame-format off - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x16, // Length: 22 - 0x05, // Type: PUSH_PROMISE - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x29, // Stream: 41 - 0x00, 0x00, 0x00, 0x3a, // Promise: 58 - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x62, 0x61, 0x72, // bar - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x03, // Value Len: 3 - 0x62, 0x61, 0x72, // bar - }; - // frame-format on - - SpdyPushPromiseIR push_promise(/* stream_id = */ 41, - /* promised_stream_id = */ 58); - push_promise.SetHeader("bar", "foo"); - push_promise.SetHeader("foo", "bar"); - SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( - &framer, push_promise, use_output_ ? &output_ : nullptr)); - CompareFrame(kDescription, frame, kFrameData, SPDY_ARRAYSIZE(kFrameData)); - } - - { - // Test framing PUSH_PROMISE with one byte of padding. - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - const char kDescription[] = "PUSH_PROMISE frame with one byte of padding"; - - // frame-format off - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x17, // Length: 23 - 0x05, // Type: PUSH_PROMISE - 0x0c, // Flags: END_HEADERS|PADDED - 0x00, 0x00, 0x00, 0x29, // Stream: 41 - 0x00, // PadLen: 0 trailing bytes - 0x00, 0x00, 0x00, 0x3a, // Promise: 58 - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x62, 0x61, 0x72, // bar - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x03, // Value Len: 3 - 0x62, 0x61, 0x72, // bar - }; - // frame-format on - - SpdyPushPromiseIR push_promise(/* stream_id = */ 41, - /* promised_stream_id = */ 58); - push_promise.set_padding_len(1); - push_promise.SetHeader("bar", "foo"); - push_promise.SetHeader("foo", "bar"); - output_.Reset(); - SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( - &framer, push_promise, use_output_ ? &output_ : nullptr)); - - CompareFrame(kDescription, frame, kFrameData, SPDY_ARRAYSIZE(kFrameData)); - } - - { - // Test framing PUSH_PROMISE with 177 bytes of padding. - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - const char kDescription[] = "PUSH_PROMISE frame with 177 bytes of padding"; - - // frame-format off - // clang-format off - const unsigned char kFrameData[] = { - 0x00, 0x00, 0xc7, // Length: 199 - 0x05, // Type: PUSH_PROMISE - 0x0c, // Flags: END_HEADERS|PADDED - 0x00, 0x00, 0x00, 0x2a, // Stream: 42 - 0xb0, // PadLen: 176 trailing bytes - 0x00, 0x00, 0x00, 0x39, // Promise: 57 - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x62, 0x61, 0x72, // bar - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x03, // Value Len: 3 - 0x62, 0x61, 0x72, // bar - - // Padding of 176 0x00(s). - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - // clang-format on - // frame-format on - - SpdyPushPromiseIR push_promise(/* stream_id = */ 42, - /* promised_stream_id = */ 57); - push_promise.set_padding_len(177); - push_promise.SetHeader("bar", "foo"); - push_promise.SetHeader("foo", "bar"); - output_.Reset(); - SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( - &framer, push_promise, use_output_ ? &output_ : nullptr)); - - CompareFrame(kDescription, frame, kFrameData, SPDY_ARRAYSIZE(kFrameData)); - } -} - -// Regression test for https://crbug.com/464748. -TEST_P(SpdyFramerTest, GetNumberRequiredContinuationFrames) { - EXPECT_EQ(1u, GetNumberRequiredContinuationFrames(16383 + 16374)); - EXPECT_EQ(2u, GetNumberRequiredContinuationFrames(16383 + 16374 + 1)); - EXPECT_EQ(2u, GetNumberRequiredContinuationFrames(16383 + 2 * 16374)); - EXPECT_EQ(3u, GetNumberRequiredContinuationFrames(16383 + 2 * 16374 + 1)); -} - -TEST_P(SpdyFramerTest, CreateContinuationUncompressed) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - const char kDescription[] = "CONTINUATION frame"; - - // frame-format off - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x12, // Length: 18 - 0x09, // Type: CONTINUATION - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x2a, // Stream: 42 - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x62, 0x61, 0x72, // bar - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x03, // Value Len: 3 - 0x62, 0x61, 0x72, // bar - }; - // frame-format on - - SpdyHeaderBlock header_block; - header_block["bar"] = "foo"; - header_block["foo"] = "bar"; - auto buffer = SpdyMakeUnique<SpdyString>(); - HpackEncoder encoder(ObtainHpackHuffmanTable()); - encoder.DisableCompression(); - encoder.EncodeHeaderSet(header_block, buffer.get()); - - SpdyContinuationIR continuation(/* stream_id = */ 42); - continuation.take_encoding(std::move(buffer)); - continuation.set_end_headers(true); - - SpdySerializedFrame frame(framer.SerializeContinuation(continuation)); - if (use_output_) { - ASSERT_TRUE(framer.SerializeContinuation(continuation, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kFrameData, SPDY_ARRAYSIZE(kFrameData)); -} - -// Test that if we send an unexpected CONTINUATION -// we signal an error (but don't crash). -TEST_P(SpdyFramerTest, SendUnexpectedContinuation) { - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - // frame-format off - char kH2FrameData[] = { - 0x00, 0x00, 0x12, // Length: 18 - 0x09, // Type: CONTINUATION - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x2a, // Stream: 42 - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x62, 0x61, 0x72, // bar - 0x03, // Value Len: 3 - 0x66, 0x6f, 0x6f, // foo - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x66, 0x6f, 0x6f, // foo - 0x03, // Value Len: 3 - 0x62, 0x61, 0x72, // bar - }; - // frame-format on - - SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false); - - // We shouldn't have to read the whole frame before we signal an error. - EXPECT_CALL(visitor, OnError(Http2DecoderAdapter::SPDY_UNEXPECTED_FRAME)); - EXPECT_GT(frame.size(), deframer_.ProcessInput(frame.data(), frame.size())); - EXPECT_TRUE(deframer_.HasError()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_UNEXPECTED_FRAME, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -TEST_P(SpdyFramerTest, CreatePushPromiseThenContinuationUncompressed) { - { - // Test framing in a case such that a PUSH_PROMISE frame, with one byte of - // padding, cannot hold all the data payload, which is overflowed to the - // consecutive CONTINUATION frame. - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - const char kDescription[] = - "PUSH_PROMISE and CONTINUATION frames with one byte of padding"; - - // frame-format off - const unsigned char kPartialPushPromiseFrameData[] = { - 0x00, 0x3f, 0xf6, // Length: 16374 - 0x05, // Type: PUSH_PROMISE - 0x08, // Flags: PADDED - 0x00, 0x00, 0x00, 0x2a, // Stream: 42 - 0x00, // PadLen: 0 trailing bytes - 0x00, 0x00, 0x00, 0x39, // Promise: 57 - - 0x00, // Unindexed Entry - 0x03, // Name Len: 3 - 0x78, 0x78, 0x78, // xxx - 0x7f, 0x80, 0x7f, // Value Len: 16361 - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - }; - const unsigned char kContinuationFrameData[] = { - 0x00, 0x00, 0x16, // Length: 22 - 0x09, // Type: CONTINUATION - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x2a, // Stream: 42 - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, 0x78, 0x78, 0x78, // xxxx - 0x78, // x - }; - // frame-format on - - SpdyPushPromiseIR push_promise(/* stream_id = */ 42, - /* promised_stream_id = */ 57); - push_promise.set_padding_len(1); - SpdyString big_value(kHttp2MaxControlFrameSendSize, 'x'); - push_promise.SetHeader("xxx", big_value); - SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( - &framer, push_promise, use_output_ ? &output_ : nullptr)); - - // The entire frame should look like below: - // Name Length in Byte - // ------------------------------------------- Begin of PUSH_PROMISE frame - // PUSH_PROMISE header 9 - // Pad length field 1 - // Promised stream 4 - // Length field of key 2 - // Content of key 3 - // Length field of value 3 - // Part of big_value 16361 - // ------------------------------------------- Begin of CONTINUATION frame - // CONTINUATION header 9 - // Remaining of big_value 22 - // ------------------------------------------- End - - // Length of everything listed above except big_value. - int len_non_data_payload = 31; - EXPECT_EQ(kHttp2MaxControlFrameSendSize + len_non_data_payload, - frame.size()); - - // Partially compare the PUSH_PROMISE frame against the template. - const unsigned char* frame_data = - reinterpret_cast<const unsigned char*>(frame.data()); - CompareCharArraysWithHexError(kDescription, frame_data, - SPDY_ARRAYSIZE(kPartialPushPromiseFrameData), - kPartialPushPromiseFrameData, - SPDY_ARRAYSIZE(kPartialPushPromiseFrameData)); - - // Compare the CONTINUATION frame against the template. - frame_data += kHttp2MaxControlFrameSendSize; - CompareCharArraysWithHexError( - kDescription, frame_data, SPDY_ARRAYSIZE(kContinuationFrameData), - kContinuationFrameData, SPDY_ARRAYSIZE(kContinuationFrameData)); - } -} - -TEST_P(SpdyFramerTest, CreateAltSvc) { - const char kDescription[] = "ALTSVC frame"; - const unsigned char kType = SerializeFrameType(SpdyFrameType::ALTSVC); - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x49, kType, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 'o', - 'r', 'i', 'g', 'i', 'n', 'p', 'i', 'd', '1', '=', '"', 'h', - 'o', 's', 't', ':', '4', '4', '3', '"', ';', ' ', 'm', 'a', - '=', '5', ',', 'p', '%', '2', '2', '%', '3', 'D', 'i', '%', - '3', 'A', 'd', '=', '"', 'h', '_', '\\', '\\', 'o', '\\', '"', - 's', 't', ':', '1', '2', '3', '"', ';', ' ', 'm', 'a', '=', - '4', '2', ';', ' ', 'v', '=', '"', '2', '4', '"'}; - SpdyAltSvcIR altsvc_ir(/* stream_id = */ 3); - altsvc_ir.set_origin("origin"); - altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService( - "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector())); - altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService( - "p\"=i:d", "h_\\o\"st", 123, 42, - SpdyAltSvcWireFormat::VersionVector{24})); - SpdySerializedFrame frame(framer_.SerializeFrame(altsvc_ir)); - if (use_output_) { - EXPECT_EQ(framer_.SerializeFrame(altsvc_ir, &output_), frame.size()); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kFrameData, SPDY_ARRAYSIZE(kFrameData)); -} - -TEST_P(SpdyFramerTest, CreatePriority) { - const char kDescription[] = "PRIORITY frame"; - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x05, // Length: 5 - 0x02, // Type: PRIORITY - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x02, // Stream: 2 - 0x80, 0x00, 0x00, 0x01, // Parent: 1 (Exclusive) - 0x10, // Weight: 17 - }; - SpdyPriorityIR priority_ir(/* stream_id = */ 2, - /* parent_stream_id = */ 1, - /* weight = */ 17, - /* exclusive = */ true); - SpdySerializedFrame frame(framer_.SerializeFrame(priority_ir)); - if (use_output_) { - EXPECT_EQ(framer_.SerializeFrame(priority_ir, &output_), frame.size()); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kFrameData, SPDY_ARRAYSIZE(kFrameData)); -} - -TEST_P(SpdyFramerTest, CreateUnknown) { - const char kDescription[] = "Unknown frame"; - const uint8_t kType = 0xaf; - const uint8_t kFlags = 0x11; - const uint8_t kLength = strlen(kDescription); - const unsigned char kFrameData[] = { - 0x00, 0x00, kLength, // Length: 13 - kType, // Type: undefined - kFlags, // Flags: arbitrary, undefined - 0x00, 0x00, 0x00, 0x02, // Stream: 2 - 0x55, 0x6e, 0x6b, 0x6e, // "Unkn" - 0x6f, 0x77, 0x6e, 0x20, // "own " - 0x66, 0x72, 0x61, 0x6d, // "fram" - 0x65, // "e" - }; - SpdyUnknownIR unknown_ir(/* stream_id = */ 2, - /* type = */ kType, - /* flags = */ kFlags, - /* payload = */ kDescription); - SpdySerializedFrame frame(framer_.SerializeFrame(unknown_ir)); - if (use_output_) { - EXPECT_EQ(framer_.SerializeFrame(unknown_ir, &output_), frame.size()); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kFrameData, SPDY_ARRAYSIZE(kFrameData)); -} - -// Test serialization of a SpdyUnknownIR with a defined type, a length field -// that does not match the payload size and in fact exceeds framer limits, and a -// stream ID that effectively flips the reserved bit. -TEST_P(SpdyFramerTest, CreateUnknownUnchecked) { - const char kDescription[] = "Unknown frame"; - const uint8_t kType = 0x00; - const uint8_t kFlags = 0x11; - const uint8_t kLength = std::numeric_limits<uint8_t>::max(); - const unsigned int kStreamId = kStreamIdMask + 42; - const unsigned char kFrameData[] = { - 0x00, 0x00, kLength, // Length: 16426 - kType, // Type: DATA, defined - kFlags, // Flags: arbitrary, undefined - 0x80, 0x00, 0x00, 0x29, // Stream: 2147483689 - 0x55, 0x6e, 0x6b, 0x6e, // "Unkn" - 0x6f, 0x77, 0x6e, 0x20, // "own " - 0x66, 0x72, 0x61, 0x6d, // "fram" - 0x65, // "e" - }; - TestSpdyUnknownIR unknown_ir(/* stream_id = */ kStreamId, - /* type = */ kType, - /* flags = */ kFlags, - /* payload = */ kDescription); - unknown_ir.set_length(kLength); - SpdySerializedFrame frame(framer_.SerializeFrame(unknown_ir)); - if (use_output_) { - EXPECT_EQ(framer_.SerializeFrame(unknown_ir, &output_), frame.size()); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - CompareFrame(kDescription, frame, kFrameData, SPDY_ARRAYSIZE(kFrameData)); -} - -TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) { - SpdyHeadersIR headers_ir(/* stream_id = */ 1); - headers_ir.SetHeader("alpha", "beta"); - headers_ir.SetHeader("gamma", "delta"); - SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders( - &framer_, headers_ir, use_output_ ? &output_ : nullptr)); - TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - control_frame.size()); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(0, visitor.control_frame_header_data_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - EXPECT_EQ(0, visitor.end_of_stream_count_); - EXPECT_EQ(headers_ir.header_block(), visitor.headers_); -} - -TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) { - SpdyHeadersIR headers_ir(/* stream_id = */ 1); - headers_ir.set_fin(true); - headers_ir.SetHeader("alpha", "beta"); - headers_ir.SetHeader("gamma", "delta"); - SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders( - &framer_, headers_ir, use_output_ ? &output_ : nullptr)); - TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - control_frame.size()); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(0, visitor.control_frame_header_data_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - EXPECT_EQ(1, visitor.end_of_stream_count_); - EXPECT_EQ(headers_ir.header_block(), visitor.headers_); -} - -TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - SpdyHeadersIR headers(/* stream_id = */ 1); - headers.set_padding_len(256); - - // Exact payload length will change with HPACK, but this should be long - // enough to cause an overflow. - const size_t kBigValueSize = kHttp2MaxControlFrameSendSize; - SpdyString big_value(kBigValueSize, 'x'); - headers.SetHeader("aa", big_value); - SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders( - &framer, headers, use_output_ ? &output_ : nullptr)); - EXPECT_GT(control_frame.size(), kHttp2MaxControlFrameSendSize); - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - control_frame.size()); - EXPECT_TRUE(visitor.header_buffer_valid_); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(1, visitor.continuation_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); -} - -TEST_P(SpdyFramerTest, MultipleContinuationFramesWithIterator) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - auto headers = SpdyMakeUnique<SpdyHeadersIR>(/* stream_id = */ 1); - headers->set_padding_len(256); - - // Exact payload length will change with HPACK, but this should be long - // enough to cause an overflow. - const size_t kBigValueSize = kHttp2MaxControlFrameSendSize; - SpdyString big_valuex(kBigValueSize, 'x'); - headers->SetHeader("aa", big_valuex); - SpdyString big_valuez(kBigValueSize, 'z'); - headers->SetHeader("bb", big_valuez); - - SpdyFramer::SpdyHeaderFrameIterator frame_it(&framer, std::move(headers)); - - EXPECT_TRUE(frame_it.HasNextFrame()); - EXPECT_GT(frame_it.NextFrame(&output_), 0u); - SpdySerializedFrame headers_frame(output_.Begin(), output_.Size(), false); - EXPECT_EQ(headers_frame.size(), kHttp2MaxControlFrameSendSize); - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(headers_frame.data()), - headers_frame.size()); - EXPECT_TRUE(visitor.header_buffer_valid_); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(0, visitor.continuation_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - - output_.Reset(); - EXPECT_TRUE(frame_it.HasNextFrame()); - EXPECT_GT(frame_it.NextFrame(&output_), 0u); - SpdySerializedFrame first_cont_frame(output_.Begin(), output_.Size(), false); - EXPECT_EQ(first_cont_frame.size(), kHttp2MaxControlFrameSendSize); - - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(first_cont_frame.data()), - first_cont_frame.size()); - EXPECT_TRUE(visitor.header_buffer_valid_); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(1, visitor.continuation_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - - output_.Reset(); - EXPECT_TRUE(frame_it.HasNextFrame()); - EXPECT_GT(frame_it.NextFrame(&output_), 0u); - SpdySerializedFrame second_cont_frame(output_.Begin(), output_.Size(), false); - EXPECT_LT(second_cont_frame.size(), kHttp2MaxControlFrameSendSize); - - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(second_cont_frame.data()), - second_cont_frame.size()); - EXPECT_TRUE(visitor.header_buffer_valid_); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(2, visitor.continuation_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - - EXPECT_FALSE(frame_it.HasNextFrame()); -} - -TEST_P(SpdyFramerTest, PushPromiseFramesWithIterator) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - auto push_promise = - SpdyMakeUnique<SpdyPushPromiseIR>(/* stream_id = */ 1, - /* promised_stream_id = */ 2); - push_promise->set_padding_len(256); - - // Exact payload length will change with HPACK, but this should be long - // enough to cause an overflow. - const size_t kBigValueSize = kHttp2MaxControlFrameSendSize; - SpdyString big_valuex(kBigValueSize, 'x'); - push_promise->SetHeader("aa", big_valuex); - SpdyString big_valuez(kBigValueSize, 'z'); - push_promise->SetHeader("bb", big_valuez); - - SpdyFramer::SpdyPushPromiseFrameIterator frame_it(&framer, - std::move(push_promise)); - - EXPECT_TRUE(frame_it.HasNextFrame()); - EXPECT_GT(frame_it.NextFrame(&output_), 0u); - SpdySerializedFrame push_promise_frame(output_.Begin(), output_.Size(), - false); - EXPECT_EQ(push_promise_frame.size(), kHttp2MaxControlFrameSendSize); - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(push_promise_frame.data()), - push_promise_frame.size()); - EXPECT_TRUE(visitor.header_buffer_valid_); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.push_promise_frame_count_); - EXPECT_EQ(0, visitor.continuation_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - - EXPECT_TRUE(frame_it.HasNextFrame()); - output_.Reset(); - EXPECT_GT(frame_it.NextFrame(&output_), 0u); - SpdySerializedFrame first_cont_frame(output_.Begin(), output_.Size(), false); - - EXPECT_EQ(first_cont_frame.size(), kHttp2MaxControlFrameSendSize); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(first_cont_frame.data()), - first_cont_frame.size()); - EXPECT_TRUE(visitor.header_buffer_valid_); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.push_promise_frame_count_); - EXPECT_EQ(1, visitor.continuation_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - - EXPECT_TRUE(frame_it.HasNextFrame()); - output_.Reset(); - EXPECT_GT(frame_it.NextFrame(&output_), 0u); - SpdySerializedFrame second_cont_frame(output_.Begin(), output_.Size(), false); - EXPECT_LT(second_cont_frame.size(), kHttp2MaxControlFrameSendSize); - - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(second_cont_frame.data()), - second_cont_frame.size()); - EXPECT_TRUE(visitor.header_buffer_valid_); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.push_promise_frame_count_); - EXPECT_EQ(2, visitor.continuation_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - - EXPECT_FALSE(frame_it.HasNextFrame()); -} - -class SpdyControlFrameIteratorTest : public ::testing::Test { - public: - SpdyControlFrameIteratorTest() : output_(output_buffer, kSize) {} - - void RunTest(std::unique_ptr<SpdyFrameIR> ir) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - SpdySerializedFrame frame(framer.SerializeFrame(*ir)); - std::unique_ptr<SpdyFrameSequence> it = - SpdyFramer::CreateIterator(&framer, std::move(ir)); - EXPECT_TRUE(it->HasNextFrame()); - EXPECT_EQ(it->NextFrame(&output_), frame.size()); - EXPECT_FALSE(it->HasNextFrame()); - } - - private: - ArrayOutputBuffer output_; -}; - -TEST_F(SpdyControlFrameIteratorTest, RstStreamFrameWithIterator) { - auto ir = SpdyMakeUnique<SpdyRstStreamIR>(0, ERROR_CODE_PROTOCOL_ERROR); - RunTest(std::move(ir)); -} - -TEST_F(SpdyControlFrameIteratorTest, SettingsFrameWithIterator) { - auto ir = SpdyMakeUnique<SpdySettingsIR>(); - uint32_t kValue = 0x0a0b0c0d; - SpdyKnownSettingsId kId = SETTINGS_INITIAL_WINDOW_SIZE; - ir->AddSetting(kId, kValue); - RunTest(std::move(ir)); -} - -TEST_F(SpdyControlFrameIteratorTest, PingFrameWithIterator) { - const SpdyPingId kPingId = 0x123456789abcdeffULL; - auto ir = SpdyMakeUnique<SpdyPingIR>(kPingId); - RunTest(std::move(ir)); -} - -TEST_F(SpdyControlFrameIteratorTest, GoAwayFrameWithIterator) { - auto ir = SpdyMakeUnique<SpdyGoAwayIR>(0, ERROR_CODE_NO_ERROR, "GA"); - RunTest(std::move(ir)); -} - -TEST_F(SpdyControlFrameIteratorTest, WindowUpdateFrameWithIterator) { - auto ir = SpdyMakeUnique<SpdyWindowUpdateIR>(1, 1); - RunTest(std::move(ir)); -} - -TEST_F(SpdyControlFrameIteratorTest, AtlSvcFrameWithIterator) { - auto ir = SpdyMakeUnique<SpdyAltSvcIR>(3); - ir->set_origin("origin"); - ir->add_altsvc(SpdyAltSvcWireFormat::AlternativeService( - "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector())); - ir->add_altsvc(SpdyAltSvcWireFormat::AlternativeService( - "p\"=i:d", "h_\\o\"st", 123, 42, - SpdyAltSvcWireFormat::VersionVector{24})); - RunTest(std::move(ir)); -} - -TEST_F(SpdyControlFrameIteratorTest, PriorityFrameWithIterator) { - auto ir = SpdyMakeUnique<SpdyPriorityIR>(2, 1, 17, true); - RunTest(std::move(ir)); -} - -TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - SpdyPushPromiseIR push_promise(/* stream_id = */ 1, - /* promised_stream_id = */ 2); - push_promise.set_padding_len(256); - - // Exact payload length will change with HPACK, but this should be long - // enough to cause an overflow. - const size_t kBigValueSize = kHttp2MaxControlFrameSendSize; - SpdyString big_value(kBigValueSize, 'x'); - push_promise.SetHeader("aa", big_value); - SpdySerializedFrame control_frame(SpdyFramerPeer::SerializePushPromise( - &framer, push_promise, use_output_ ? &output_ : nullptr)); - EXPECT_GT(control_frame.size(), kHttp2MaxControlFrameSendSize); - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - control_frame.size()); - EXPECT_TRUE(visitor.header_buffer_valid_); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.push_promise_frame_count_); - EXPECT_EQ(1, visitor.continuation_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); -} - -// Check that the framer stops delivering header data chunks once the visitor -// declares it doesn't want any more. This is important to guard against -// "zip bomb" types of attacks. -TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) { - const size_t kHeaderBufferChunks = 4; - const size_t kHeaderBufferSize = - kHttp2DefaultFramePayloadLimit / kHeaderBufferChunks; - const size_t kBigValueSize = kHeaderBufferSize * 2; - SpdyString big_value(kBigValueSize, 'x'); - SpdyHeadersIR headers(/* stream_id = */ 1); - headers.set_fin(true); - headers.SetHeader("aa", big_value); - SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders( - &framer_, headers, use_output_ ? &output_ : nullptr)); - TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); - visitor.set_header_buffer_size(kHeaderBufferSize); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - control_frame.size()); - // It's up to the visitor to ignore extraneous header data; the framer - // won't throw an error. - EXPECT_GT(visitor.header_bytes_received_, visitor.header_buffer_size_); - EXPECT_EQ(1, visitor.end_of_stream_count_); -} - -TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) { - // Create a GoAway frame that has a few extra bytes at the end. - const size_t length = 20; - - // HTTP/2 GOAWAY frames are only bound by a minimal length, since they may - // carry opaque data. Verify that minimal length is tested. - ASSERT_GT(kGoawayFrameMinimumSize, kFrameHeaderSize); - const size_t less_than_min_length = - kGoawayFrameMinimumSize - kFrameHeaderSize - 1; - ASSERT_LE(less_than_min_length, std::numeric_limits<unsigned char>::max()); - const unsigned char kH2Len = static_cast<unsigned char>(less_than_min_length); - const unsigned char kH2FrameData[] = { - 0x00, 0x00, kH2Len, // Length: min length - 1 - 0x07, // Type: GOAWAY - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x00, 0x00, 0x00, 0x00, // Last: 0 - 0x00, 0x00, 0x00, // Truncated Status Field - }; - const size_t pad_length = length + kFrameHeaderSize - sizeof(kH2FrameData); - SpdyString pad(pad_length, 'A'); - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - - visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData)); - visitor.SimulateInFramer(reinterpret_cast<const unsigned char*>(pad.c_str()), - pad.length()); - - EXPECT_EQ(1, visitor.error_count_); // This generated an error. - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); - EXPECT_EQ(0, visitor.goaway_count_); // Frame not parsed. -} - -TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) { - SpdySettingsIR settings_ir; - SpdySerializedFrame control_frame(framer_.SerializeSettings(settings_ir)); - if (use_output_) { - ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_)); - control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - SetFrameLength(&control_frame, 0); - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), kFrameHeaderSize); - // Zero-len settings frames are permitted as of HTTP/2. - EXPECT_EQ(0, visitor.error_count_); -} - -// Tests handling of SETTINGS frames with invalid length. -TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) { - SpdySettingsIR settings_ir; - - // Add settings to more than fill the frame so that we don't get a buffer - // overflow when calling SimulateInFramer() below. These settings must be - // distinct parameters because SpdySettingsIR has a map for settings, and - // will collapse multiple copies of the same parameter. - settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 0x00000002); - settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 0x00000002); - SpdySerializedFrame control_frame(framer_.SerializeSettings(settings_ir)); - if (use_output_) { - ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_)); - control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - const size_t kNewLength = 8; - SetFrameLength(&control_frame, kNewLength); - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - kFrameHeaderSize + kNewLength); - // Should generate an error, since its not possible to have a - // settings frame of length kNewLength. - EXPECT_EQ(1, visitor.error_count_); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME_SIZE, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); -} - -// Tests handling of larger SETTINGS frames. -TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) { - SpdySettingsIR settings_ir; - settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 5); - settings_ir.AddSetting(SETTINGS_ENABLE_PUSH, 6); - settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 7); - - SpdySerializedFrame control_frame(framer_.SerializeSettings(settings_ir)); - if (use_output_) { - ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_)); - control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - - // Read all at once. - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - control_frame.size()); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(3, visitor.setting_count_); - EXPECT_EQ(1, visitor.settings_ack_sent_); - - // Read data in small chunks. - size_t framed_data = 0; - size_t unframed_data = control_frame.size(); - size_t kReadChunkSize = 5; // Read five bytes at a time. - while (unframed_data > 0) { - size_t to_read = std::min(kReadChunkSize, unframed_data); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data() + framed_data), - to_read); - unframed_data -= to_read; - framed_data += to_read; - } - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(3 * 2, visitor.setting_count_); - EXPECT_EQ(2, visitor.settings_ack_sent_); -} - -// Tests handling of SETTINGS frame with duplicate entries. -TEST_P(SpdyFramerTest, ReadDuplicateSettings) { - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x12, // Length: 18 - 0x04, // Type: SETTINGS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x00, 0x01, // Param: HEADER_TABLE_SIZE - 0x00, 0x00, 0x00, 0x02, // Value: 2 - 0x00, 0x01, // Param: HEADER_TABLE_SIZE - 0x00, 0x00, 0x00, 0x03, // Value: 3 - 0x00, 0x03, // Param: MAX_CONCURRENT_STREAMS - 0x00, 0x00, 0x00, 0x03, // Value: 3 - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData)); - - // In HTTP/2, duplicate settings are allowed; - // each setting replaces the previous value for that setting. - EXPECT_EQ(3, visitor.setting_count_); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.settings_ack_sent_); -} - -// Tests handling of SETTINGS frame with a setting we don't recognize. -TEST_P(SpdyFramerTest, ReadUnknownSettingsId) { - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x06, // Length: 6 - 0x04, // Type: SETTINGS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x00, 0x10, // Param: 16 - 0x00, 0x00, 0x00, 0x02, // Value: 2 - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData)); - - // In HTTP/2, we ignore unknown settings because of extensions. However, we - // pass the SETTINGS to the visitor, which can decide how to handle them. - EXPECT_EQ(1, visitor.setting_count_); - EXPECT_EQ(0, visitor.error_count_); -} - -TEST_P(SpdyFramerTest, ReadKnownAndUnknownSettingsWithExtension) { - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x12, // Length: 18 - 0x04, // Type: SETTINGS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x00, 0x10, // Param: 16 - 0x00, 0x00, 0x00, 0x02, // Value: 2 - 0x00, 0x5f, // Param: 95 - 0x00, 0x01, 0x00, 0x02, // Value: 65538 - 0x00, 0x02, // Param: ENABLE_PUSH - 0x00, 0x00, 0x00, 0x01, // Value: 1 - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - TestExtension extension; - visitor.set_extension_visitor(&extension); - visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData)); - - // In HTTP/2, we ignore unknown settings because of extensions. However, we - // pass the SETTINGS to the visitor, which can decide how to handle them. - EXPECT_EQ(3, visitor.setting_count_); - EXPECT_EQ(0, visitor.error_count_); - - // The extension receives all SETTINGS, including the non-standard SETTINGS. - EXPECT_THAT( - extension.settings_received_, - testing::ElementsAre(testing::Pair(16, 2), testing::Pair(95, 65538), - testing::Pair(2, 1))); -} - -// Tests handling of SETTINGS frame with entries out of order. -TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) { - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x12, // Length: 18 - 0x04, // Type: SETTINGS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x00, 0x02, // Param: ENABLE_PUSH - 0x00, 0x00, 0x00, 0x02, // Value: 2 - 0x00, 0x01, // Param: HEADER_TABLE_SIZE - 0x00, 0x00, 0x00, 0x03, // Value: 3 - 0x00, 0x03, // Param: MAX_CONCURRENT_STREAMS - 0x00, 0x00, 0x00, 0x03, // Value: 3 - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData)); - - // In HTTP/2, settings are allowed in any order. - EXPECT_EQ(3, visitor.setting_count_); - EXPECT_EQ(0, visitor.error_count_); -} - -TEST_P(SpdyFramerTest, ProcessSettingsAckFrame) { - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x00, // Length: 0 - 0x04, // Type: SETTINGS - 0x01, // Flags: ACK - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); - - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(0, visitor.setting_count_); - EXPECT_EQ(1, visitor.settings_ack_received_); -} - -TEST_P(SpdyFramerTest, ProcessDataFrameWithPadding) { - const int kPaddingLen = 119; - const char data_payload[] = "hello"; - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - deframer_.set_visitor(&visitor); - - SpdyDataIR data_ir(/* stream_id = */ 1, data_payload); - data_ir.set_padding_len(kPaddingLen); - SpdySerializedFrame frame(framer_.SerializeData(data_ir)); - - int bytes_consumed = 0; - - // Send the frame header. - EXPECT_CALL(visitor, - OnDataFrameHeader(1, kPaddingLen + strlen(data_payload), false)); - CHECK_EQ(kDataFrameMinimumSize, - deframer_.ProcessInput(frame.data(), kDataFrameMinimumSize)); - CHECK_EQ(deframer_.state(), - Http2DecoderAdapter::SPDY_READ_DATA_FRAME_PADDING_LENGTH); - CHECK_EQ(deframer_.spdy_framer_error(), Http2DecoderAdapter::SPDY_NO_ERROR); - bytes_consumed += kDataFrameMinimumSize; - - // Send the padding length field. - EXPECT_CALL(visitor, OnStreamPadLength(1, kPaddingLen - 1)); - CHECK_EQ(1u, deframer_.ProcessInput(frame.data() + bytes_consumed, 1)); - CHECK_EQ(deframer_.state(), Http2DecoderAdapter::SPDY_FORWARD_STREAM_FRAME); - CHECK_EQ(deframer_.spdy_framer_error(), Http2DecoderAdapter::SPDY_NO_ERROR); - bytes_consumed += 1; - - // Send the first two bytes of the data payload, i.e., "he". - EXPECT_CALL(visitor, OnStreamFrameData(1, _, 2)); - CHECK_EQ(2u, deframer_.ProcessInput(frame.data() + bytes_consumed, 2)); - CHECK_EQ(deframer_.state(), Http2DecoderAdapter::SPDY_FORWARD_STREAM_FRAME); - CHECK_EQ(deframer_.spdy_framer_error(), Http2DecoderAdapter::SPDY_NO_ERROR); - bytes_consumed += 2; - - // Send the rest three bytes of the data payload, i.e., "llo". - EXPECT_CALL(visitor, OnStreamFrameData(1, _, 3)); - CHECK_EQ(3u, deframer_.ProcessInput(frame.data() + bytes_consumed, 3)); - CHECK_EQ(deframer_.state(), Http2DecoderAdapter::SPDY_CONSUME_PADDING); - CHECK_EQ(deframer_.spdy_framer_error(), Http2DecoderAdapter::SPDY_NO_ERROR); - bytes_consumed += 3; - - // Send the first 100 bytes of the padding payload. - EXPECT_CALL(visitor, OnStreamPadding(1, 100)); - CHECK_EQ(100u, deframer_.ProcessInput(frame.data() + bytes_consumed, 100)); - CHECK_EQ(deframer_.state(), Http2DecoderAdapter::SPDY_CONSUME_PADDING); - CHECK_EQ(deframer_.spdy_framer_error(), Http2DecoderAdapter::SPDY_NO_ERROR); - bytes_consumed += 100; - - // Send rest of the padding payload. - EXPECT_CALL(visitor, OnStreamPadding(1, 18)); - CHECK_EQ(18u, deframer_.ProcessInput(frame.data() + bytes_consumed, 18)); - CHECK_EQ(deframer_.state(), Http2DecoderAdapter::SPDY_READY_FOR_FRAME); - CHECK_EQ(deframer_.spdy_framer_error(), Http2DecoderAdapter::SPDY_NO_ERROR); -} - -TEST_P(SpdyFramerTest, ReadWindowUpdate) { - SpdySerializedFrame control_frame(framer_.SerializeWindowUpdate( - SpdyWindowUpdateIR(/* stream_id = */ 1, /* delta = */ 2))); - if (use_output_) { - ASSERT_TRUE(framer_.SerializeWindowUpdate( - SpdyWindowUpdateIR(/* stream_id = */ 1, /* delta = */ 2), &output_)); - control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - control_frame.size()); - EXPECT_EQ(1u, visitor.last_window_update_stream_); - EXPECT_EQ(2, visitor.last_window_update_delta_); -} - -TEST_P(SpdyFramerTest, ReadCompressedPushPromise) { - SpdyPushPromiseIR push_promise(/* stream_id = */ 42, - /* promised_stream_id = */ 57); - push_promise.SetHeader("foo", "bar"); - push_promise.SetHeader("bar", "foofoo"); - SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( - &framer_, push_promise, use_output_ ? &output_ : nullptr)); - TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); - visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()), - frame.size()); - EXPECT_EQ(42u, visitor.last_push_promise_stream_); - EXPECT_EQ(57u, visitor.last_push_promise_promised_stream_); - EXPECT_EQ(push_promise.header_block(), visitor.headers_); -} - -TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) { - // frame-format off - const unsigned char kInput[] = { - 0x00, 0x00, 0x14, // Length: 20 - 0x01, // Type: HEADERS - 0x08, // Flags: PADDED - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x03, // PadLen: 3 trailing bytes - 0x00, // Unindexed Entry - 0x06, // Name Len: 6 - 'c', 'o', 'o', 'k', 'i', 'e', // Name - 0x07, // Value Len: 7 - 'f', 'o', 'o', '=', 'b', 'a', 'r', // Value - 0x00, 0x00, 0x00, // Padding - - 0x00, 0x00, 0x14, // Length: 20 - 0x09, // Type: CONTINUATION - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, // Unindexed Entry - 0x06, // Name Len: 6 - 'c', 'o', 'o', 'k', 'i', 'e', // Name - 0x08, // Value Len: 7 - 'b', 'a', 'z', '=', 'b', 'i', 'n', 'g', // Value - 0x00, // Unindexed Entry - 0x06, // Name Len: 6 - 'c', // Name (split) - - 0x00, 0x00, 0x12, // Length: 18 - 0x09, // Type: CONTINUATION - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 'o', 'o', 'k', 'i', 'e', // Name (continued) - 0x00, // Value Len: 0 - 0x00, // Unindexed Entry - 0x04, // Name Len: 4 - 'n', 'a', 'm', 'e', // Name - 0x05, // Value Len: 5 - 'v', 'a', 'l', 'u', 'e', // Value - }; - // frame-format on - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kInput, sizeof(kInput)); - - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(2, visitor.continuation_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - EXPECT_EQ(0, visitor.end_of_stream_count_); - - EXPECT_THAT( - visitor.headers_, - testing::ElementsAre(testing::Pair("cookie", "foo=bar; baz=bing; "), - testing::Pair("name", "value"))); -} - -TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) { - // frame-format off - const unsigned char kInput[] = { - 0x00, 0x00, 0x10, // Length: 20 - 0x01, // Type: HEADERS - 0x01, // Flags: END_STREAM - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, // Unindexed Entry - 0x06, // Name Len: 6 - 'c', 'o', 'o', 'k', 'i', 'e', // Name - 0x07, // Value Len: 7 - 'f', 'o', 'o', '=', 'b', 'a', 'r', // Value - - 0x00, 0x00, 0x14, // Length: 20 - 0x09, // Type: CONTINUATION - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, // Unindexed Entry - 0x06, // Name Len: 6 - 'c', 'o', 'o', 'k', 'i', 'e', // Name - 0x08, // Value Len: 7 - 'b', 'a', 'z', '=', 'b', 'i', 'n', 'g', // Value - 0x00, // Unindexed Entry - 0x06, // Name Len: 6 - 'c', // Name (split) - - 0x00, 0x00, 0x12, // Length: 18 - 0x09, // Type: CONTINUATION - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 'o', 'o', 'k', 'i', 'e', // Name (continued) - 0x00, // Value Len: 0 - 0x00, // Unindexed Entry - 0x04, // Name Len: 4 - 'n', 'a', 'm', 'e', // Name - 0x05, // Value Len: 5 - 'v', 'a', 'l', 'u', 'e', // Value - }; - // frame-format on - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kInput, sizeof(kInput)); - - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(2, visitor.continuation_count_); - EXPECT_EQ(1, visitor.fin_flag_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - EXPECT_EQ(1, visitor.end_of_stream_count_); - - EXPECT_THAT( - visitor.headers_, - testing::ElementsAre(testing::Pair("cookie", "foo=bar; baz=bing; "), - testing::Pair("name", "value"))); -} - -TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) { - // frame-format off - const unsigned char kInput[] = { - 0x00, 0x00, 0x17, // Length: 23 - 0x05, // Type: PUSH_PROMISE - 0x08, // Flags: PADDED - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x02, // PadLen: 2 trailing bytes - 0x00, 0x00, 0x00, 0x2a, // Promise: 42 - 0x00, // Unindexed Entry - 0x06, // Name Len: 6 - 'c', 'o', 'o', 'k', 'i', 'e', // Name - 0x07, // Value Len: 7 - 'f', 'o', 'o', '=', 'b', 'a', 'r', // Value - 0x00, 0x00, // Padding - - 0x00, 0x00, 0x14, // Length: 20 - 0x09, // Type: CONTINUATION - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, // Unindexed Entry - 0x06, // Name Len: 6 - 'c', 'o', 'o', 'k', 'i', 'e', // Name - 0x08, // Value Len: 7 - 'b', 'a', 'z', '=', 'b', 'i', 'n', 'g', // Value - 0x00, // Unindexed Entry - 0x06, // Name Len: 6 - 'c', // Name (split) - - 0x00, 0x00, 0x12, // Length: 18 - 0x09, // Type: CONTINUATION - 0x04, // Flags: END_HEADERS - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 'o', 'o', 'k', 'i', 'e', // Name (continued) - 0x00, // Value Len: 0 - 0x00, // Unindexed Entry - 0x04, // Name Len: 4 - 'n', 'a', 'm', 'e', // Name - 0x05, // Value Len: 5 - 'v', 'a', 'l', 'u', 'e', // Value - }; - // frame-format on - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kInput, sizeof(kInput)); - - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1u, visitor.last_push_promise_stream_); - EXPECT_EQ(42u, visitor.last_push_promise_promised_stream_); - EXPECT_EQ(2, visitor.continuation_count_); - EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); - EXPECT_EQ(0, visitor.end_of_stream_count_); - - EXPECT_THAT( - visitor.headers_, - testing::ElementsAre(testing::Pair("cookie", "foo=bar; baz=bing; "), - testing::Pair("name", "value"))); -} - -// Receiving an unknown frame when a continuation is expected should -// result in a SPDY_UNEXPECTED_FRAME error -TEST_P(SpdyFramerTest, ReceiveUnknownMidContinuation) { - const unsigned char kInput[] = { - 0x00, 0x00, 0x10, // Length: 16 - 0x01, // Type: HEADERS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x06, 0x63, 0x6f, // HPACK - 0x6f, 0x6b, 0x69, 0x65, // - 0x07, 0x66, 0x6f, 0x6f, // - 0x3d, 0x62, 0x61, 0x72, // - - 0x00, 0x00, 0x14, // Length: 20 - 0xa9, // Type: UnknownFrameType(169) - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x06, 0x63, 0x6f, // Payload - 0x6f, 0x6b, 0x69, 0x65, // - 0x08, 0x62, 0x61, 0x7a, // - 0x3d, 0x62, 0x69, 0x6e, // - 0x67, 0x00, 0x06, 0x63, // - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - // Assume the unknown frame is allowed - visitor.on_unknown_frame_result_ = true; - deframer_.set_visitor(&visitor); - visitor.SimulateInFramer(kInput, sizeof(kInput)); - - EXPECT_EQ(1, visitor.error_count_); - EXPECT_EQ(Http2DecoderAdapter::SPDY_UNEXPECTED_FRAME, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(0, visitor.continuation_count_); - EXPECT_EQ(0u, visitor.header_buffer_length_); -} - -// Receiving an unknown frame when a continuation is expected should -// result in a SPDY_UNEXPECTED_FRAME error -TEST_P(SpdyFramerTest, ReceiveUnknownMidContinuationWithExtension) { - const unsigned char kInput[] = { - 0x00, 0x00, 0x10, // Length: 16 - 0x01, // Type: HEADERS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x06, 0x63, 0x6f, // HPACK - 0x6f, 0x6b, 0x69, 0x65, // - 0x07, 0x66, 0x6f, 0x6f, // - 0x3d, 0x62, 0x61, 0x72, // - - 0x00, 0x00, 0x14, // Length: 20 - 0xa9, // Type: UnknownFrameType(169) - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x06, 0x63, 0x6f, // Payload - 0x6f, 0x6b, 0x69, 0x65, // - 0x08, 0x62, 0x61, 0x7a, // - 0x3d, 0x62, 0x69, 0x6e, // - 0x67, 0x00, 0x06, 0x63, // - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - TestExtension extension; - visitor.set_extension_visitor(&extension); - deframer_.set_visitor(&visitor); - visitor.SimulateInFramer(kInput, sizeof(kInput)); - - EXPECT_EQ(1, visitor.error_count_); - EXPECT_EQ(Http2DecoderAdapter::SPDY_UNEXPECTED_FRAME, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(0, visitor.continuation_count_); - EXPECT_EQ(0u, visitor.header_buffer_length_); -} - -TEST_P(SpdyFramerTest, ReceiveContinuationOnWrongStream) { - const unsigned char kInput[] = { - 0x00, 0x00, 0x10, // Length: 16 - 0x01, // Type: HEADERS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x06, 0x63, 0x6f, // HPACK - 0x6f, 0x6b, 0x69, 0x65, // - 0x07, 0x66, 0x6f, 0x6f, // - 0x3d, 0x62, 0x61, 0x72, // - - 0x00, 0x00, 0x14, // Length: 20 - 0x09, // Type: CONTINUATION - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x02, // Stream: 2 - 0x00, 0x06, 0x63, 0x6f, // HPACK - 0x6f, 0x6b, 0x69, 0x65, // - 0x08, 0x62, 0x61, 0x7a, // - 0x3d, 0x62, 0x69, 0x6e, // - 0x67, 0x00, 0x06, 0x63, // - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - deframer_.set_visitor(&visitor); - visitor.SimulateInFramer(kInput, sizeof(kInput)); - - EXPECT_EQ(1, visitor.error_count_); - EXPECT_EQ(Http2DecoderAdapter::SPDY_UNEXPECTED_FRAME, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(0, visitor.continuation_count_); - EXPECT_EQ(0u, visitor.header_buffer_length_); -} - -TEST_P(SpdyFramerTest, ReadContinuationOutOfOrder) { - const unsigned char kInput[] = { - 0x00, 0x00, 0x18, // Length: 24 - 0x09, // Type: CONTINUATION - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x06, 0x63, 0x6f, // HPACK - 0x6f, 0x6b, 0x69, 0x65, // - 0x07, 0x66, 0x6f, 0x6f, // - 0x3d, 0x62, 0x61, 0x72, // - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - deframer_.set_visitor(&visitor); - visitor.SimulateInFramer(kInput, sizeof(kInput)); - - EXPECT_EQ(1, visitor.error_count_); - EXPECT_EQ(Http2DecoderAdapter::SPDY_UNEXPECTED_FRAME, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); - EXPECT_EQ(0, visitor.continuation_count_); - EXPECT_EQ(0u, visitor.header_buffer_length_); -} - -TEST_P(SpdyFramerTest, ExpectContinuationReceiveData) { - const unsigned char kInput[] = { - 0x00, 0x00, 0x10, // Length: 16 - 0x01, // Type: HEADERS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x06, 0x63, 0x6f, // HPACK - 0x6f, 0x6b, 0x69, 0x65, // - 0x07, 0x66, 0x6f, 0x6f, // - 0x3d, 0x62, 0x61, 0x72, // - - 0x00, 0x00, 0x00, // Length: 0 - 0x00, // Type: DATA - 0x01, // Flags: END_STREAM - 0x00, 0x00, 0x00, 0x04, // Stream: 4 - - 0xde, 0xad, 0xbe, 0xef, // Truncated Frame Header - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - deframer_.set_visitor(&visitor); - visitor.SimulateInFramer(kInput, sizeof(kInput)); - - EXPECT_EQ(1, visitor.error_count_); - EXPECT_EQ(Http2DecoderAdapter::SPDY_UNEXPECTED_FRAME, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(0, visitor.continuation_count_); - EXPECT_EQ(0u, visitor.header_buffer_length_); - EXPECT_EQ(0, visitor.data_frame_count_); -} - -TEST_P(SpdyFramerTest, ExpectContinuationReceiveControlFrame) { - const unsigned char kInput[] = { - 0x00, 0x00, 0x10, // Length: 16 - 0x01, // Type: HEADERS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x06, 0x63, 0x6f, // HPACK - 0x6f, 0x6b, 0x69, 0x65, // - 0x07, 0x66, 0x6f, 0x6f, // - 0x3d, 0x62, 0x61, 0x72, // - - 0x00, 0x00, 0x10, // Length: 16 - 0x01, // Type: HEADERS - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x06, 0x63, 0x6f, // HPACK - 0x6f, 0x6b, 0x69, 0x65, // - 0x07, 0x66, 0x6f, 0x6f, // - 0x3d, 0x62, 0x61, 0x72, // - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - deframer_.set_visitor(&visitor); - visitor.SimulateInFramer(kInput, sizeof(kInput)); - - EXPECT_EQ(1, visitor.error_count_); - EXPECT_EQ(Http2DecoderAdapter::SPDY_UNEXPECTED_FRAME, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); - EXPECT_EQ(1, visitor.headers_frame_count_); - EXPECT_EQ(0, visitor.continuation_count_); - EXPECT_EQ(0u, visitor.header_buffer_length_); - EXPECT_EQ(0, visitor.data_frame_count_); -} - -TEST_P(SpdyFramerTest, ReadGarbage) { - unsigned char garbage_frame[256]; - memset(garbage_frame, ~0, sizeof(garbage_frame)); - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame)); - EXPECT_EQ(1, visitor.error_count_); -} - -TEST_P(SpdyFramerTest, ReadUnknownExtensionFrame) { - // The unrecognized frame type should still have a valid length. - const unsigned char unknown_frame[] = { - 0x00, 0x00, 0x08, // Length: 8 - 0xff, // Type: UnknownFrameType(255) - 0xff, // Flags: 0xff - 0xff, 0xff, 0xff, 0xff, // Stream: 0x7fffffff (R-bit set) - 0xff, 0xff, 0xff, 0xff, // Payload - 0xff, 0xff, 0xff, 0xff, // - }; - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - - // Simulate the case where the stream id validation checks out. - visitor.on_unknown_frame_result_ = true; - visitor.SimulateInFramer(unknown_frame, SPDY_ARRAYSIZE(unknown_frame)); - EXPECT_EQ(0, visitor.error_count_); - - // Follow it up with a valid control frame to make sure we handle - // subsequent frames correctly. - SpdySettingsIR settings_ir; - settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 10); - SpdySerializedFrame control_frame(framer_.SerializeSettings(settings_ir)); - if (use_output_) { - ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_)); - control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - control_frame.size()); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.setting_count_); - EXPECT_EQ(1, visitor.settings_ack_sent_); -} - -TEST_P(SpdyFramerTest, ReadUnknownExtensionFrameWithExtension) { - // The unrecognized frame type should still have a valid length. - const unsigned char unknown_frame[] = { - 0x00, 0x00, 0x14, // Length: 20 - 0xff, // Type: UnknownFrameType(255) - 0xff, // Flags: 0xff - 0xff, 0xff, 0xff, 0xff, // Stream: 0x7fffffff (R-bit set) - 0xff, 0xff, 0xff, 0xff, // Payload - 0xff, 0xff, 0xff, 0xff, // - 0xff, 0xff, 0xff, 0xff, // - 0xff, 0xff, 0xff, 0xff, // - 0xff, 0xff, 0xff, 0xff, // - }; - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - TestExtension extension; - visitor.set_extension_visitor(&extension); - visitor.SimulateInFramer(unknown_frame, SPDY_ARRAYSIZE(unknown_frame)); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(0x7fffffffu, extension.stream_id_); - EXPECT_EQ(20u, extension.length_); - EXPECT_EQ(255, extension.type_); - EXPECT_EQ(0xff, extension.flags_); - EXPECT_EQ(SpdyString(20, '\xff'), extension.payload_); - - // Follow it up with a valid control frame to make sure we handle - // subsequent frames correctly. - SpdySettingsIR settings_ir; - settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 10); - SpdySerializedFrame control_frame(framer_.SerializeSettings(settings_ir)); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - control_frame.size()); - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.setting_count_); - EXPECT_EQ(1, visitor.settings_ack_sent_); -} - -TEST_P(SpdyFramerTest, ReadGarbageWithValidLength) { - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x08, // Length: 8 - 0xff, // Type: UnknownFrameType(255) - 0xff, // Flags: 0xff - 0xff, 0xff, 0xff, 0xff, // Stream: 0x7fffffff (R-bit set) - 0xff, 0xff, 0xff, 0xff, // Payload - 0xff, 0xff, 0xff, 0xff, // - }; - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kFrameData, SPDY_ARRAYSIZE(kFrameData)); - EXPECT_EQ(1, visitor.error_count_); -} - -TEST_P(SpdyFramerTest, ReadGarbageHPACKEncoding) { - const unsigned char kInput[] = { - 0x00, 0x12, 0x01, // Length: 4609 - 0x04, // Type: SETTINGS - 0x00, // Flags: none - 0x00, 0x00, 0x01, 0xef, // Stream: 495 - 0xef, 0xff, // Param: 61439 - 0xff, 0xff, 0xff, 0xff, // Value: 4294967295 - 0xff, 0xff, // Param: 0xffff - 0xff, 0xff, 0xff, 0xff, // Value: 4294967295 - 0xff, 0xff, 0xff, 0xff, // Settings (Truncated) - 0xff, // - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kInput, SPDY_ARRAYSIZE(kInput)); - EXPECT_EQ(1, visitor.error_count_); -} - -TEST_P(SpdyFramerTest, SizesTest) { - EXPECT_EQ(9u, kFrameHeaderSize); - EXPECT_EQ(9u, kDataFrameMinimumSize); - EXPECT_EQ(9u, kHeadersFrameMinimumSize); - EXPECT_EQ(14u, kPriorityFrameSize); - EXPECT_EQ(13u, kRstStreamFrameSize); - EXPECT_EQ(9u, kSettingsFrameMinimumSize); - EXPECT_EQ(13u, kPushPromiseFrameMinimumSize); - EXPECT_EQ(17u, kPingFrameSize); - EXPECT_EQ(17u, kGoawayFrameMinimumSize); - EXPECT_EQ(13u, kWindowUpdateFrameSize); - EXPECT_EQ(9u, kContinuationFrameMinimumSize); - EXPECT_EQ(11u, kGetAltSvcFrameMinimumSize); - EXPECT_EQ(9u, kFrameMinimumSize); - - EXPECT_EQ(16384u, kHttp2DefaultFramePayloadLimit); - EXPECT_EQ(16393u, kHttp2DefaultFrameSizeLimit); -} - -TEST_P(SpdyFramerTest, StateToStringTest) { - EXPECT_STREQ("ERROR", Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_ERROR)); - EXPECT_STREQ("FRAME_COMPLETE", Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_FRAME_COMPLETE)); - EXPECT_STREQ("READY_FOR_FRAME", - Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_READY_FOR_FRAME)); - EXPECT_STREQ("READING_COMMON_HEADER", - Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_READING_COMMON_HEADER)); - EXPECT_STREQ("CONTROL_FRAME_PAYLOAD", - Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_CONTROL_FRAME_PAYLOAD)); - EXPECT_STREQ("IGNORE_REMAINING_PAYLOAD", - Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_IGNORE_REMAINING_PAYLOAD)); - EXPECT_STREQ("FORWARD_STREAM_FRAME", - Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_FORWARD_STREAM_FRAME)); - EXPECT_STREQ( - "SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK", - Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK)); - EXPECT_STREQ("SPDY_CONTROL_FRAME_HEADER_BLOCK", - Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_CONTROL_FRAME_HEADER_BLOCK)); - EXPECT_STREQ("SPDY_SETTINGS_FRAME_PAYLOAD", - Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_SETTINGS_FRAME_PAYLOAD)); - EXPECT_STREQ("SPDY_ALTSVC_FRAME_PAYLOAD", - Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_ALTSVC_FRAME_PAYLOAD)); - EXPECT_STREQ("UNKNOWN_STATE", - Http2DecoderAdapter::StateToString( - Http2DecoderAdapter::SPDY_ALTSVC_FRAME_PAYLOAD + 1)); -} - -TEST_P(SpdyFramerTest, SpdyFramerErrorToStringTest) { - EXPECT_STREQ("NO_ERROR", Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_NO_ERROR)); - EXPECT_STREQ("INVALID_STREAM_ID", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_INVALID_STREAM_ID)); - EXPECT_STREQ("INVALID_CONTROL_FRAME", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME)); - EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_CONTROL_PAYLOAD_TOO_LARGE)); - EXPECT_STREQ("ZLIB_INIT_FAILURE", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_ZLIB_INIT_FAILURE)); - EXPECT_STREQ("UNSUPPORTED_VERSION", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_UNSUPPORTED_VERSION)); - EXPECT_STREQ("DECOMPRESS_FAILURE", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_DECOMPRESS_FAILURE)); - EXPECT_STREQ("COMPRESS_FAILURE", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_COMPRESS_FAILURE)); - EXPECT_STREQ("GOAWAY_FRAME_CORRUPT", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_GOAWAY_FRAME_CORRUPT)); - EXPECT_STREQ("RST_STREAM_FRAME_CORRUPT", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_RST_STREAM_FRAME_CORRUPT)); - EXPECT_STREQ("INVALID_PADDING", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_INVALID_PADDING)); - EXPECT_STREQ("INVALID_DATA_FRAME_FLAGS", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_INVALID_DATA_FRAME_FLAGS)); - EXPECT_STREQ("INVALID_CONTROL_FRAME_FLAGS", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME_FLAGS)); - EXPECT_STREQ("UNEXPECTED_FRAME", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_UNEXPECTED_FRAME)); - EXPECT_STREQ("INTERNAL_FRAMER_ERROR", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_INTERNAL_FRAMER_ERROR)); - EXPECT_STREQ("INVALID_CONTROL_FRAME_SIZE", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME_SIZE)); - EXPECT_STREQ("OVERSIZED_PAYLOAD", - Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::SPDY_OVERSIZED_PAYLOAD)); - EXPECT_STREQ("UNKNOWN_ERROR", Http2DecoderAdapter::SpdyFramerErrorToString( - Http2DecoderAdapter::LAST_ERROR)); - EXPECT_STREQ("UNKNOWN_ERROR", - Http2DecoderAdapter::SpdyFramerErrorToString( - static_cast<Http2DecoderAdapter::SpdyFramerError>( - Http2DecoderAdapter::LAST_ERROR + 1))); -} - -TEST_P(SpdyFramerTest, DataFrameFlagsV4) { - uint8_t valid_data_flags = DATA_FLAG_FIN | DATA_FLAG_PADDED; - - uint8_t flags = 0; - do { - SCOPED_TRACE(testing::Message() - << "Flags " << std::hex << static_cast<int>(flags)); - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - SpdyDataIR data_ir(/* stream_id = */ 1, "hello"); - SpdySerializedFrame frame(framer_.SerializeData(data_ir)); - SetFrameFlags(&frame, flags); - - if (flags & ~valid_data_flags) { - EXPECT_CALL(visitor, OnError(_)); - } else { - EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN)); - if (flags & DATA_FLAG_PADDED) { - // The first byte of payload is parsed as padding length, but 'h' - // (0x68) is too large a padding length for a 5 byte payload. - EXPECT_CALL(visitor, OnStreamPadding(_, 1)); - // Expect Error since the frame ends prematurely. - EXPECT_CALL(visitor, OnError(_)); - } else { - EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5)); - if (flags & DATA_FLAG_FIN) { - EXPECT_CALL(visitor, OnStreamEnd(_)); - } - } - } - - deframer_.ProcessInput(frame.data(), frame.size()); - if (flags & ~valid_data_flags) { - EXPECT_EQ(Http2DecoderAdapter::SPDY_ERROR, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_DATA_FRAME_FLAGS, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); - } else if (flags & DATA_FLAG_PADDED) { - EXPECT_EQ(Http2DecoderAdapter::SPDY_ERROR, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_PADDING, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); - } else { - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); - } - deframer_.Reset(); - } while (++flags != 0); -} - -TEST_P(SpdyFramerTest, RstStreamFrameFlags) { - uint8_t flags = 0; - do { - SCOPED_TRACE(testing::Message() - << "Flags " << std::hex << static_cast<int>(flags)); - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - deframer_.set_visitor(&visitor); - - SpdyRstStreamIR rst_stream(/* stream_id = */ 13, ERROR_CODE_CANCEL); - SpdySerializedFrame frame(framer_.SerializeRstStream(rst_stream)); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializeRstStream(rst_stream, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - SetFrameFlags(&frame, flags); - - EXPECT_CALL(visitor, OnRstStream(13, ERROR_CODE_CANCEL)); - - deframer_.ProcessInput(frame.data(), frame.size()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); - deframer_.Reset(); - } while (++flags != 0); -} - -TEST_P(SpdyFramerTest, SettingsFrameFlags) { - uint8_t flags = 0; - do { - SCOPED_TRACE(testing::Message() - << "Flags " << std::hex << static_cast<int>(flags)); - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - deframer_.set_visitor(&visitor); - - SpdySettingsIR settings_ir; - settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 16); - SpdySerializedFrame frame(framer_.SerializeSettings(settings_ir)); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - SetFrameFlags(&frame, flags); - - if (flags & SETTINGS_FLAG_ACK) { - EXPECT_CALL(visitor, OnError(_)); - } else { - EXPECT_CALL(visitor, OnSettings()); - EXPECT_CALL(visitor, OnSetting(SETTINGS_INITIAL_WINDOW_SIZE, 16)); - EXPECT_CALL(visitor, OnSettingsEnd()); - } - - deframer_.ProcessInput(frame.data(), frame.size()); - if (flags & SETTINGS_FLAG_ACK) { - // The frame is invalid because ACK frames should have no payload. - EXPECT_EQ(Http2DecoderAdapter::SPDY_ERROR, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME_SIZE, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); - } else { - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); - } - deframer_.Reset(); - } while (++flags != 0); -} - -TEST_P(SpdyFramerTest, GoawayFrameFlags) { - uint8_t flags = 0; - do { - SCOPED_TRACE(testing::Message() - << "Flags " << std::hex << static_cast<int>(flags)); - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - SpdyGoAwayIR goaway_ir(/* last_good_stream_id = */ 97, ERROR_CODE_NO_ERROR, - "test"); - SpdySerializedFrame frame(framer_.SerializeGoAway(goaway_ir)); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializeGoAway(goaway_ir, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - SetFrameFlags(&frame, flags); - - EXPECT_CALL(visitor, OnGoAway(97, ERROR_CODE_NO_ERROR)); - - deframer_.ProcessInput(frame.data(), frame.size()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); - deframer_.Reset(); - } while (++flags != 0); -} - -TEST_P(SpdyFramerTest, HeadersFrameFlags) { - uint8_t flags = 0; - do { - SCOPED_TRACE(testing::Message() - << "Flags " << std::hex << static_cast<int>(flags)); - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); - Http2DecoderAdapter deframer; - deframer.set_visitor(&visitor); - - SpdyHeadersIR headers_ir(/* stream_id = */ 57); - if (flags & HEADERS_FLAG_PRIORITY) { - headers_ir.set_weight(3); - headers_ir.set_has_priority(true); - headers_ir.set_parent_stream_id(5); - headers_ir.set_exclusive(true); - } - headers_ir.SetHeader("foo", "bar"); - SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( - &framer, headers_ir, use_output_ ? &output_ : nullptr)); - uint8_t set_flags = flags & ~HEADERS_FLAG_PADDED; - SetFrameFlags(&frame, set_flags); - - // Expected callback values - SpdyStreamId stream_id = 57; - bool has_priority = false; - int weight = 0; - SpdyStreamId parent_stream_id = 0; - bool exclusive = false; - bool fin = flags & CONTROL_FLAG_FIN; - bool end = flags & HEADERS_FLAG_END_HEADERS; - if (flags & HEADERS_FLAG_PRIORITY) { - has_priority = true; - weight = 3; - parent_stream_id = 5; - exclusive = true; - } - EXPECT_CALL(visitor, OnHeaders(stream_id, has_priority, weight, - parent_stream_id, exclusive, fin, end)); - EXPECT_CALL(visitor, OnHeaderFrameStart(57)).Times(1); - if (end) { - EXPECT_CALL(visitor, OnHeaderFrameEnd(57)).Times(1); - } - if (flags & DATA_FLAG_FIN && end) { - EXPECT_CALL(visitor, OnStreamEnd(_)); - } else { - // Do not close the stream if we are expecting a CONTINUATION frame. - EXPECT_CALL(visitor, OnStreamEnd(_)).Times(0); - } - - deframer.ProcessInput(frame.data(), frame.size()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer.spdy_framer_error()); - deframer.Reset(); - } while (++flags != 0); -} - -TEST_P(SpdyFramerTest, PingFrameFlags) { - uint8_t flags = 0; - do { - SCOPED_TRACE(testing::Message() - << "Flags " << std::hex << static_cast<int>(flags)); - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - deframer_.set_visitor(&visitor); - - SpdySerializedFrame frame(framer_.SerializePing(SpdyPingIR(42))); - SetFrameFlags(&frame, flags); - - EXPECT_CALL(visitor, OnPing(42, flags & PING_FLAG_ACK)); - - deframer_.ProcessInput(frame.data(), frame.size()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); - deframer_.Reset(); - } while (++flags != 0); -} - -TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) { - uint8_t flags = 0; - do { - SCOPED_TRACE(testing::Message() - << "Flags " << std::hex << static_cast<int>(flags)); - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - SpdySerializedFrame frame(framer_.SerializeWindowUpdate( - SpdyWindowUpdateIR(/* stream_id = */ 4, /* delta = */ 1024))); - SetFrameFlags(&frame, flags); - - EXPECT_CALL(visitor, OnWindowUpdate(4, 1024)); - - deframer_.ProcessInput(frame.data(), frame.size()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); - deframer_.Reset(); - } while (++flags != 0); -} - -TEST_P(SpdyFramerTest, PushPromiseFrameFlags) { - const SpdyStreamId client_id = 123; // Must be odd. - const SpdyStreamId promised_id = 22; // Must be even. - uint8_t flags = 0; - do { - SCOPED_TRACE(testing::Message() - << "Flags " << std::hex << static_cast<int>(flags)); - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - testing::StrictMock<test::MockDebugVisitor> debug_visitor; - SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); - Http2DecoderAdapter deframer; - deframer.set_visitor(&visitor); - deframer.set_debug_visitor(&debug_visitor); - framer.set_debug_visitor(&debug_visitor); - - EXPECT_CALL( - debug_visitor, - OnSendCompressedFrame(client_id, SpdyFrameType::PUSH_PROMISE, _, _)); - - SpdyPushPromiseIR push_promise(client_id, promised_id); - push_promise.SetHeader("foo", "bar"); - SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( - &framer, push_promise, use_output_ ? &output_ : nullptr)); - // TODO(jgraettinger): Add padding to SpdyPushPromiseIR, - // and implement framing. - SetFrameFlags(&frame, flags & ~HEADERS_FLAG_PADDED); - - bool end = flags & PUSH_PROMISE_FLAG_END_PUSH_PROMISE; - EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame( - client_id, SpdyFrameType::PUSH_PROMISE, _)); - EXPECT_CALL(visitor, OnPushPromise(client_id, promised_id, end)); - EXPECT_CALL(visitor, OnHeaderFrameStart(client_id)).Times(1); - if (end) { - EXPECT_CALL(visitor, OnHeaderFrameEnd(client_id)).Times(1); - } - - deframer.ProcessInput(frame.data(), frame.size()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer.spdy_framer_error()); - } while (++flags != 0); -} - -TEST_P(SpdyFramerTest, ContinuationFrameFlags) { - uint8_t flags = 0; - do { - if (use_output_) { - output_.Reset(); - } - SCOPED_TRACE(testing::Message() - << "Flags " << std::hex << static_cast<int>(flags)); - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - testing::StrictMock<test::MockDebugVisitor> debug_visitor; - SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); - Http2DecoderAdapter deframer; - deframer.set_visitor(&visitor); - deframer.set_debug_visitor(&debug_visitor); - framer.set_debug_visitor(&debug_visitor); - - EXPECT_CALL(debug_visitor, - OnSendCompressedFrame(42, SpdyFrameType::HEADERS, _, _)); - EXPECT_CALL(debug_visitor, - OnReceiveCompressedFrame(42, SpdyFrameType::HEADERS, _)); - EXPECT_CALL(visitor, OnHeaders(42, false, 0, 0, false, false, false)); - EXPECT_CALL(visitor, OnHeaderFrameStart(42)).Times(1); - - SpdyHeadersIR headers_ir(/* stream_id = */ 42); - headers_ir.SetHeader("foo", "bar"); - SpdySerializedFrame frame0; - if (use_output_) { - EXPECT_TRUE(framer.SerializeHeaders(headers_ir, &output_)); - frame0 = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } else { - frame0 = framer.SerializeHeaders(headers_ir); - } - SetFrameFlags(&frame0, 0); - - SpdyContinuationIR continuation(/* stream_id = */ 42); - SpdySerializedFrame frame1; - if (use_output_) { - char* begin = output_.Begin() + output_.Size(); - ASSERT_TRUE(framer.SerializeContinuation(continuation, &output_)); - frame1 = - SpdySerializedFrame(begin, output_.Size() - frame0.size(), false); - } else { - frame1 = framer.SerializeContinuation(continuation); - } - SetFrameFlags(&frame1, flags); - - EXPECT_CALL(debug_visitor, - OnReceiveCompressedFrame(42, SpdyFrameType::CONTINUATION, _)); - EXPECT_CALL(visitor, OnContinuation(42, flags & HEADERS_FLAG_END_HEADERS)); - bool end = flags & HEADERS_FLAG_END_HEADERS; - if (end) { - EXPECT_CALL(visitor, OnHeaderFrameEnd(42)).Times(1); - } - - deframer.ProcessInput(frame0.data(), frame0.size()); - deframer.ProcessInput(frame1.data(), frame1.size()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer.spdy_framer_error()); - } while (++flags != 0); -} - -// TODO(mlavan): Add TEST_P(SpdyFramerTest, AltSvcFrameFlags) - -// Test handling of a RST_STREAM with out-of-bounds status codes. -TEST_P(SpdyFramerTest, RstStreamStatusBounds) { - const unsigned char kH2RstStreamInvalid[] = { - 0x00, 0x00, 0x04, // Length: 4 - 0x03, // Type: RST_STREAM - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR - }; - const unsigned char kH2RstStreamNumStatusCodes[] = { - 0x00, 0x00, 0x04, // Length: 4 - 0x03, // Type: RST_STREAM - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0xff, // Error: 255 - }; - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - deframer_.set_visitor(&visitor); - - EXPECT_CALL(visitor, OnRstStream(1, ERROR_CODE_NO_ERROR)); - deframer_.ProcessInput(reinterpret_cast<const char*>(kH2RstStreamInvalid), - SPDY_ARRAYSIZE(kH2RstStreamInvalid)); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); - deframer_.Reset(); - - EXPECT_CALL(visitor, OnRstStream(1, ERROR_CODE_INTERNAL_ERROR)); - deframer_.ProcessInput( - reinterpret_cast<const char*>(kH2RstStreamNumStatusCodes), - SPDY_ARRAYSIZE(kH2RstStreamNumStatusCodes)); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Test handling of GOAWAY frames with out-of-bounds status code. -TEST_P(SpdyFramerTest, GoAwayStatusBounds) { - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x0a, // Length: 10 - 0x07, // Type: GOAWAY - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x00, 0x00, 0x00, 0x01, // Last: 1 - 0xff, 0xff, 0xff, 0xff, // Error: 0xffffffff - 0x47, 0x41, // Description - }; - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - deframer_.set_visitor(&visitor); - - EXPECT_CALL(visitor, OnGoAway(1, ERROR_CODE_INTERNAL_ERROR)); - deframer_.ProcessInput(reinterpret_cast<const char*>(kH2FrameData), - SPDY_ARRAYSIZE(kH2FrameData)); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Tests handling of a GOAWAY frame with out-of-bounds stream ID. -TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) { - const unsigned char kH2FrameData[] = { - 0x00, 0x00, 0x08, // Length: 8 - 0x07, // Type: GOAWAY - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0xff, 0xff, 0xff, 0xff, // Last: 0x7fffffff (R-bit set) - 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR - }; - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - EXPECT_CALL(visitor, OnGoAway(0x7fffffff, ERROR_CODE_NO_ERROR)); - deframer_.ProcessInput(reinterpret_cast<const char*>(kH2FrameData), - SPDY_ARRAYSIZE(kH2FrameData)); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -TEST_P(SpdyFramerTest, OnAltSvcWithOrigin) { - const SpdyStreamId kStreamId = 0; // Stream id must be zero if origin given. - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - SpdyAltSvcWireFormat::AlternativeService altsvc1( - "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()); - SpdyAltSvcWireFormat::AlternativeService altsvc2( - "p\"=i:d", "h_\\o\"st", 123, 42, SpdyAltSvcWireFormat::VersionVector{24}); - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - altsvc_vector.push_back(altsvc1); - altsvc_vector.push_back(altsvc2); - EXPECT_CALL(visitor, - OnAltSvc(kStreamId, SpdyStringPiece("o_r|g!n"), altsvc_vector)); - - SpdyAltSvcIR altsvc_ir(kStreamId); - altsvc_ir.set_origin("o_r|g!n"); - altsvc_ir.add_altsvc(altsvc1); - altsvc_ir.add_altsvc(altsvc2); - SpdySerializedFrame frame(framer_.SerializeFrame(altsvc_ir)); - if (use_output_) { - output_.Reset(); - EXPECT_EQ(framer_.SerializeFrame(altsvc_ir, &output_), frame.size()); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - deframer_.ProcessInput(frame.data(), frame.size()); - - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -TEST_P(SpdyFramerTest, OnAltSvcNoOrigin) { - const SpdyStreamId kStreamId = 1; - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - SpdyAltSvcWireFormat::AlternativeService altsvc1( - "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()); - SpdyAltSvcWireFormat::AlternativeService altsvc2( - "p\"=i:d", "h_\\o\"st", 123, 42, SpdyAltSvcWireFormat::VersionVector{24}); - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - altsvc_vector.push_back(altsvc1); - altsvc_vector.push_back(altsvc2); - EXPECT_CALL(visitor, OnAltSvc(kStreamId, SpdyStringPiece(""), altsvc_vector)); - - SpdyAltSvcIR altsvc_ir(kStreamId); - altsvc_ir.add_altsvc(altsvc1); - altsvc_ir.add_altsvc(altsvc2); - SpdySerializedFrame frame(framer_.SerializeFrame(altsvc_ir)); - deframer_.ProcessInput(frame.data(), frame.size()); - - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -TEST_P(SpdyFramerTest, OnAltSvcEmptyProtocolId) { - const SpdyStreamId kStreamId = 0; // Stream id must be zero if origin given. - - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - - deframer_.set_visitor(&visitor); - - EXPECT_CALL(visitor, - OnError(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME)); - - SpdyAltSvcIR altsvc_ir(kStreamId); - altsvc_ir.set_origin("o1"); - altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService( - "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector())); - altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService( - "", "h1", 443, 10, SpdyAltSvcWireFormat::VersionVector())); - SpdySerializedFrame frame(framer_.SerializeFrame(altsvc_ir)); - if (use_output_) { - output_.Reset(); - EXPECT_EQ(framer_.SerializeFrame(altsvc_ir, &output_), frame.size()); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - deframer_.ProcessInput(frame.data(), frame.size()); - - EXPECT_EQ(Http2DecoderAdapter::SPDY_ERROR, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -TEST_P(SpdyFramerTest, OnAltSvcBadLengths) { - const unsigned char kType = SerializeFrameType(SpdyFrameType::ALTSVC); - const unsigned char kFrameDataOriginLenLargerThanFrame[] = { - 0x00, 0x00, 0x05, kType, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x42, 0x42, 'f', 'o', 'o', - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - - deframer_.set_visitor(&visitor); - visitor.SimulateInFramer(kFrameDataOriginLenLargerThanFrame, - sizeof(kFrameDataOriginLenLargerThanFrame)); - - EXPECT_EQ(1, visitor.error_count_); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME, - visitor.deframer_.spdy_framer_error()); -} - -// Tests handling of ALTSVC frames delivered in small chunks. -TEST_P(SpdyFramerTest, ReadChunkedAltSvcFrame) { - SpdyAltSvcIR altsvc_ir(/* stream_id = */ 1); - SpdyAltSvcWireFormat::AlternativeService altsvc1( - "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()); - SpdyAltSvcWireFormat::AlternativeService altsvc2( - "p\"=i:d", "h_\\o\"st", 123, 42, SpdyAltSvcWireFormat::VersionVector{24}); - altsvc_ir.add_altsvc(altsvc1); - altsvc_ir.add_altsvc(altsvc2); - - SpdySerializedFrame control_frame(framer_.SerializeAltSvc(altsvc_ir)); - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - - // Read data in small chunks. - size_t framed_data = 0; - size_t unframed_data = control_frame.size(); - size_t kReadChunkSize = 5; // Read five bytes at a time. - while (unframed_data > 0) { - size_t to_read = std::min(kReadChunkSize, unframed_data); - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data() + framed_data), - to_read); - unframed_data -= to_read; - framed_data += to_read; - } - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.altsvc_count_); - ASSERT_NE(nullptr, visitor.test_altsvc_ir_); - ASSERT_EQ(2u, visitor.test_altsvc_ir_->altsvc_vector().size()); - EXPECT_TRUE(visitor.test_altsvc_ir_->altsvc_vector()[0] == altsvc1); - EXPECT_TRUE(visitor.test_altsvc_ir_->altsvc_vector()[1] == altsvc2); -} - -// While RFC7838 Section 4 says that an ALTSVC frame on stream 0 with empty -// origin MUST be ignored, it is not implemented at the framer level: instead, -// such frames are passed on to the consumer. -TEST_P(SpdyFramerTest, ReadAltSvcFrame) { - constexpr struct { - uint32_t stream_id; - const char* origin; - } test_cases[] = {{0, ""}, - {1, ""}, - {0, "https://www.example.com"}, - {1, "https://www.example.com"}}; - for (const auto& test_case : test_cases) { - SpdyAltSvcIR altsvc_ir(test_case.stream_id); - SpdyAltSvcWireFormat::AlternativeService altsvc( - "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()); - altsvc_ir.add_altsvc(altsvc); - altsvc_ir.set_origin(test_case.origin); - SpdySerializedFrame frame(framer_.SerializeAltSvc(altsvc_ir)); - - TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); - deframer_.set_visitor(&visitor); - deframer_.ProcessInput(frame.data(), frame.size()); - - EXPECT_EQ(0, visitor.error_count_); - EXPECT_EQ(1, visitor.altsvc_count_); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); - } -} - -// An ALTSVC frame with invalid Alt-Svc-Field-Value results in an error. -TEST_P(SpdyFramerTest, ErrorOnAltSvcFrameWithInvalidValue) { - // Alt-Svc-Field-Value must be "clear" or must contain an "=" character - // per RFC7838 Section 3. - const char kFrameData[] = { - 0x00, 0x00, 0x16, // Length: 22 - 0x0a, // Type: ALTSVC - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, // Origin-Len: 0 - 0x74, 0x68, 0x69, 0x73, // thisisnotavalidvalue - 0x69, 0x73, 0x6e, 0x6f, 0x74, 0x61, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x76, 0x61, 0x6c, 0x75, 0x65, - }; - - TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); - deframer_.set_visitor(&visitor); - deframer_.ProcessInput(kFrameData, sizeof(kFrameData)); - - EXPECT_EQ(1, visitor.error_count_); - EXPECT_EQ(0, visitor.altsvc_count_); - EXPECT_EQ(Http2DecoderAdapter::SPDY_ERROR, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME, - deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Tests handling of PRIORITY frames. -TEST_P(SpdyFramerTest, ReadPriority) { - SpdyPriorityIR priority(/* stream_id = */ 3, - /* parent_stream_id = */ 1, - /* weight = */ 256, - /* exclusive = */ false); - SpdySerializedFrame frame(framer_.SerializePriority(priority)); - if (use_output_) { - output_.Reset(); - ASSERT_TRUE(framer_.SerializePriority(priority, &output_)); - frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); - } - testing::StrictMock<test::MockSpdyFramerVisitor> visitor; - deframer_.set_visitor(&visitor); - EXPECT_CALL(visitor, OnPriority(3, 1, 256, false)); - deframer_.ProcessInput(frame.data(), frame.size()); - - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_NO_ERROR, deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - deframer_.spdy_framer_error()); -} - -// Tests handling of PRIORITY frame with incorrect size. -TEST_P(SpdyFramerTest, ReadIncorrectlySizedPriority) { - // PRIORITY frame of size 4, which isn't correct. - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x04, // Length: 4 - 0x02, // Type: PRIORITY - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x03, // Stream: 3 - 0x00, 0x00, 0x00, 0x01, // Priority (Truncated) - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); - - EXPECT_EQ(Http2DecoderAdapter::SPDY_ERROR, visitor.deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME_SIZE, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); -} - -// Tests handling of PING frame with incorrect size. -TEST_P(SpdyFramerTest, ReadIncorrectlySizedPing) { - // PING frame of size 4, which isn't correct. - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x04, // Length: 4 - 0x06, // Type: PING - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x00, // Stream: 0 - 0x00, 0x00, 0x00, 0x01, // Ping (Truncated) - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); - - EXPECT_EQ(Http2DecoderAdapter::SPDY_ERROR, visitor.deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME_SIZE, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); -} - -// Tests handling of WINDOW_UPDATE frame with incorrect size. -TEST_P(SpdyFramerTest, ReadIncorrectlySizedWindowUpdate) { - // WINDOW_UPDATE frame of size 3, which isn't correct. - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x03, // Length: 3 - 0x08, // Type: WINDOW_UPDATE - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x03, // Stream: 3 - 0x00, 0x00, 0x01, // WindowUpdate (Truncated) - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); - - EXPECT_EQ(Http2DecoderAdapter::SPDY_ERROR, visitor.deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME_SIZE, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); -} - -// Tests handling of RST_STREAM frame with incorrect size. -TEST_P(SpdyFramerTest, ReadIncorrectlySizedRstStream) { - // RST_STREAM frame of size 3, which isn't correct. - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x03, // Length: 3 - 0x03, // Type: RST_STREAM - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x03, // Stream: 3 - 0x00, 0x00, 0x01, // RstStream (Truncated) - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); - - EXPECT_EQ(Http2DecoderAdapter::SPDY_ERROR, visitor.deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME_SIZE, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); -} - -// Regression test for https://crbug.com/548674: -// RST_STREAM with payload must not be accepted. -TEST_P(SpdyFramerTest, ReadInvalidRstStreamWithPayload) { - const unsigned char kFrameData[] = { - 0x00, 0x00, 0x07, // Length: 7 - 0x03, // Type: RST_STREAM - 0x00, // Flags: none - 0x00, 0x00, 0x00, 0x01, // Stream: 1 - 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR - 'f', 'o', 'o' // Payload: "foo" - }; - - TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); - visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); - - EXPECT_EQ(Http2DecoderAdapter::SPDY_ERROR, visitor.deframer_.state()); - EXPECT_EQ(Http2DecoderAdapter::SPDY_INVALID_CONTROL_FRAME_SIZE, - visitor.deframer_.spdy_framer_error()) - << Http2DecoderAdapter::SpdyFramerErrorToString( - visitor.deframer_.spdy_framer_error()); -} - -// Test that SpdyFramer processes, by default, all passed input in one call -// to ProcessInput (i.e. will not be calling set_process_single_input_frame()). -TEST_P(SpdyFramerTest, ProcessAllInput) { - auto visitor = - SpdyMakeUnique<TestSpdyVisitor>(SpdyFramer::DISABLE_COMPRESSION); - deframer_.set_visitor(visitor.get()); - - // Create two input frames. - SpdyHeadersIR headers(/* stream_id = */ 1); - headers.SetHeader("alpha", "beta"); - headers.SetHeader("gamma", "charlie"); - headers.SetHeader("cookie", "key1=value1; key2=value2"); - SpdySerializedFrame headers_frame(SpdyFramerPeer::SerializeHeaders( - &framer_, headers, use_output_ ? &output_ : nullptr)); - - const char four_score[] = "Four score and seven years ago"; - SpdyDataIR four_score_ir(/* stream_id = */ 1, four_score); - SpdySerializedFrame four_score_frame(framer_.SerializeData(four_score_ir)); - - // Put them in a single buffer (new variables here to make it easy to - // change the order and type of frames). - SpdySerializedFrame frame1 = std::move(headers_frame); - SpdySerializedFrame frame2 = std::move(four_score_frame); - - const size_t frame1_size = frame1.size(); - const size_t frame2_size = frame2.size(); - - VLOG(1) << "frame1_size = " << frame1_size; - VLOG(1) << "frame2_size = " << frame2_size; - - SpdyString input_buffer; - input_buffer.append(frame1.data(), frame1_size); - input_buffer.append(frame2.data(), frame2_size); - - const char* buf = input_buffer.data(); - const size_t buf_size = input_buffer.size(); - - VLOG(1) << "buf_size = " << buf_size; - - size_t processed = deframer_.ProcessInput(buf, buf_size); - EXPECT_EQ(buf_size, processed); - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - EXPECT_EQ(1, visitor->headers_frame_count_); - EXPECT_EQ(1, visitor->data_frame_count_); - EXPECT_EQ(strlen(four_score), static_cast<unsigned>(visitor->data_bytes_)); -} - -// Test that SpdyFramer stops after processing a full frame if -// process_single_input_frame is set. Input to ProcessInput has two frames, but -// only processes the first when we give it the first frame split at any point, -// or give it more than one frame in the input buffer. -TEST_P(SpdyFramerTest, ProcessAtMostOneFrame) { - deframer_.set_process_single_input_frame(true); - - // Create two input frames. - const char four_score[] = "Four score and ..."; - SpdyDataIR four_score_ir(/* stream_id = */ 1, four_score); - SpdySerializedFrame four_score_frame(framer_.SerializeData(four_score_ir)); - - SpdyHeadersIR headers(/* stream_id = */ 2); - headers.SetHeader("alpha", "beta"); - headers.SetHeader("gamma", "charlie"); - headers.SetHeader("cookie", "key1=value1; key2=value2"); - SpdySerializedFrame headers_frame(SpdyFramerPeer::SerializeHeaders( - &framer_, headers, use_output_ ? &output_ : nullptr)); - - // Put them in a single buffer (new variables here to make it easy to - // change the order and type of frames). - SpdySerializedFrame frame1 = std::move(four_score_frame); - SpdySerializedFrame frame2 = std::move(headers_frame); - - const size_t frame1_size = frame1.size(); - const size_t frame2_size = frame2.size(); - - VLOG(1) << "frame1_size = " << frame1_size; - VLOG(1) << "frame2_size = " << frame2_size; - - SpdyString input_buffer; - input_buffer.append(frame1.data(), frame1_size); - input_buffer.append(frame2.data(), frame2_size); - - const char* buf = input_buffer.data(); - const size_t buf_size = input_buffer.size(); - - VLOG(1) << "buf_size = " << buf_size; - - for (size_t first_size = 0; first_size <= buf_size; ++first_size) { - VLOG(1) << "first_size = " << first_size; - auto visitor = - SpdyMakeUnique<TestSpdyVisitor>(SpdyFramer::DISABLE_COMPRESSION); - deframer_.set_visitor(visitor.get()); - - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - - size_t processed_first = deframer_.ProcessInput(buf, first_size); - if (first_size < frame1_size) { - EXPECT_EQ(first_size, processed_first); - - if (first_size == 0) { - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - } else { - EXPECT_NE(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - } - - const char* rest = buf + processed_first; - const size_t remaining = buf_size - processed_first; - VLOG(1) << "remaining = " << remaining; - - size_t processed_second = deframer_.ProcessInput(rest, remaining); - - // Redundant tests just to make it easier to think about. - EXPECT_EQ(frame1_size - processed_first, processed_second); - size_t processed_total = processed_first + processed_second; - EXPECT_EQ(frame1_size, processed_total); - } else { - EXPECT_EQ(frame1_size, processed_first); - } - - EXPECT_EQ(Http2DecoderAdapter::SPDY_READY_FOR_FRAME, deframer_.state()); - - // At this point should have processed the entirety of the first frame, - // and none of the second frame. - - EXPECT_EQ(1, visitor->data_frame_count_); - EXPECT_EQ(strlen(four_score), static_cast<unsigned>(visitor->data_bytes_)); - EXPECT_EQ(0, visitor->headers_frame_count_); - } -} - -namespace { -void CheckFrameAndIRSize(SpdyFrameIR* ir, - SpdyFramer* framer, - ArrayOutputBuffer* output_buffer) { - output_buffer->Reset(); - SpdyFrameType type = ir->frame_type(); - size_t ir_size = ir->size(); - framer->SerializeFrame(*ir, output_buffer); - if (type == SpdyFrameType::HEADERS || type == SpdyFrameType::PUSH_PROMISE) { - // For HEADERS and PUSH_PROMISE, the size is an estimate. - EXPECT_GE(ir_size, output_buffer->Size() * 9 / 10); - EXPECT_LT(ir_size, output_buffer->Size() * 11 / 10); - } else { - EXPECT_EQ(ir_size, output_buffer->Size()); - } -} -} // namespace - -TEST_P(SpdyFramerTest, SpdyFrameIRSize) { - SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); - - const char bytes[] = "this is a very short data frame"; - SpdyDataIR data_ir(1, SpdyStringPiece(bytes, SPDY_ARRAYSIZE(bytes))); - CheckFrameAndIRSize(&data_ir, &framer, &output_); - - SpdyRstStreamIR rst_ir(/* stream_id = */ 1, ERROR_CODE_PROTOCOL_ERROR); - CheckFrameAndIRSize(&rst_ir, &framer, &output_); - - SpdySettingsIR settings_ir; - settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 5); - settings_ir.AddSetting(SETTINGS_ENABLE_PUSH, 6); - settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 7); - CheckFrameAndIRSize(&settings_ir, &framer, &output_); - - SpdyPingIR ping_ir(42); - CheckFrameAndIRSize(&ping_ir, &framer, &output_); - - SpdyGoAwayIR goaway_ir(97, ERROR_CODE_NO_ERROR, "Goaway description"); - CheckFrameAndIRSize(&goaway_ir, &framer, &output_); - - SpdyHeadersIR headers_ir(1); - headers_ir.SetHeader("alpha", "beta"); - headers_ir.SetHeader("gamma", "charlie"); - headers_ir.SetHeader("cookie", "key1=value1; key2=value2"); - CheckFrameAndIRSize(&headers_ir, &framer, &output_); - - SpdyHeadersIR headers_ir_with_continuation(1); - headers_ir_with_continuation.SetHeader("alpha", SpdyString(100000, 'x')); - headers_ir_with_continuation.SetHeader("beta", SpdyString(100000, 'x')); - headers_ir_with_continuation.SetHeader("cookie", "key1=value1; key2=value2"); - CheckFrameAndIRSize(&headers_ir_with_continuation, &framer, &output_); - - SpdyWindowUpdateIR window_update_ir(4, 1024); - CheckFrameAndIRSize(&window_update_ir, &framer, &output_); - - SpdyPushPromiseIR push_promise_ir(3, 8); - push_promise_ir.SetHeader("alpha", SpdyString(100000, 'x')); - push_promise_ir.SetHeader("beta", SpdyString(100000, 'x')); - push_promise_ir.SetHeader("cookie", "key1=value1; key2=value2"); - CheckFrameAndIRSize(&push_promise_ir, &framer, &output_); - - SpdyAltSvcWireFormat::AlternativeService altsvc1( - "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()); - SpdyAltSvcWireFormat::AlternativeService altsvc2( - "p\"=i:d", "h_\\o\"st", 123, 42, SpdyAltSvcWireFormat::VersionVector{24}); - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; - altsvc_vector.push_back(altsvc1); - altsvc_vector.push_back(altsvc2); - SpdyAltSvcIR altsvc_ir(0); - altsvc_ir.set_origin("o_r|g!n"); - altsvc_ir.add_altsvc(altsvc1); - altsvc_ir.add_altsvc(altsvc2); - CheckFrameAndIRSize(&altsvc_ir, &framer, &output_); - - SpdyPriorityIR priority_ir(3, 1, 256, false); - CheckFrameAndIRSize(&priority_ir, &framer, &output_); - - const char kDescription[] = "Unknown frame"; - const uint8_t kType = 0xaf; - const uint8_t kFlags = 0x11; - SpdyUnknownIR unknown_ir(2, kType, kFlags, kDescription); - CheckFrameAndIRSize(&unknown_ir, &framer, &output_); -} - -} // namespace test - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_header_block.cc b/net/third_party/spdy/core/spdy_header_block.cc deleted file mode 100644 index 94ed0db..0000000 --- a/net/third_party/spdy/core/spdy_header_block.cc +++ /dev/null
@@ -1,395 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_header_block.h" - -#include <string.h> - -#include <algorithm> -#include <utility> - -#include "base/logging.h" -#include "base/macros.h" -#include "net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h" -#include "net/third_party/spdy/platform/api/spdy_ptr_util.h" -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" -#include "net/third_party/spdy/platform/api/spdy_unsafe_arena.h" - -namespace spdy { -namespace { - -// By default, linked_hash_map's internal map allocates space for 100 map -// buckets on construction, which is larger than necessary. Standard library -// unordered map implementations use a list of prime numbers to set the bucket -// count for a particular capacity. |kInitialMapBuckets| is chosen to reduce -// memory usage for small header blocks, at the cost of having to rehash for -// large header blocks. -const size_t kInitialMapBuckets = 11; - -// SpdyHeaderBlock::Storage allocates blocks of this size by default. -const size_t kDefaultStorageBlockSize = 2048; - -const char kCookieKey[] = "cookie"; -const char kNullSeparator = 0; - -SpdyStringPiece SeparatorForKey(SpdyStringPiece key) { - if (key == kCookieKey) { - static SpdyStringPiece cookie_separator = "; "; - return cookie_separator; - } else { - return SpdyStringPiece(&kNullSeparator, 1); - } -} - -} // namespace - -// This class provides a backing store for SpdyStringPieces. It previously used -// custom allocation logic, but now uses an UnsafeArena instead. It has the -// property that SpdyStringPieces that refer to data in Storage are never -// invalidated until the Storage is deleted or Clear() is called. -// -// Write operations always append to the last block. If there is not enough -// space to perform the write, a new block is allocated, and any unused space -// is wasted. -class SpdyHeaderBlock::Storage { - public: - Storage() : arena_(kDefaultStorageBlockSize) {} - Storage(const Storage&) = delete; - Storage& operator=(const Storage&) = delete; - - SpdyStringPiece Write(const SpdyStringPiece s) { - return SpdyStringPiece(arena_.Memdup(s.data(), s.size()), s.size()); - } - - // If |s| points to the most recent allocation from arena_, the arena will - // reclaim the memory. Otherwise, this method is a no-op. - void Rewind(const SpdyStringPiece s) { - arena_.Free(const_cast<char*>(s.data()), s.size()); - } - - void Clear() { arena_.Reset(); } - - // Given a list of fragments and a separator, writes the fragments joined by - // the separator to a contiguous region of memory. Returns a SpdyStringPiece - // pointing to the region of memory. - SpdyStringPiece WriteFragments(const std::vector<SpdyStringPiece>& fragments, - SpdyStringPiece separator) { - if (fragments.empty()) { - return SpdyStringPiece(); - } - size_t total_size = separator.size() * (fragments.size() - 1); - for (const auto fragment : fragments) { - total_size += fragment.size(); - } - char* dst = arena_.Alloc(total_size); - size_t written = Join(dst, fragments, separator); - DCHECK_EQ(written, total_size); - return SpdyStringPiece(dst, total_size); - } - - size_t bytes_allocated() const { return arena_.status().bytes_allocated(); } - - // TODO(xunjieli): https://crbug.com/669108. Merge this with bytes_allocated() - size_t EstimateMemoryUsage() const { - return arena_.status().bytes_allocated(); - } - - private: - SpdyUnsafeArena arena_; -}; - -SpdyHeaderBlock::HeaderValue::HeaderValue(Storage* storage, - SpdyStringPiece key, - SpdyStringPiece initial_value) - : storage_(storage), - fragments_({initial_value}), - pair_({key, {}}), - size_(initial_value.size()), - separator_size_(SeparatorForKey(key).size()) {} - -SpdyHeaderBlock::HeaderValue::HeaderValue(HeaderValue&& other) - : storage_(other.storage_), - fragments_(std::move(other.fragments_)), - pair_(std::move(other.pair_)), - size_(other.size_), - separator_size_(other.separator_size_) {} - -SpdyHeaderBlock::HeaderValue& SpdyHeaderBlock::HeaderValue::operator=( - HeaderValue&& other) { - storage_ = other.storage_; - fragments_ = std::move(other.fragments_); - pair_ = std::move(other.pair_); - size_ = other.size_; - separator_size_ = other.separator_size_; - return *this; -} - -SpdyHeaderBlock::HeaderValue::~HeaderValue() = default; - -SpdyStringPiece SpdyHeaderBlock::HeaderValue::ConsolidatedValue() const { - if (fragments_.empty()) { - return SpdyStringPiece(); - } - if (fragments_.size() > 1) { - fragments_ = { - storage_->WriteFragments(fragments_, SeparatorForKey(pair_.first))}; - } - return fragments_[0]; -} - -void SpdyHeaderBlock::HeaderValue::Append(SpdyStringPiece fragment) { - size_ += (fragment.size() + separator_size_); - fragments_.push_back(fragment); -} - -const std::pair<SpdyStringPiece, SpdyStringPiece>& -SpdyHeaderBlock::HeaderValue::as_pair() const { - pair_.second = ConsolidatedValue(); - return pair_; -} - -SpdyHeaderBlock::iterator::iterator(MapType::const_iterator it) : it_(it) {} - -SpdyHeaderBlock::iterator::iterator(const iterator& other) = default; - -SpdyHeaderBlock::iterator::~iterator() = default; - -SpdyHeaderBlock::ValueProxy::ValueProxy( - SpdyHeaderBlock::MapType* block, - SpdyHeaderBlock::Storage* storage, - SpdyHeaderBlock::MapType::iterator lookup_result, - const SpdyStringPiece key, - size_t* spdy_header_block_value_size) - : block_(block), - storage_(storage), - lookup_result_(lookup_result), - key_(key), - spdy_header_block_value_size_(spdy_header_block_value_size), - valid_(true) {} - -SpdyHeaderBlock::ValueProxy::ValueProxy(ValueProxy&& other) - : block_(other.block_), - storage_(other.storage_), - lookup_result_(other.lookup_result_), - key_(other.key_), - spdy_header_block_value_size_(other.spdy_header_block_value_size_), - valid_(true) { - other.valid_ = false; -} - -SpdyHeaderBlock::ValueProxy& SpdyHeaderBlock::ValueProxy::operator=( - SpdyHeaderBlock::ValueProxy&& other) { - block_ = other.block_; - storage_ = other.storage_; - lookup_result_ = other.lookup_result_; - key_ = other.key_; - valid_ = true; - other.valid_ = false; - spdy_header_block_value_size_ = other.spdy_header_block_value_size_; - return *this; -} - -SpdyHeaderBlock::ValueProxy::~ValueProxy() { - // If the ValueProxy is destroyed while lookup_result_ == block_->end(), - // the assignment operator was never used, and the block's Storage can - // reclaim the memory used by the key. This makes lookup-only access to - // SpdyHeaderBlock through operator[] memory-neutral. - if (valid_ && lookup_result_ == block_->end()) { - storage_->Rewind(key_); - } -} - -SpdyHeaderBlock::ValueProxy& SpdyHeaderBlock::ValueProxy::operator=( - const SpdyStringPiece value) { - *spdy_header_block_value_size_ += value.size(); - if (lookup_result_ == block_->end()) { - DVLOG(1) << "Inserting: (" << key_ << ", " << value << ")"; - lookup_result_ = - block_ - ->emplace(std::make_pair( - key_, HeaderValue(storage_, key_, storage_->Write(value)))) - .first; - } else { - DVLOG(1) << "Updating key: " << key_ << " with value: " << value; - *spdy_header_block_value_size_ -= lookup_result_->second.SizeEstimate(); - lookup_result_->second = - HeaderValue(storage_, key_, storage_->Write(value)); - } - return *this; -} - -SpdyString SpdyHeaderBlock::ValueProxy::as_string() const { - if (lookup_result_ == block_->end()) { - return ""; - } else { - return SpdyString(lookup_result_->second.value()); - } -} - -SpdyHeaderBlock::SpdyHeaderBlock() : block_(kInitialMapBuckets) {} - -SpdyHeaderBlock::SpdyHeaderBlock(SpdyHeaderBlock&& other) = default; - -SpdyHeaderBlock::~SpdyHeaderBlock() = default; - -SpdyHeaderBlock& SpdyHeaderBlock::operator=(SpdyHeaderBlock&& other) { - block_.swap(other.block_); - storage_.swap(other.storage_); - key_size_ = other.key_size_; - value_size_ = other.value_size_; - return *this; -} - -SpdyHeaderBlock SpdyHeaderBlock::Clone() const { - SpdyHeaderBlock copy; - for (const auto& p : *this) { - copy.AppendHeader(p.first, p.second); - } - return copy; -} - -bool SpdyHeaderBlock::operator==(const SpdyHeaderBlock& other) const { - return size() == other.size() && std::equal(begin(), end(), other.begin()); -} - -bool SpdyHeaderBlock::operator!=(const SpdyHeaderBlock& other) const { - return !(operator==(other)); -} - -SpdyString SpdyHeaderBlock::DebugString() const { - if (empty()) { - return "{}"; - } - - SpdyString output = "\n{\n"; - for (auto it = begin(); it != end(); ++it) { - SpdyStrAppend(&output, " ", it->first, " ", it->second, "\n"); - } - SpdyStrAppend(&output, "}\n"); - return output; -} - -void SpdyHeaderBlock::erase(SpdyStringPiece key) { - auto iter = block_.find(key); - if (iter != block_.end()) { - DVLOG(1) << "Erasing header with name: " << key; - key_size_ -= key.size(); - value_size_ -= iter->second.SizeEstimate(); - block_.erase(iter); - } -} - -void SpdyHeaderBlock::clear() { - key_size_ = 0; - value_size_ = 0; - block_.clear(); - storage_.reset(); -} - -void SpdyHeaderBlock::insert(const SpdyHeaderBlock::value_type& value) { - // TODO(birenroy): Write new value in place of old value, if it fits. - value_size_ += value.second.size(); - - auto iter = block_.find(value.first); - if (iter == block_.end()) { - DVLOG(1) << "Inserting: (" << value.first << ", " << value.second << ")"; - AppendHeader(value.first, value.second); - } else { - DVLOG(1) << "Updating key: " << iter->first - << " with value: " << value.second; - value_size_ -= iter->second.SizeEstimate(); - auto* storage = GetStorage(); - iter->second = - HeaderValue(storage, iter->first, storage->Write(value.second)); - } -} - -SpdyHeaderBlock::ValueProxy SpdyHeaderBlock::operator[]( - const SpdyStringPiece key) { - DVLOG(2) << "Operator[] saw key: " << key; - SpdyStringPiece out_key; - auto iter = block_.find(key); - if (iter == block_.end()) { - // We write the key first, to assure that the ValueProxy has a - // reference to a valid SpdyStringPiece in its operator=. - out_key = WriteKey(key); - DVLOG(2) << "Key written as: " << std::hex - << static_cast<const void*>(key.data()) << ", " << std::dec - << key.size(); - } else { - out_key = iter->first; - } - return ValueProxy(&block_, GetStorage(), iter, out_key, &value_size_); -} - -void SpdyHeaderBlock::AppendValueOrAddHeader(const SpdyStringPiece key, - const SpdyStringPiece value) { - value_size_ += value.size(); - - auto iter = block_.find(key); - if (iter == block_.end()) { - DVLOG(1) << "Inserting: (" << key << ", " << value << ")"; - - AppendHeader(key, value); - return; - } - DVLOG(1) << "Updating key: " << iter->first << "; appending value: " << value; - value_size_ += SeparatorForKey(key).size(); - iter->second.Append(GetStorage()->Write(value)); -} - -size_t SpdyHeaderBlock::EstimateMemoryUsage() const { - // TODO(xunjieli): https://crbug.com/669108. Also include |block_| when EMU() - // supports linked_hash_map. - return SpdyEstimateMemoryUsage(storage_); -} - -void SpdyHeaderBlock::AppendHeader(const SpdyStringPiece key, - const SpdyStringPiece value) { - auto backed_key = WriteKey(key); - auto* storage = GetStorage(); - block_.emplace(std::make_pair( - backed_key, HeaderValue(storage, backed_key, storage->Write(value)))); -} - -SpdyHeaderBlock::Storage* SpdyHeaderBlock::GetStorage() { - if (storage_ == nullptr) { - storage_ = SpdyMakeUnique<Storage>(); - } - return storage_.get(); -} - -SpdyStringPiece SpdyHeaderBlock::WriteKey(const SpdyStringPiece key) { - key_size_ += key.size(); - return GetStorage()->Write(key); -} - -size_t SpdyHeaderBlock::bytes_allocated() const { - if (storage_ == nullptr) { - return 0; - } else { - return storage_->bytes_allocated(); - } -} - -size_t Join(char* dst, - const std::vector<SpdyStringPiece>& fragments, - SpdyStringPiece separator) { - if (fragments.empty()) { - return 0; - } - auto* original_dst = dst; - auto it = fragments.begin(); - memcpy(dst, it->data(), it->size()); - dst += it->size(); - for (++it; it != fragments.end(); ++it) { - memcpy(dst, separator.data(), separator.size()); - dst += separator.size(); - memcpy(dst, it->data(), it->size()); - dst += it->size(); - } - return dst - original_dst; -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_header_block.h b/net/third_party/spdy/core/spdy_header_block.h deleted file mode 100644 index e424b13..0000000 --- a/net/third_party/spdy/core/spdy_header_block.h +++ /dev/null
@@ -1,254 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_HEADER_BLOCK_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_HEADER_BLOCK_H_ - -#include <stddef.h> - -#include <list> -#include <memory> -#include <utility> -#include <vector> - -#include "base/macros.h" -#include "net/third_party/spdy/platform/api/spdy_containers.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_macros.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { - -namespace test { -class SpdyHeaderBlockPeer; -class ValueProxyPeer; -} // namespace test - -// This class provides a key-value map that can be used to store SPDY header -// names and values. This data structure preserves insertion order. -// -// Under the hood, this data structure uses large, contiguous blocks of memory -// to store names and values. Lookups may be performed with SpdyStringPiece -// keys, and values are returned as SpdyStringPieces (via ValueProxy, below). -// Value SpdyStringPieces are valid as long as the SpdyHeaderBlock exists; -// allocated memory is never freed until SpdyHeaderBlock's destruction. -// -// This implementation does not make much of an effort to minimize wasted space. -// It's expected that keys are rarely deleted from a SpdyHeaderBlock. -class SPDY_EXPORT_PRIVATE SpdyHeaderBlock { - private: - class Storage; - - // Stores a list of value fragments that can be joined later with a - // key-dependent separator. - class SPDY_EXPORT_PRIVATE HeaderValue { - public: - HeaderValue(Storage* storage, - SpdyStringPiece key, - SpdyStringPiece initial_value); - - // Moves are allowed. - HeaderValue(HeaderValue&& other); - HeaderValue& operator=(HeaderValue&& other); - - // Copies are not. - HeaderValue(const HeaderValue& other) = delete; - HeaderValue& operator=(const HeaderValue& other) = delete; - - ~HeaderValue(); - - // Consumes at most |fragment.size()| bytes of memory. - void Append(SpdyStringPiece fragment); - - SpdyStringPiece value() const { return as_pair().second; } - const std::pair<SpdyStringPiece, SpdyStringPiece>& as_pair() const; - - // Size estimate including separators. Used when keys are erased from - // SpdyHeaderBlock. - size_t SizeEstimate() const { return size_; } - - private: - // May allocate a large contiguous region of memory to hold the concatenated - // fragments and separators. - SpdyStringPiece ConsolidatedValue() const; - - mutable Storage* storage_; - mutable std::vector<SpdyStringPiece> fragments_; - // The first element is the key; the second is the consolidated value. - mutable std::pair<SpdyStringPiece, SpdyStringPiece> pair_; - size_t size_ = 0; - size_t separator_size_ = 0; - }; - - typedef SpdyLinkedHashMap<SpdyStringPiece, HeaderValue, SpdyStringPieceHash> - MapType; - - public: - typedef std::pair<SpdyStringPiece, SpdyStringPiece> value_type; - - // Provides iteration over a sequence of std::pair<SpdyStringPiece, - // SpdyStringPiece>, even though the underlying MapType::value_type is - // different. Dereferencing the iterator will result in memory allocation for - // multi-value headers. - class SPDY_EXPORT_PRIVATE iterator { - public: - // The following type definitions fulfill the requirements for iterator - // implementations. - typedef std::pair<SpdyStringPiece, SpdyStringPiece> value_type; - typedef value_type& reference; - typedef value_type* pointer; - typedef std::forward_iterator_tag iterator_category; - typedef MapType::iterator::difference_type difference_type; - - // In practice, this iterator only offers access to const value_type. - typedef const value_type& const_reference; - typedef const value_type* const_pointer; - - explicit iterator(MapType::const_iterator it); - iterator(const iterator& other); - ~iterator(); - - // This will result in memory allocation if the value consists of multiple - // fragments. - const_reference operator*() const { return it_->second.as_pair(); } - - const_pointer operator->() const { return &(this->operator*()); } - bool operator==(const iterator& it) const { return it_ == it.it_; } - bool operator!=(const iterator& it) const { return !(*this == it); } - - iterator& operator++() { - it_++; - return *this; - } - - iterator operator++(int) { - auto ret = *this; - this->operator++(); - return ret; - } - - private: - MapType::const_iterator it_; - }; - typedef iterator const_iterator; - - class ValueProxy; - - SpdyHeaderBlock(); - SpdyHeaderBlock(const SpdyHeaderBlock& other) = delete; - SpdyHeaderBlock(SpdyHeaderBlock&& other); - ~SpdyHeaderBlock(); - - SpdyHeaderBlock& operator=(const SpdyHeaderBlock& other) = delete; - SpdyHeaderBlock& operator=(SpdyHeaderBlock&& other); - SpdyHeaderBlock Clone() const; - - bool operator==(const SpdyHeaderBlock& other) const; - bool operator!=(const SpdyHeaderBlock& other) const; - - // Provides a human readable multi-line representation of the stored header - // keys and values. - SpdyString DebugString() const; - - iterator begin() { return iterator(block_.begin()); } - iterator end() { return iterator(block_.end()); } - const_iterator begin() const { return const_iterator(block_.begin()); } - const_iterator end() const { return const_iterator(block_.end()); } - bool empty() const { return block_.empty(); } - size_t size() const { return block_.size(); } - iterator find(SpdyStringPiece key) { return iterator(block_.find(key)); } - const_iterator find(SpdyStringPiece key) const { - return const_iterator(block_.find(key)); - } - void erase(SpdyStringPiece key); - - // Clears both our MapType member and the memory used to hold headers. - void clear(); - - // The next few methods copy data into our backing storage. - - // If key already exists in the block, replaces the value of that key. Else - // adds a new header to the end of the block. - void insert(const value_type& value); - - // If a header with the key is already present, then append the value to the - // existing header value, NUL ("\0") separated unless the key is cookie, in - // which case the separator is "; ". - // If there is no such key, a new header with the key and value is added. - void AppendValueOrAddHeader(const SpdyStringPiece key, - const SpdyStringPiece value); - - // Allows either lookup or mutation of the value associated with a key. - ValueProxy operator[](const SpdyStringPiece key) SPDY_MUST_USE_RESULT; - - // This object provides automatic conversions that allow SpdyHeaderBlock to be - // nearly a drop-in replacement for SpdyLinkedHashMap<SpdyString, SpdyString>. - // It reads data from or writes data to a SpdyHeaderBlock::Storage. - class SPDY_EXPORT_PRIVATE ValueProxy { - public: - ~ValueProxy(); - - // Moves are allowed. - ValueProxy(ValueProxy&& other); - ValueProxy& operator=(ValueProxy&& other); - - // Copies are not. - ValueProxy(const ValueProxy& other) = delete; - ValueProxy& operator=(const ValueProxy& other) = delete; - - // Assignment modifies the underlying SpdyHeaderBlock. - ValueProxy& operator=(const SpdyStringPiece other); - - SpdyString as_string() const; - - private: - friend class SpdyHeaderBlock; - friend class test::ValueProxyPeer; - - ValueProxy(SpdyHeaderBlock::MapType* block, - SpdyHeaderBlock::Storage* storage, - SpdyHeaderBlock::MapType::iterator lookup_result, - const SpdyStringPiece key, - size_t* spdy_header_block_value_size); - - SpdyHeaderBlock::MapType* block_; - SpdyHeaderBlock::Storage* storage_; - SpdyHeaderBlock::MapType::iterator lookup_result_; - SpdyStringPiece key_; - size_t* spdy_header_block_value_size_; - bool valid_; - }; - - // Returns the estimate of dynamically allocated memory in bytes. - size_t EstimateMemoryUsage() const; - - size_t TotalBytesUsed() const { return key_size_ + value_size_; } - - private: - friend class test::SpdyHeaderBlockPeer; - - void AppendHeader(const SpdyStringPiece key, const SpdyStringPiece value); - Storage* GetStorage(); - SpdyStringPiece WriteKey(const SpdyStringPiece key); - size_t bytes_allocated() const; - - // SpdyStringPieces held by |block_| point to memory owned by |*storage_|. - // |storage_| might be nullptr as long as |block_| is empty. - MapType block_; - std::unique_ptr<Storage> storage_; - - size_t key_size_ = 0; - size_t value_size_ = 0; -}; - -// Writes |fragments| to |dst|, joined by |separator|. |dst| must be large -// enough to hold the result. Returns the number of bytes written. -SPDY_EXPORT_PRIVATE size_t Join(char* dst, - const std::vector<SpdyStringPiece>& fragments, - SpdyStringPiece separator); - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_HEADER_BLOCK_H_
diff --git a/net/third_party/spdy/core/spdy_header_block_test.cc b/net/third_party/spdy/core/spdy_header_block_test.cc deleted file mode 100644 index c3cfdbda..0000000 --- a/net/third_party/spdy/core/spdy_header_block_test.cc +++ /dev/null
@@ -1,252 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_header_block.h" - -#include <memory> -#include <utility> - -#include "net/third_party/spdy/core/spdy_test_utils.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::ElementsAre; - -namespace spdy { -namespace test { - -class ValueProxyPeer { - public: - static SpdyStringPiece key(SpdyHeaderBlock::ValueProxy* p) { return p->key_; } -}; - -std::pair<SpdyStringPiece, SpdyStringPiece> Pair(SpdyStringPiece k, - SpdyStringPiece v) { - return std::make_pair(k, v); -} - -// This test verifies that SpdyHeaderBlock behaves correctly when empty. -TEST(SpdyHeaderBlockTest, EmptyBlock) { - SpdyHeaderBlock block; - EXPECT_TRUE(block.empty()); - EXPECT_EQ(0u, block.size()); - EXPECT_EQ(block.end(), block.find("foo")); - EXPECT_TRUE(block.end() == block.begin()); - - // Should have no effect. - block.erase("bar"); -} - -TEST(SpdyHeaderBlockTest, KeyMemoryReclaimedOnLookup) { - SpdyHeaderBlock block; - SpdyStringPiece copied_key1; - { - auto proxy1 = block["some key name"]; - copied_key1 = ValueProxyPeer::key(&proxy1); - } - SpdyStringPiece copied_key2; - { - auto proxy2 = block["some other key name"]; - copied_key2 = ValueProxyPeer::key(&proxy2); - } - // Because proxy1 was never used to modify the block, the memory used for the - // key could be reclaimed and used for the second call to operator[]. - // Therefore, we expect the pointers of the two SpdyStringPieces to be equal. - EXPECT_EQ(copied_key1.data(), copied_key2.data()); - - { - auto proxy1 = block["some key name"]; - block["some other key name"] = "some value"; - } - // Nothing should blow up when proxy1 is destructed, and we should be able to - // modify and access the SpdyHeaderBlock. - block["key"] = "value"; - EXPECT_EQ("value", block["key"]); - EXPECT_EQ("some value", block["some other key name"]); - EXPECT_TRUE(block.find("some key name") == block.end()); -} - -// This test verifies that headers can be set in a variety of ways. -TEST(SpdyHeaderBlockTest, AddHeaders) { - SpdyHeaderBlock block; - block["foo"] = SpdyString(300, 'x'); - block["bar"] = "baz"; - block["qux"] = "qux1"; - block["qux"] = "qux2"; - block.insert(std::make_pair("key", "value")); - - EXPECT_EQ(Pair("foo", SpdyString(300, 'x')), *block.find("foo")); - EXPECT_EQ("baz", block["bar"]); - SpdyString qux("qux"); - EXPECT_EQ("qux2", block[qux]); - ASSERT_NE(block.end(), block.find("key")); - EXPECT_EQ(Pair("key", "value"), *block.find("key")); - - block.erase("key"); - EXPECT_EQ(block.end(), block.find("key")); -} - -// This test verifies that SpdyHeaderBlock can be copied using Clone(). -TEST(SpdyHeaderBlockTest, CopyBlocks) { - SpdyHeaderBlock block1; - block1["foo"] = SpdyString(300, 'x'); - block1["bar"] = "baz"; - block1.insert(std::make_pair("qux", "qux1")); - - SpdyHeaderBlock block2 = block1.Clone(); - SpdyHeaderBlock block3(block1.Clone()); - - EXPECT_EQ(block1, block2); - EXPECT_EQ(block1, block3); -} - -TEST(SpdyHeaderBlockTest, Equality) { - // Test equality and inequality operators. - SpdyHeaderBlock block1; - block1["foo"] = "bar"; - - SpdyHeaderBlock block2; - block2["foo"] = "bar"; - - SpdyHeaderBlock block3; - block3["baz"] = "qux"; - - EXPECT_EQ(block1, block2); - EXPECT_NE(block1, block3); - - block2["baz"] = "qux"; - EXPECT_NE(block1, block2); -} - -// Test that certain methods do not crash on moved-from instances. -TEST(SpdyHeaderBlockTest, MovedFromIsValid) { - SpdyHeaderBlock block1; - block1["foo"] = "bar"; - - SpdyHeaderBlock block2(std::move(block1)); - EXPECT_THAT(block2, ElementsAre(Pair("foo", "bar"))); - - block1["baz"] = "qux"; // NOLINT testing post-move behavior - - SpdyHeaderBlock block3(std::move(block1)); - - block1["foo"] = "bar"; // NOLINT testing post-move behavior - - SpdyHeaderBlock block4(std::move(block1)); - - block1.clear(); // NOLINT testing post-move behavior - EXPECT_TRUE(block1.empty()); - - block1["foo"] = "bar"; - EXPECT_THAT(block1, ElementsAre(Pair("foo", "bar"))); -} - -// This test verifies that headers can be appended to no matter how they were -// added originally. -TEST(SpdyHeaderBlockTest, AppendHeaders) { - SpdyHeaderBlock block; - block["foo"] = "foo"; - block.AppendValueOrAddHeader("foo", "bar"); - EXPECT_EQ(Pair("foo", SpdyString("foo\0bar", 7)), *block.find("foo")); - - block.insert(std::make_pair("foo", "baz")); - EXPECT_EQ("baz", block["foo"]); - EXPECT_EQ(Pair("foo", "baz"), *block.find("foo")); - - // Try all four methods of adding an entry. - block["cookie"] = "key1=value1"; - block.AppendValueOrAddHeader("h1", "h1v1"); - block.insert(std::make_pair("h2", "h2v1")); - - block.AppendValueOrAddHeader("h3", "h3v2"); - block.AppendValueOrAddHeader("h2", "h2v2"); - block.AppendValueOrAddHeader("h1", "h1v2"); - block.AppendValueOrAddHeader("cookie", "key2=value2"); - - block.AppendValueOrAddHeader("cookie", "key3=value3"); - block.AppendValueOrAddHeader("h1", "h1v3"); - block.AppendValueOrAddHeader("h2", "h2v3"); - block.AppendValueOrAddHeader("h3", "h3v3"); - block.AppendValueOrAddHeader("h4", "singleton"); - - EXPECT_EQ("key1=value1; key2=value2; key3=value3", block["cookie"]); - EXPECT_EQ("baz", block["foo"]); - EXPECT_EQ(SpdyString("h1v1\0h1v2\0h1v3", 14), block["h1"]); - EXPECT_EQ(SpdyString("h2v1\0h2v2\0h2v3", 14), block["h2"]); - EXPECT_EQ(SpdyString("h3v2\0h3v3", 9), block["h3"]); - EXPECT_EQ("singleton", block["h4"]); -} - -TEST(JoinTest, JoinEmpty) { - std::vector<SpdyStringPiece> empty; - SpdyStringPiece separator = ", "; - char buf[10] = ""; - size_t written = Join(buf, empty, separator); - EXPECT_EQ(0u, written); -} - -TEST(JoinTest, JoinOne) { - std::vector<SpdyStringPiece> v = {"one"}; - SpdyStringPiece separator = ", "; - char buf[15]; - size_t written = Join(buf, v, separator); - EXPECT_EQ(3u, written); - EXPECT_EQ("one", SpdyStringPiece(buf, written)); -} - -TEST(JoinTest, JoinMultiple) { - std::vector<SpdyStringPiece> v = {"one", "two", "three"}; - SpdyStringPiece separator = ", "; - char buf[15]; - size_t written = Join(buf, v, separator); - EXPECT_EQ(15u, written); - EXPECT_EQ("one, two, three", SpdyStringPiece(buf, written)); -} - -namespace { -size_t SpdyHeaderBlockSize(const SpdyHeaderBlock& block) { - size_t size = 0; - for (const auto& pair : block) { - size += pair.first.size() + pair.second.size(); - } - return size; -} -} // namespace - -// Tests SpdyHeaderBlock SizeEstimate(). -TEST(SpdyHeaderBlockTest, TotalBytesUsed) { - SpdyHeaderBlock block; - const size_t value_size = 300; - block["foo"] = SpdyString(value_size, 'x'); - EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); - block.insert(std::make_pair("key", SpdyString(value_size, 'x'))); - EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); - block.AppendValueOrAddHeader("abc", SpdyString(value_size, 'x')); - EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); - - // Replace value for existing key. - block["foo"] = SpdyString(value_size, 'x'); - EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); - block.insert(std::make_pair("key", SpdyString(value_size, 'x'))); - EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); - // Add value for existing key. - block.AppendValueOrAddHeader("abc", SpdyString(value_size, 'x')); - EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); - - // Copies/clones SpdyHeaderBlock. - size_t block_size = block.TotalBytesUsed(); - SpdyHeaderBlock block_copy = std::move(block); - EXPECT_EQ(block_size, block_copy.TotalBytesUsed()); - - // Erases key. - block_copy.erase("foo"); - EXPECT_EQ(block_copy.TotalBytesUsed(), SpdyHeaderBlockSize(block_copy)); - block_copy.erase("key"); - EXPECT_EQ(block_copy.TotalBytesUsed(), SpdyHeaderBlockSize(block_copy)); - block_copy.erase("abc"); - EXPECT_EQ(block_copy.TotalBytesUsed(), SpdyHeaderBlockSize(block_copy)); -} - -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_headers_handler_interface.h b/net/third_party/spdy/core/spdy_headers_handler_interface.h deleted file mode 100644 index 6c47d54..0000000 --- a/net/third_party/spdy/core/spdy_headers_handler_interface.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_HEADERS_HANDLER_INTERFACE_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_HEADERS_HANDLER_INTERFACE_H_ - -#include <stddef.h> - -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { - -// This interface defines how an object that accepts header data should behave. -// It is used by both SpdyHeadersBlockParser and HpackDecoder. -class SPDY_EXPORT_PRIVATE SpdyHeadersHandlerInterface { - public: - virtual ~SpdyHeadersHandlerInterface() {} - - // A callback method which notifies when the parser starts handling a new - // header block. Will only be called once per block, even if it extends into - // CONTINUATION frames. - virtual void OnHeaderBlockStart() = 0; - - // A callback method which notifies on a header key value pair. Multiple - // values for a given key will be emitted as multiple calls to OnHeader. - virtual void OnHeader(SpdyStringPiece key, SpdyStringPiece value) = 0; - - // A callback method which notifies when the parser finishes handling a - // header block (i.e. the containing frame has the END_HEADERS flag set). - // Also indicates the total number of bytes in this block. - virtual void OnHeaderBlockEnd(size_t uncompressed_header_bytes, - size_t compressed_header_bytes) = 0; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_HEADERS_HANDLER_INTERFACE_H_
diff --git a/net/third_party/spdy/core/spdy_no_op_visitor.cc b/net/third_party/spdy/core/spdy_no_op_visitor.cc deleted file mode 100644 index e621996..0000000 --- a/net/third_party/spdy/core/spdy_no_op_visitor.cc +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_no_op_visitor.h" - -#include <type_traits> - -namespace spdy { -namespace test { - -SpdyNoOpVisitor::SpdyNoOpVisitor() { - static_assert(std::is_abstract<SpdyNoOpVisitor>::value == false, - "Need to update SpdyNoOpVisitor."); -} -SpdyNoOpVisitor::~SpdyNoOpVisitor() = default; - -SpdyHeadersHandlerInterface* SpdyNoOpVisitor::OnHeaderFrameStart( - SpdyStreamId stream_id) { - return this; -} - -bool SpdyNoOpVisitor::OnUnknownFrame(SpdyStreamId stream_id, - uint8_t frame_type) { - return true; -} - -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_no_op_visitor.h b/net/third_party/spdy/core/spdy_no_op_visitor.h deleted file mode 100644 index e8a612cf..0000000 --- a/net/third_party/spdy/core/spdy_no_op_visitor.h +++ /dev/null
@@ -1,89 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// SpdyNoOpVisitor implements several of the visitor and handler interfaces -// to make it easier to write tests that need to provide instances. Other -// interfaces can be added as needed. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_NO_OP_VISITOR_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_NO_OP_VISITOR_H_ - -#include <cstdint> - -#include "net/third_party/spdy/core/http2_frame_decoder_adapter.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { -namespace test { - -class SpdyNoOpVisitor : public SpdyFramerVisitorInterface, - public SpdyFramerDebugVisitorInterface, - public SpdyHeadersHandlerInterface { - public: - SpdyNoOpVisitor(); - ~SpdyNoOpVisitor() override; - - // SpdyFramerVisitorInterface methods: - void OnError(http2::Http2DecoderAdapter::SpdyFramerError error) override {} - SpdyHeadersHandlerInterface* OnHeaderFrameStart( - SpdyStreamId stream_id) override; - void OnHeaderFrameEnd(SpdyStreamId stream_id) override {} - void OnDataFrameHeader(SpdyStreamId stream_id, - size_t length, - bool fin) override {} - void OnStreamFrameData(SpdyStreamId stream_id, - const char* data, - size_t len) override {} - void OnStreamEnd(SpdyStreamId stream_id) override {} - void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {} - void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override {} - void OnSetting(SpdySettingsId id, uint32_t value) override {} - void OnPing(SpdyPingId unique_id, bool is_ack) override {} - void OnSettingsEnd() override {} - void OnSettingsAck() override {} - void OnGoAway(SpdyStreamId last_accepted_stream_id, - SpdyErrorCode error_code) override {} - void OnHeaders(SpdyStreamId stream_id, - bool has_priority, - int weight, - SpdyStreamId parent_stream_id, - bool exclusive, - bool fin, - bool end) override {} - void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {} - void OnPushPromise(SpdyStreamId stream_id, - SpdyStreamId promised_stream_id, - bool end) override {} - void OnContinuation(SpdyStreamId stream_id, bool end) override {} - void OnAltSvc(SpdyStreamId stream_id, - SpdyStringPiece origin, - const SpdyAltSvcWireFormat::AlternativeServiceVector& - altsvc_vector) override {} - void OnPriority(SpdyStreamId stream_id, - SpdyStreamId parent_stream_id, - int weight, - bool exclusive) override {} - bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override; - - // SpdyFramerDebugVisitorInterface methods: - void OnSendCompressedFrame(SpdyStreamId stream_id, - SpdyFrameType type, - size_t payload_len, - size_t frame_len) override {} - void OnReceiveCompressedFrame(SpdyStreamId stream_id, - SpdyFrameType type, - size_t frame_len) override {} - - // SpdyHeadersHandlerInterface methods: - void OnHeaderBlockStart() override {} - void OnHeader(SpdyStringPiece key, SpdyStringPiece value) override {} - void OnHeaderBlockEnd(size_t /* uncompressed_header_bytes */, - size_t /* compressed_header_bytes */) override {} -}; - -} // namespace test -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_NO_OP_VISITOR_H_
diff --git a/net/third_party/spdy/core/spdy_pinnable_buffer_piece.cc b/net/third_party/spdy/core/spdy_pinnable_buffer_piece.cc deleted file mode 100644 index dc274c6..0000000 --- a/net/third_party/spdy/core/spdy_pinnable_buffer_piece.cc +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_pinnable_buffer_piece.h" - -#include <new> - -namespace spdy { - -SpdyPinnableBufferPiece::SpdyPinnableBufferPiece() - : buffer_(nullptr), length_(0) {} - -SpdyPinnableBufferPiece::~SpdyPinnableBufferPiece() = default; - -void SpdyPinnableBufferPiece::Pin() { - if (!storage_ && buffer_ != nullptr && length_ != 0) { - storage_.reset(new char[length_]); - std::copy(buffer_, buffer_ + length_, storage_.get()); - buffer_ = storage_.get(); - } -} - -void SpdyPinnableBufferPiece::Swap(SpdyPinnableBufferPiece* other) { - size_t length = length_; - length_ = other->length_; - other->length_ = length; - - const char* buffer = buffer_; - buffer_ = other->buffer_; - other->buffer_ = buffer; - - storage_.swap(other->storage_); -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_pinnable_buffer_piece.h b/net/third_party/spdy/core/spdy_pinnable_buffer_piece.h deleted file mode 100644 index b68f8552..0000000 --- a/net/third_party/spdy/core/spdy_pinnable_buffer_piece.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_PINNABLE_BUFFER_PIECE_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_PINNABLE_BUFFER_PIECE_H_ - -#include <stddef.h> - -#include <memory> - -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { - -class SpdyPrefixedBufferReader; - -// Helper class of SpdyPrefixedBufferReader. -// Represents a piece of consumed buffer which may (or may not) own its -// underlying storage. Users may "pin" the buffer at a later time to ensure -// a SpdyPinnableBufferPiece owns and retains storage of the buffer. -struct SPDY_EXPORT_PRIVATE SpdyPinnableBufferPiece { - public: - SpdyPinnableBufferPiece(); - ~SpdyPinnableBufferPiece(); - - const char* buffer() const { return buffer_; } - - explicit operator SpdyStringPiece() const { - return SpdyStringPiece(buffer_, length_); - } - - // Allocates and copies the buffer to internal storage. - void Pin(); - - bool IsPinned() const { return storage_ != nullptr; } - - // Swaps buffers, including internal storage, with |other|. - void Swap(SpdyPinnableBufferPiece* other); - - private: - friend class SpdyPrefixedBufferReader; - - const char* buffer_; - size_t length_; - // Null iff |buffer_| isn't pinned. - std::unique_ptr<char[]> storage_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_PINNABLE_BUFFER_PIECE_H_
diff --git a/net/third_party/spdy/core/spdy_pinnable_buffer_piece_test.cc b/net/third_party/spdy/core/spdy_pinnable_buffer_piece_test.cc deleted file mode 100644 index 8051d26..0000000 --- a/net/third_party/spdy/core/spdy_pinnable_buffer_piece_test.cc +++ /dev/null
@@ -1,80 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_pinnable_buffer_piece.h" - -#include "net/third_party/spdy/core/spdy_prefixed_buffer_reader.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -namespace test { - -class SpdyPinnableBufferPieceTest : public ::testing::Test { - protected: - SpdyPrefixedBufferReader Build(const SpdyString& prefix, - const SpdyString& suffix) { - prefix_ = prefix; - suffix_ = suffix; - return SpdyPrefixedBufferReader(prefix_.data(), prefix_.length(), - suffix_.data(), suffix_.length()); - } - SpdyString prefix_, suffix_; -}; - -TEST_F(SpdyPinnableBufferPieceTest, Pin) { - SpdyPrefixedBufferReader reader = Build("foobar", ""); - SpdyPinnableBufferPiece piece; - EXPECT_TRUE(reader.ReadN(6, &piece)); - - // Piece points to underlying prefix storage. - EXPECT_EQ(SpdyStringPiece("foobar"), SpdyStringPiece(piece)); - EXPECT_FALSE(piece.IsPinned()); - EXPECT_EQ(prefix_.data(), piece.buffer()); - - piece.Pin(); - - // Piece now points to allocated storage. - EXPECT_EQ(SpdyStringPiece("foobar"), SpdyStringPiece(piece)); - EXPECT_TRUE(piece.IsPinned()); - EXPECT_NE(prefix_.data(), piece.buffer()); - - // Pinning again has no effect. - const char* buffer = piece.buffer(); - piece.Pin(); - EXPECT_EQ(buffer, piece.buffer()); -} - -TEST_F(SpdyPinnableBufferPieceTest, Swap) { - SpdyPrefixedBufferReader reader = Build("foobar", ""); - SpdyPinnableBufferPiece piece1, piece2; - EXPECT_TRUE(reader.ReadN(4, &piece1)); - EXPECT_TRUE(reader.ReadN(2, &piece2)); - - piece1.Pin(); - - EXPECT_EQ(SpdyStringPiece("foob"), SpdyStringPiece(piece1)); - EXPECT_TRUE(piece1.IsPinned()); - EXPECT_EQ(SpdyStringPiece("ar"), SpdyStringPiece(piece2)); - EXPECT_FALSE(piece2.IsPinned()); - - piece1.Swap(&piece2); - - EXPECT_EQ(SpdyStringPiece("ar"), SpdyStringPiece(piece1)); - EXPECT_FALSE(piece1.IsPinned()); - EXPECT_EQ(SpdyStringPiece("foob"), SpdyStringPiece(piece2)); - EXPECT_TRUE(piece2.IsPinned()); - - SpdyPinnableBufferPiece empty; - piece2.Swap(&empty); - - EXPECT_EQ(SpdyStringPiece(""), SpdyStringPiece(piece2)); - EXPECT_FALSE(piece2.IsPinned()); -} - -} // namespace test - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_prefixed_buffer_reader.cc b/net/third_party/spdy/core/spdy_prefixed_buffer_reader.cc deleted file mode 100644 index bb84505..0000000 --- a/net/third_party/spdy/core/spdy_prefixed_buffer_reader.cc +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_prefixed_buffer_reader.h" - -#include <new> - -#include "base/logging.h" - -namespace spdy { - -SpdyPrefixedBufferReader::SpdyPrefixedBufferReader(const char* prefix, - size_t prefix_length, - const char* suffix, - size_t suffix_length) - : prefix_(prefix), - suffix_(suffix), - prefix_length_(prefix_length), - suffix_length_(suffix_length) {} - -size_t SpdyPrefixedBufferReader::Available() { - return prefix_length_ + suffix_length_; -} - -bool SpdyPrefixedBufferReader::ReadN(size_t count, char* out) { - if (Available() < count) { - return false; - } - - if (prefix_length_ >= count) { - // Read is fully satisfied by the prefix. - std::copy(prefix_, prefix_ + count, out); - prefix_ += count; - prefix_length_ -= count; - return true; - } else if (prefix_length_ != 0) { - // Read is partially satisfied by the prefix. - out = std::copy(prefix_, prefix_ + prefix_length_, out); - count -= prefix_length_; - prefix_length_ = 0; - // Fallthrough to suffix read. - } - DCHECK(suffix_length_ >= count); - // Read is satisfied by the suffix. - std::copy(suffix_, suffix_ + count, out); - suffix_ += count; - suffix_length_ -= count; - return true; -} - -bool SpdyPrefixedBufferReader::ReadN(size_t count, - SpdyPinnableBufferPiece* out) { - if (Available() < count) { - return false; - } - - out->storage_.reset(); - out->length_ = count; - - if (prefix_length_ >= count) { - // Read is fully satisfied by the prefix. - out->buffer_ = prefix_; - prefix_ += count; - prefix_length_ -= count; - return true; - } else if (prefix_length_ != 0) { - // Read is only partially satisfied by the prefix. We need to allocate - // contiguous storage as the read spans the prefix & suffix. - out->storage_.reset(new char[count]); - out->buffer_ = out->storage_.get(); - ReadN(count, out->storage_.get()); - return true; - } else { - DCHECK(suffix_length_ >= count); - // Read is fully satisfied by the suffix. - out->buffer_ = suffix_; - suffix_ += count; - suffix_length_ -= count; - return true; - } -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_prefixed_buffer_reader.h b/net/third_party/spdy/core/spdy_prefixed_buffer_reader.h deleted file mode 100644 index 879c3127..0000000 --- a/net/third_party/spdy/core/spdy_prefixed_buffer_reader.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_PREFIXED_BUFFER_READER_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_PREFIXED_BUFFER_READER_H_ - -#include <stddef.h> - -#include "net/third_party/spdy/core/spdy_pinnable_buffer_piece.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" - -namespace spdy { - -// Reader class which simplifies reading contiguously from -// from a disjoint buffer prefix & suffix. -class SPDY_EXPORT_PRIVATE SpdyPrefixedBufferReader { - public: - SpdyPrefixedBufferReader(const char* prefix, - size_t prefix_length, - const char* suffix, - size_t suffix_length); - - // Returns number of bytes available to be read. - size_t Available(); - - // Reads |count| bytes, copying into |*out|. Returns true on success, - // false if not enough bytes were available. - bool ReadN(size_t count, char* out); - - // Reads |count| bytes, returned in |*out|. Returns true on success, - // false if not enough bytes were available. - bool ReadN(size_t count, SpdyPinnableBufferPiece* out); - - private: - const char* prefix_; - const char* suffix_; - - size_t prefix_length_; - size_t suffix_length_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_PREFIXED_BUFFER_READER_H_
diff --git a/net/third_party/spdy/core/spdy_prefixed_buffer_reader_test.cc b/net/third_party/spdy/core/spdy_prefixed_buffer_reader_test.cc deleted file mode 100644 index 03da2e6..0000000 --- a/net/third_party/spdy/core/spdy_prefixed_buffer_reader_test.cc +++ /dev/null
@@ -1,131 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_prefixed_buffer_reader.h" - -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -namespace test { - -using testing::ElementsAreArray; - -class SpdyPrefixedBufferReaderTest : public ::testing::Test { - protected: - SpdyPrefixedBufferReader Build(const SpdyString& prefix, - const SpdyString& suffix) { - prefix_ = prefix; - suffix_ = suffix; - return SpdyPrefixedBufferReader(prefix_.data(), prefix_.length(), - suffix_.data(), suffix_.length()); - } - SpdyString prefix_, suffix_; -}; - -TEST_F(SpdyPrefixedBufferReaderTest, ReadRawFromPrefix) { - SpdyPrefixedBufferReader reader = Build("foobar", ""); - EXPECT_EQ(6u, reader.Available()); - - char buffer[] = "123456"; - EXPECT_FALSE(reader.ReadN(10, buffer)); // Not enough buffer. - EXPECT_TRUE(reader.ReadN(6, buffer)); - EXPECT_THAT(buffer, ElementsAreArray("foobar")); - EXPECT_EQ(0u, reader.Available()); -} - -TEST_F(SpdyPrefixedBufferReaderTest, ReadPieceFromPrefix) { - SpdyPrefixedBufferReader reader = Build("foobar", ""); - EXPECT_EQ(6u, reader.Available()); - - SpdyPinnableBufferPiece piece; - EXPECT_FALSE(reader.ReadN(10, &piece)); // Not enough buffer. - EXPECT_TRUE(reader.ReadN(6, &piece)); - EXPECT_FALSE(piece.IsPinned()); - EXPECT_EQ(SpdyStringPiece("foobar"), SpdyStringPiece(piece)); - EXPECT_EQ(0u, reader.Available()); -} - -TEST_F(SpdyPrefixedBufferReaderTest, ReadRawFromSuffix) { - SpdyPrefixedBufferReader reader = Build("", "foobar"); - EXPECT_EQ(6u, reader.Available()); - - char buffer[] = "123456"; - EXPECT_FALSE(reader.ReadN(10, buffer)); // Not enough buffer. - EXPECT_TRUE(reader.ReadN(6, buffer)); - EXPECT_THAT(buffer, ElementsAreArray("foobar")); - EXPECT_EQ(0u, reader.Available()); -} - -TEST_F(SpdyPrefixedBufferReaderTest, ReadPieceFromSuffix) { - SpdyPrefixedBufferReader reader = Build("", "foobar"); - EXPECT_EQ(6u, reader.Available()); - - SpdyPinnableBufferPiece piece; - EXPECT_FALSE(reader.ReadN(10, &piece)); // Not enough buffer. - EXPECT_TRUE(reader.ReadN(6, &piece)); - EXPECT_FALSE(piece.IsPinned()); - EXPECT_EQ(SpdyStringPiece("foobar"), SpdyStringPiece(piece)); - EXPECT_EQ(0u, reader.Available()); -} - -TEST_F(SpdyPrefixedBufferReaderTest, ReadRawSpanning) { - SpdyPrefixedBufferReader reader = Build("foob", "ar"); - EXPECT_EQ(6u, reader.Available()); - - char buffer[] = "123456"; - EXPECT_FALSE(reader.ReadN(10, buffer)); // Not enough buffer. - EXPECT_TRUE(reader.ReadN(6, buffer)); - EXPECT_THAT(buffer, ElementsAreArray("foobar")); - EXPECT_EQ(0u, reader.Available()); -} - -TEST_F(SpdyPrefixedBufferReaderTest, ReadPieceSpanning) { - SpdyPrefixedBufferReader reader = Build("foob", "ar"); - EXPECT_EQ(6u, reader.Available()); - - SpdyPinnableBufferPiece piece; - EXPECT_FALSE(reader.ReadN(10, &piece)); // Not enough buffer. - EXPECT_TRUE(reader.ReadN(6, &piece)); - EXPECT_TRUE(piece.IsPinned()); - EXPECT_EQ(SpdyStringPiece("foobar"), SpdyStringPiece(piece)); - EXPECT_EQ(0u, reader.Available()); -} - -TEST_F(SpdyPrefixedBufferReaderTest, ReadMixed) { - SpdyPrefixedBufferReader reader = Build("abcdef", "hijkl"); - EXPECT_EQ(11u, reader.Available()); - - char buffer[] = "1234"; - SpdyPinnableBufferPiece piece; - - EXPECT_TRUE(reader.ReadN(3, buffer)); - EXPECT_THAT(buffer, ElementsAreArray("abc4")); - EXPECT_EQ(8u, reader.Available()); - - EXPECT_TRUE(reader.ReadN(2, buffer)); - EXPECT_THAT(buffer, ElementsAreArray("dec4")); - EXPECT_EQ(6u, reader.Available()); - - EXPECT_TRUE(reader.ReadN(3, &piece)); - EXPECT_EQ(SpdyStringPiece("fhi"), SpdyStringPiece(piece)); - EXPECT_TRUE(piece.IsPinned()); - EXPECT_EQ(3u, reader.Available()); - - EXPECT_TRUE(reader.ReadN(2, &piece)); - EXPECT_EQ(SpdyStringPiece("jk"), SpdyStringPiece(piece)); - EXPECT_FALSE(piece.IsPinned()); - EXPECT_EQ(1u, reader.Available()); - - EXPECT_TRUE(reader.ReadN(1, buffer)); - EXPECT_THAT(buffer, ElementsAreArray("lec4")); - EXPECT_EQ(0u, reader.Available()); -} - -} // namespace test - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_protocol.cc b/net/third_party/spdy/core/spdy_protocol.cc deleted file mode 100644 index 5db0630..0000000 --- a/net/third_party/spdy/core/spdy_protocol.cc +++ /dev/null
@@ -1,571 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_protocol.h" - -#include <ostream> - -#include "net/third_party/spdy/platform/api/spdy_bug_tracker.h" -#include "net/third_party/spdy/platform/api/spdy_ptr_util.h" -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" - -namespace spdy { - -const char* const kHttp2ConnectionHeaderPrefix = - "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; - -std::ostream& operator<<(std::ostream& out, SpdyKnownSettingsId id) { - return out << static_cast<SpdySettingsId>(id); -} - -std::ostream& operator<<(std::ostream& out, SpdyFrameType frame_type) { - return out << SerializeFrameType(frame_type); -} - -SpdyPriority ClampSpdy3Priority(SpdyPriority priority) { - if (priority < kV3HighestPriority) { - SPDY_BUG << "Invalid priority: " << static_cast<int>(priority); - return kV3HighestPriority; - } - if (priority > kV3LowestPriority) { - SPDY_BUG << "Invalid priority: " << static_cast<int>(priority); - return kV3LowestPriority; - } - return priority; -} - -int ClampHttp2Weight(int weight) { - if (weight < kHttp2MinStreamWeight) { - SPDY_BUG << "Invalid weight: " << weight; - return kHttp2MinStreamWeight; - } - if (weight > kHttp2MaxStreamWeight) { - SPDY_BUG << "Invalid weight: " << weight; - return kHttp2MaxStreamWeight; - } - return weight; -} - -int Spdy3PriorityToHttp2Weight(SpdyPriority priority) { - priority = ClampSpdy3Priority(priority); - const float kSteps = 255.9f / 7.f; - return static_cast<int>(kSteps * (7.f - priority)) + 1; -} - -SpdyPriority Http2WeightToSpdy3Priority(int weight) { - weight = ClampHttp2Weight(weight); - const float kSteps = 255.9f / 7.f; - return static_cast<SpdyPriority>(7.f - (weight - 1) / kSteps); -} - -bool IsDefinedFrameType(uint8_t frame_type_field) { - return frame_type_field <= SerializeFrameType(SpdyFrameType::MAX_FRAME_TYPE); -} - -SpdyFrameType ParseFrameType(uint8_t frame_type_field) { - SPDY_BUG_IF(!IsDefinedFrameType(frame_type_field)) - << "Frame type not defined: " << static_cast<int>(frame_type_field); - return static_cast<SpdyFrameType>(frame_type_field); -} - -uint8_t SerializeFrameType(SpdyFrameType frame_type) { - return static_cast<uint8_t>(frame_type); -} - -bool IsValidHTTP2FrameStreamId(SpdyStreamId current_frame_stream_id, - SpdyFrameType frame_type_field) { - if (current_frame_stream_id == 0) { - switch (frame_type_field) { - case SpdyFrameType::DATA: - case SpdyFrameType::HEADERS: - case SpdyFrameType::PRIORITY: - case SpdyFrameType::RST_STREAM: - case SpdyFrameType::CONTINUATION: - case SpdyFrameType::PUSH_PROMISE: - // These frame types must specify a stream - return false; - default: - return true; - } - } else { - switch (frame_type_field) { - case SpdyFrameType::GOAWAY: - case SpdyFrameType::SETTINGS: - case SpdyFrameType::PING: - // These frame types must not specify a stream - return false; - default: - return true; - } - } -} - -const char* FrameTypeToString(SpdyFrameType frame_type) { - switch (frame_type) { - case SpdyFrameType::DATA: - return "DATA"; - case SpdyFrameType::RST_STREAM: - return "RST_STREAM"; - case SpdyFrameType::SETTINGS: - return "SETTINGS"; - case SpdyFrameType::PING: - return "PING"; - case SpdyFrameType::GOAWAY: - return "GOAWAY"; - case SpdyFrameType::HEADERS: - return "HEADERS"; - case SpdyFrameType::WINDOW_UPDATE: - return "WINDOW_UPDATE"; - case SpdyFrameType::PUSH_PROMISE: - return "PUSH_PROMISE"; - case SpdyFrameType::CONTINUATION: - return "CONTINUATION"; - case SpdyFrameType::PRIORITY: - return "PRIORITY"; - case SpdyFrameType::ALTSVC: - return "ALTSVC"; - case SpdyFrameType::EXTENSION: - return "EXTENSION (unspecified)"; - } - return "UNKNOWN_FRAME_TYPE"; -} - -bool ParseSettingsId(SpdySettingsId wire_setting_id, - SpdyKnownSettingsId* setting_id) { - if (wire_setting_id != SETTINGS_EXPERIMENT_SCHEDULER && - (wire_setting_id < SETTINGS_MIN || wire_setting_id > SETTINGS_MAX)) { - return false; - } - - *setting_id = static_cast<SpdyKnownSettingsId>(wire_setting_id); - // This switch ensures that the casted value is valid. The default case is - // explicitly omitted to have compile-time guarantees that new additions to - // |SpdyKnownSettingsId| must also be handled here. - switch (*setting_id) { - case SETTINGS_HEADER_TABLE_SIZE: - case SETTINGS_ENABLE_PUSH: - case SETTINGS_MAX_CONCURRENT_STREAMS: - case SETTINGS_INITIAL_WINDOW_SIZE: - case SETTINGS_MAX_FRAME_SIZE: - case SETTINGS_MAX_HEADER_LIST_SIZE: - case SETTINGS_ENABLE_CONNECT_PROTOCOL: - case SETTINGS_EXPERIMENT_SCHEDULER: - // FALLTHROUGH_INTENDED - return true; - } - return false; -} - -SpdyString SettingsIdToString(SpdySettingsId id) { - SpdyKnownSettingsId known_id; - if (!ParseSettingsId(id, &known_id)) { - return SpdyStrCat("SETTINGS_UNKNOWN_", - SpdyHexEncodeUInt32AndTrim(uint32_t{id})); - } - - switch (known_id) { - case SETTINGS_HEADER_TABLE_SIZE: - return "SETTINGS_HEADER_TABLE_SIZE"; - case SETTINGS_ENABLE_PUSH: - return "SETTINGS_ENABLE_PUSH"; - case SETTINGS_MAX_CONCURRENT_STREAMS: - return "SETTINGS_MAX_CONCURRENT_STREAMS"; - case SETTINGS_INITIAL_WINDOW_SIZE: - return "SETTINGS_INITIAL_WINDOW_SIZE"; - case SETTINGS_MAX_FRAME_SIZE: - return "SETTINGS_MAX_FRAME_SIZE"; - case SETTINGS_MAX_HEADER_LIST_SIZE: - return "SETTINGS_MAX_HEADER_LIST_SIZE"; - case SETTINGS_ENABLE_CONNECT_PROTOCOL: - return "SETTINGS_ENABLE_CONNECT_PROTOCOL"; - case SETTINGS_EXPERIMENT_SCHEDULER: - return "SETTINGS_EXPERIMENT_SCHEDULER"; - } - - return SpdyStrCat("SETTINGS_UNKNOWN_", - SpdyHexEncodeUInt32AndTrim(uint32_t{id})); -} - -SpdyErrorCode ParseErrorCode(uint32_t wire_error_code) { - if (wire_error_code > ERROR_CODE_MAX) { - return ERROR_CODE_INTERNAL_ERROR; - } - - return static_cast<SpdyErrorCode>(wire_error_code); -} - -const char* ErrorCodeToString(SpdyErrorCode error_code) { - switch (error_code) { - case ERROR_CODE_NO_ERROR: - return "NO_ERROR"; - case ERROR_CODE_PROTOCOL_ERROR: - return "PROTOCOL_ERROR"; - case ERROR_CODE_INTERNAL_ERROR: - return "INTERNAL_ERROR"; - case ERROR_CODE_FLOW_CONTROL_ERROR: - return "FLOW_CONTROL_ERROR"; - case ERROR_CODE_SETTINGS_TIMEOUT: - return "SETTINGS_TIMEOUT"; - case ERROR_CODE_STREAM_CLOSED: - return "STREAM_CLOSED"; - case ERROR_CODE_FRAME_SIZE_ERROR: - return "FRAME_SIZE_ERROR"; - case ERROR_CODE_REFUSED_STREAM: - return "REFUSED_STREAM"; - case ERROR_CODE_CANCEL: - return "CANCEL"; - case ERROR_CODE_COMPRESSION_ERROR: - return "COMPRESSION_ERROR"; - case ERROR_CODE_CONNECT_ERROR: - return "CONNECT_ERROR"; - case ERROR_CODE_ENHANCE_YOUR_CALM: - return "ENHANCE_YOUR_CALM"; - case ERROR_CODE_INADEQUATE_SECURITY: - return "INADEQUATE_SECURITY"; - case ERROR_CODE_HTTP_1_1_REQUIRED: - return "HTTP_1_1_REQUIRED"; - } - return "UNKNOWN_ERROR_CODE"; -} - -size_t GetNumberRequiredContinuationFrames(size_t size) { - DCHECK_GT(size, kHttp2MaxControlFrameSendSize); - size_t overflow = size - kHttp2MaxControlFrameSendSize; - int payload_size = - kHttp2MaxControlFrameSendSize - kContinuationFrameMinimumSize; - // This is ceiling(overflow/payload_size) using integer arithmetics. - return (overflow - 1) / payload_size + 1; -} - -const char* const kHttp2Npn = "h2"; - -const char* const kHttp2AuthorityHeader = ":authority"; -const char* const kHttp2MethodHeader = ":method"; -const char* const kHttp2PathHeader = ":path"; -const char* const kHttp2SchemeHeader = ":scheme"; -const char* const kHttp2ProtocolHeader = ":protocol"; - -const char* const kHttp2StatusHeader = ":status"; - -bool SpdyFrameIR::fin() const { - return false; -} - -int SpdyFrameIR::flow_control_window_consumed() const { - return 0; -} - -bool SpdyFrameWithFinIR::fin() const { - return fin_; -} - -SpdyFrameWithHeaderBlockIR::SpdyFrameWithHeaderBlockIR( - SpdyStreamId stream_id, - SpdyHeaderBlock header_block) - : SpdyFrameWithFinIR(stream_id), header_block_(std::move(header_block)) {} - -SpdyFrameWithHeaderBlockIR::~SpdyFrameWithHeaderBlockIR() = default; - -SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, SpdyStringPiece data) - : SpdyFrameWithFinIR(stream_id), - data_(nullptr), - data_len_(0), - padded_(false), - padding_payload_len_(0) { - SetDataDeep(data); -} - -SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, const char* data) - : SpdyDataIR(stream_id, SpdyStringPiece(data)) {} - -SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, SpdyString data) - : SpdyFrameWithFinIR(stream_id), - data_store_(SpdyMakeUnique<SpdyString>(std::move(data))), - data_(data_store_->data()), - data_len_(data_store_->size()), - padded_(false), - padding_payload_len_(0) {} - -SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id) - : SpdyFrameWithFinIR(stream_id), - data_(nullptr), - data_len_(0), - padded_(false), - padding_payload_len_(0) {} - -SpdyDataIR::~SpdyDataIR() = default; - -void SpdyDataIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitData(*this); -} - -SpdyFrameType SpdyDataIR::frame_type() const { - return SpdyFrameType::DATA; -} - -int SpdyDataIR::flow_control_window_consumed() const { - return padded_ ? 1 + padding_payload_len_ + data_len_ : data_len_; -} - -size_t SpdyDataIR::size() const { - return kFrameHeaderSize + - (padded() ? 1 + padding_payload_len() + data_len() : data_len()); -} - -SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id, - SpdyErrorCode error_code) - : SpdyFrameIR(stream_id) { - set_error_code(error_code); -} - -SpdyRstStreamIR::~SpdyRstStreamIR() = default; - -void SpdyRstStreamIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitRstStream(*this); -} - -SpdyFrameType SpdyRstStreamIR::frame_type() const { - return SpdyFrameType::RST_STREAM; -} - -size_t SpdyRstStreamIR::size() const { - return kRstStreamFrameSize; -} - -SpdySettingsIR::SpdySettingsIR() : is_ack_(false) {} - -SpdySettingsIR::~SpdySettingsIR() = default; - -void SpdySettingsIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitSettings(*this); -} - -SpdyFrameType SpdySettingsIR::frame_type() const { - return SpdyFrameType::SETTINGS; -} - -size_t SpdySettingsIR::size() const { - return kFrameHeaderSize + values_.size() * kSettingsOneSettingSize; -} - -void SpdyPingIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitPing(*this); -} - -SpdyFrameType SpdyPingIR::frame_type() const { - return SpdyFrameType::PING; -} - -size_t SpdyPingIR::size() const { - return kPingFrameSize; -} - -SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id, - SpdyErrorCode error_code, - SpdyStringPiece description) - : description_(description) { - set_last_good_stream_id(last_good_stream_id); - set_error_code(error_code); -} - -SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id, - SpdyErrorCode error_code, - const char* description) - : SpdyGoAwayIR(last_good_stream_id, - error_code, - SpdyStringPiece(description)) {} - -SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id, - SpdyErrorCode error_code, - SpdyString description) - : description_store_(std::move(description)), - description_(description_store_) { - set_last_good_stream_id(last_good_stream_id); - set_error_code(error_code); -} - -SpdyGoAwayIR::~SpdyGoAwayIR() = default; - -void SpdyGoAwayIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitGoAway(*this); -} - -SpdyFrameType SpdyGoAwayIR::frame_type() const { - return SpdyFrameType::GOAWAY; -} - -size_t SpdyGoAwayIR::size() const { - return kGoawayFrameMinimumSize + description_.size(); -} - -SpdyContinuationIR::SpdyContinuationIR(SpdyStreamId stream_id) - : SpdyFrameIR(stream_id), end_headers_(false) { - encoding_ = SpdyMakeUnique<SpdyString>(); -} - -SpdyContinuationIR::~SpdyContinuationIR() = default; - -void SpdyContinuationIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitContinuation(*this); -} - -SpdyFrameType SpdyContinuationIR::frame_type() const { - return SpdyFrameType::CONTINUATION; -} - -size_t SpdyContinuationIR::size() const { - // We don't need to get the size of CONTINUATION frame directly. It is - // calculated in HEADERS or PUSH_PROMISE frame. - DLOG(WARNING) << "Shouldn't not call size() for CONTINUATION frame."; - return 0; -} - -void SpdyHeadersIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitHeaders(*this); -} - -SpdyFrameType SpdyHeadersIR::frame_type() const { - return SpdyFrameType::HEADERS; -} - -size_t SpdyHeadersIR::size() const { - size_t size = kHeadersFrameMinimumSize; - - if (padded_) { - // Padding field length. - size += 1; - size += padding_payload_len_; - } - - if (has_priority_) { - size += 5; - } - - // Assume no hpack encoding is applied. - size += header_block().TotalBytesUsed() + - header_block().size() * kPerHeaderHpackOverhead; - if (size > kHttp2MaxControlFrameSendSize) { - size += GetNumberRequiredContinuationFrames(size) * - kContinuationFrameMinimumSize; - } - return size; -} - -void SpdyWindowUpdateIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitWindowUpdate(*this); -} - -SpdyFrameType SpdyWindowUpdateIR::frame_type() const { - return SpdyFrameType::WINDOW_UPDATE; -} - -size_t SpdyWindowUpdateIR::size() const { - return kWindowUpdateFrameSize; -} - -void SpdyPushPromiseIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitPushPromise(*this); -} - -SpdyFrameType SpdyPushPromiseIR::frame_type() const { - return SpdyFrameType::PUSH_PROMISE; -} - -size_t SpdyPushPromiseIR::size() const { - size_t size = kPushPromiseFrameMinimumSize; - - if (padded_) { - // Padding length field. - size += 1; - size += padding_payload_len_; - } - - size += header_block().TotalBytesUsed(); - if (size > kHttp2MaxControlFrameSendSize) { - size += GetNumberRequiredContinuationFrames(size) * - kContinuationFrameMinimumSize; - } - return size; -} - -SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id) : SpdyFrameIR(stream_id) {} - -SpdyAltSvcIR::~SpdyAltSvcIR() = default; - -void SpdyAltSvcIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitAltSvc(*this); -} - -SpdyFrameType SpdyAltSvcIR::frame_type() const { - return SpdyFrameType::ALTSVC; -} - -size_t SpdyAltSvcIR::size() const { - size_t size = kGetAltSvcFrameMinimumSize; - size += origin_.length(); - // TODO(yasong): estimates the size without serializing the vector. - SpdyString str = - SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector_); - size += str.size(); - return size; -} - -void SpdyPriorityIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitPriority(*this); -} - -SpdyFrameType SpdyPriorityIR::frame_type() const { - return SpdyFrameType::PRIORITY; -} - -size_t SpdyPriorityIR::size() const { - return kPriorityFrameSize; -} - -void SpdyUnknownIR::Visit(SpdyFrameVisitor* visitor) const { - return visitor->VisitUnknown(*this); -} - -SpdyFrameType SpdyUnknownIR::frame_type() const { - return static_cast<SpdyFrameType>(type()); -} - -size_t SpdyUnknownIR::size() const { - return kFrameHeaderSize + payload_.size(); -} - -int SpdyUnknownIR::flow_control_window_consumed() const { - if (frame_type() == SpdyFrameType::DATA) { - return payload_.size(); - } else { - return 0; - } -} - -// Wire size of pad length field. -const size_t kPadLengthFieldSize = 1; - -size_t GetHeaderFrameSizeSansBlock(const SpdyHeadersIR& header_ir) { - size_t min_size = kFrameHeaderSize; - if (header_ir.padded()) { - min_size += kPadLengthFieldSize; - min_size += header_ir.padding_payload_len(); - } - if (header_ir.has_priority()) { - min_size += 5; - } - return min_size; -} - -size_t GetPushPromiseFrameSizeSansBlock( - const SpdyPushPromiseIR& push_promise_ir) { - size_t min_size = kPushPromiseFrameMinimumSize; - if (push_promise_ir.padded()) { - min_size += kPadLengthFieldSize; - min_size += push_promise_ir.padding_payload_len(); - } - return min_size; -} - -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_protocol.h b/net/third_party/spdy/core/spdy_protocol.h deleted file mode 100644 index b23bbf6..0000000 --- a/net/third_party/spdy/core/spdy_protocol.h +++ /dev/null
@@ -1,1066 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains some protocol structures for use with SPDY 3 and HTTP 2 -// The SPDY 3 spec can be found at: -// http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3 - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_PROTOCOL_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_PROTOCOL_H_ - -#include <cstddef> -#include <cstdint> -#include <iosfwd> -#include <limits> -#include <map> -#include <memory> -#include <new> -#include <utility> - -#include "base/logging.h" -#include "base/macros.h" -#include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h" -#include "net/third_party/spdy/core/spdy_bitmasks.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/platform/api/spdy_bug_tracker.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_ptr_util.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { - -// A stream ID is a 31-bit entity. -using SpdyStreamId = uint32_t; - -// A SETTINGS ID is a 16-bit entity. -using SpdySettingsId = uint16_t; - -// Specifies the stream ID used to denote the current session (for -// flow control). -const SpdyStreamId kSessionFlowControlStreamId = 0; - -// 0 is not a valid stream ID for any other purpose than flow control. -const SpdyStreamId kInvalidStreamId = 0; - -// Max stream id. -const SpdyStreamId kMaxStreamId = 0x7fffffff; - -// The maximum possible frame payload size allowed by the spec. -const uint32_t kSpdyMaxFrameSizeLimit = (1 << 24) - 1; - -// The initial value for the maximum frame payload size as per the spec. This is -// the maximum control frame size we accept. -const uint32_t kHttp2DefaultFramePayloadLimit = 1 << 14; - -// The maximum size of the control frames that we send, including the size of -// the header. This limit is arbitrary. We can enforce it here or at the -// application layer. We chose the framing layer, but this can be changed (or -// removed) if necessary later down the line. -const size_t kHttp2MaxControlFrameSendSize = kHttp2DefaultFramePayloadLimit - 1; - -// Number of octets in the frame header. -const size_t kFrameHeaderSize = 9; - -// The initial value for the maximum frame payload size as per the spec. This is -// the maximum control frame size we accept. -const uint32_t kHttp2DefaultFrameSizeLimit = - kHttp2DefaultFramePayloadLimit + kFrameHeaderSize; - -// The initial value for the maximum size of the header list, "unlimited" (max -// unsigned 32-bit int) as per the spec. -const uint32_t kSpdyInitialHeaderListSizeLimit = 0xFFFFFFFF; - -// Maximum window size for a Spdy stream or session. -const int32_t kSpdyMaximumWindowSize = 0x7FFFFFFF; // Max signed 32bit int - -// Maximum padding size in octets for one DATA or HEADERS or PUSH_PROMISE frame. -const int32_t kPaddingSizePerFrame = 256; - -// The HTTP/2 connection preface, which must be the first bytes sent by the -// client upon starting an HTTP/2 connection, and which must be followed by a -// SETTINGS frame. Note that even though |kHttp2ConnectionHeaderPrefix| is -// defined as a string literal with a null terminator, the actual connection -// preface is only the first |kHttp2ConnectionHeaderPrefixSize| bytes, which -// excludes the null terminator. -SPDY_EXPORT_PRIVATE extern const char* const kHttp2ConnectionHeaderPrefix; -const int kHttp2ConnectionHeaderPrefixSize = 24; - -// Wire values for HTTP2 frame types. -enum class SpdyFrameType : uint8_t { - DATA = 0x00, - HEADERS = 0x01, - PRIORITY = 0x02, - RST_STREAM = 0x03, - SETTINGS = 0x04, - PUSH_PROMISE = 0x05, - PING = 0x06, - GOAWAY = 0x07, - WINDOW_UPDATE = 0x08, - CONTINUATION = 0x09, - // ALTSVC is a public extension. - ALTSVC = 0x0a, - MAX_FRAME_TYPE = ALTSVC, - // The specific value of EXTENSION is meaningless; it is a placeholder used - // within SpdyFramer's state machine when handling unknown frames via an - // extension API. - // TODO(birenroy): Remove the fake EXTENSION value from the SpdyFrameType - // enum. - EXTENSION = 0xff -}; - -// Flags on data packets. -enum SpdyDataFlags { - DATA_FLAG_NONE = 0x00, - DATA_FLAG_FIN = 0x01, - DATA_FLAG_PADDED = 0x08, -}; - -// Flags on control packets -enum SpdyControlFlags { - CONTROL_FLAG_NONE = 0x00, - CONTROL_FLAG_FIN = 0x01, -}; - -enum SpdyPingFlags { - PING_FLAG_ACK = 0x01, -}; - -// Used by HEADERS, PUSH_PROMISE, and CONTINUATION. -enum SpdyHeadersFlags { - HEADERS_FLAG_END_HEADERS = 0x04, - HEADERS_FLAG_PADDED = 0x08, - HEADERS_FLAG_PRIORITY = 0x20, -}; - -enum SpdyPushPromiseFlags { - PUSH_PROMISE_FLAG_END_PUSH_PROMISE = 0x04, - PUSH_PROMISE_FLAG_PADDED = 0x08, -}; - -enum Http2SettingsControlFlags { - SETTINGS_FLAG_ACK = 0x01, -}; - -// Wire values of HTTP/2 setting identifiers. -enum SpdyKnownSettingsId : SpdySettingsId { - // HPACK header table maximum size. - SETTINGS_HEADER_TABLE_SIZE = 0x1, - SETTINGS_MIN = SETTINGS_HEADER_TABLE_SIZE, - // Whether or not server push (PUSH_PROMISE) is enabled. - SETTINGS_ENABLE_PUSH = 0x2, - // The maximum number of simultaneous live streams in each direction. - SETTINGS_MAX_CONCURRENT_STREAMS = 0x3, - // Initial window size in bytes - SETTINGS_INITIAL_WINDOW_SIZE = 0x4, - // The size of the largest frame payload that a receiver is willing to accept. - SETTINGS_MAX_FRAME_SIZE = 0x5, - // The maximum size of header list that the sender is prepared to accept. - SETTINGS_MAX_HEADER_LIST_SIZE = 0x6, - // Enable Websockets over HTTP/2, see - // https://tools.ietf.org/html/draft-ietf-httpbis-h2-websockets-00. - SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x8, - SETTINGS_MAX = SETTINGS_ENABLE_CONNECT_PROTOCOL, - // Experimental setting used to configure an alternative write scheduler. - SETTINGS_EXPERIMENT_SCHEDULER = 0xFF45, -}; - -// This explicit operator is needed, otherwise compiler finds -// overloaded operator to be ambiguous. -SPDY_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, - SpdyKnownSettingsId id); - -// This operator is needed, because SpdyFrameType is an enum class, -// therefore implicit conversion to underlying integer type is not allowed. -SPDY_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, - SpdyFrameType frame_type); - -using SettingsMap = std::map<SpdySettingsId, uint32_t>; - -// HTTP/2 error codes, RFC 7540 Section 7. -enum SpdyErrorCode : uint32_t { - ERROR_CODE_NO_ERROR = 0x0, - ERROR_CODE_PROTOCOL_ERROR = 0x1, - ERROR_CODE_INTERNAL_ERROR = 0x2, - ERROR_CODE_FLOW_CONTROL_ERROR = 0x3, - ERROR_CODE_SETTINGS_TIMEOUT = 0x4, - ERROR_CODE_STREAM_CLOSED = 0x5, - ERROR_CODE_FRAME_SIZE_ERROR = 0x6, - ERROR_CODE_REFUSED_STREAM = 0x7, - ERROR_CODE_CANCEL = 0x8, - ERROR_CODE_COMPRESSION_ERROR = 0x9, - ERROR_CODE_CONNECT_ERROR = 0xa, - ERROR_CODE_ENHANCE_YOUR_CALM = 0xb, - ERROR_CODE_INADEQUATE_SECURITY = 0xc, - ERROR_CODE_HTTP_1_1_REQUIRED = 0xd, - ERROR_CODE_MAX = ERROR_CODE_HTTP_1_1_REQUIRED -}; - -// A SPDY priority is a number between 0 and 7 (inclusive). -typedef uint8_t SpdyPriority; - -// Lowest and Highest here refer to SPDY priorities as described in -// https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1#TOC-2.3.3-Stream-priority -const SpdyPriority kV3HighestPriority = 0; -const SpdyPriority kV3LowestPriority = 7; - -// Returns SPDY 3.x priority value clamped to the valid range of [0, 7]. -SPDY_EXPORT_PRIVATE SpdyPriority ClampSpdy3Priority(SpdyPriority priority); - -// HTTP/2 stream weights are integers in range [1, 256], as specified in RFC -// 7540 section 5.3.2. Default stream weight is defined in section 5.3.5. -const int kHttp2MinStreamWeight = 1; -const int kHttp2MaxStreamWeight = 256; -const int kHttp2DefaultStreamWeight = 16; - -// Returns HTTP/2 weight clamped to the valid range of [1, 256]. -SPDY_EXPORT_PRIVATE int ClampHttp2Weight(int weight); - -// Maps SPDY 3.x priority value in range [0, 7] to HTTP/2 weight value in range -// [1, 256], where priority 0 (i.e. highest precedence) corresponds to maximum -// weight 256 and priority 7 (lowest precedence) corresponds to minimum weight -// 1. -SPDY_EXPORT_PRIVATE int Spdy3PriorityToHttp2Weight(SpdyPriority priority); - -// Maps HTTP/2 weight value in range [1, 256] to SPDY 3.x priority value in -// range [0, 7], where minimum weight 1 corresponds to priority 7 (lowest -// precedence) and maximum weight 256 corresponds to priority 0 (highest -// precedence). -SPDY_EXPORT_PRIVATE SpdyPriority Http2WeightToSpdy3Priority(int weight); - -// Reserved ID for root stream of HTTP/2 stream dependency tree, as specified -// in RFC 7540 section 5.3.1. -const unsigned int kHttp2RootStreamId = 0; - -typedef uint64_t SpdyPingId; - -// Returns true if a given on-the-wire enumeration of a frame type is defined -// in a standardized HTTP/2 specification, false otherwise. -SPDY_EXPORT_PRIVATE bool IsDefinedFrameType(uint8_t frame_type_field); - -// Parses a frame type from an on-the-wire enumeration. -// Behavior is undefined for invalid frame type fields; consumers should first -// use IsValidFrameType() to verify validity of frame type fields. -SPDY_EXPORT_PRIVATE SpdyFrameType ParseFrameType(uint8_t frame_type_field); - -// Serializes a frame type to the on-the-wire value. -SPDY_EXPORT_PRIVATE uint8_t SerializeFrameType(SpdyFrameType frame_type); - -// (HTTP/2) All standard frame types except WINDOW_UPDATE are -// (stream-specific xor connection-level). Returns false iff we know -// the given frame type does not align with the given streamID. -SPDY_EXPORT_PRIVATE bool IsValidHTTP2FrameStreamId( - SpdyStreamId current_frame_stream_id, - SpdyFrameType frame_type_field); - -// Serialize |frame_type| to string for logging/debugging. -const char* FrameTypeToString(SpdyFrameType frame_type); - -// If |wire_setting_id| is the on-the-wire representation of a defined SETTINGS -// parameter, parse it to |*setting_id| and return true. -SPDY_EXPORT_PRIVATE bool ParseSettingsId(SpdySettingsId wire_setting_id, - SpdyKnownSettingsId* setting_id); - -// Returns a string representation of the |id| for logging/debugging. Returns -// the |id| prefixed with "SETTINGS_UNKNOWN_" for unknown SETTINGS IDs. To parse -// the |id| into a SpdyKnownSettingsId (if applicable), use ParseSettingsId(). -SPDY_EXPORT_PRIVATE SpdyString SettingsIdToString(SpdySettingsId id); - -// Parse |wire_error_code| to a SpdyErrorCode. -// Treat unrecognized error codes as INTERNAL_ERROR -// as recommended by the HTTP/2 specification. -SPDY_EXPORT_PRIVATE SpdyErrorCode ParseErrorCode(uint32_t wire_error_code); - -// Serialize RST_STREAM or GOAWAY frame error code to string -// for logging/debugging. -const char* ErrorCodeToString(SpdyErrorCode error_code); - -// Minimum size of a frame, in octets. -const size_t kFrameMinimumSize = kFrameHeaderSize; - -// Minimum frame size for variable size frame types (includes mandatory fields), -// frame size for fixed size frames, in octets. - -const size_t kDataFrameMinimumSize = kFrameHeaderSize; -const size_t kHeadersFrameMinimumSize = kFrameHeaderSize; -// PRIORITY frame has stream_dependency (4 octets) and weight (1 octet) fields. -const size_t kPriorityFrameSize = kFrameHeaderSize + 5; -// RST_STREAM frame has error_code (4 octets) field. -const size_t kRstStreamFrameSize = kFrameHeaderSize + 4; -const size_t kSettingsFrameMinimumSize = kFrameHeaderSize; -const size_t kSettingsOneSettingSize = - sizeof(uint32_t) + sizeof(SpdySettingsId); -// PUSH_PROMISE frame has promised_stream_id (4 octet) field. -const size_t kPushPromiseFrameMinimumSize = kFrameHeaderSize + 4; -// PING frame has opaque_bytes (8 octet) field. -const size_t kPingFrameSize = kFrameHeaderSize + 8; -// GOAWAY frame has last_stream_id (4 octet) and error_code (4 octet) fields. -const size_t kGoawayFrameMinimumSize = kFrameHeaderSize + 8; -// WINDOW_UPDATE frame has window_size_increment (4 octet) field. -const size_t kWindowUpdateFrameSize = kFrameHeaderSize + 4; -const size_t kContinuationFrameMinimumSize = kFrameHeaderSize; -// ALTSVC frame has origin_len (2 octets) field. -const size_t kGetAltSvcFrameMinimumSize = kFrameHeaderSize + 2; - -// Maximum possible configurable size of a frame in octets. -const size_t kMaxFrameSizeLimit = kSpdyMaxFrameSizeLimit + kFrameHeaderSize; -// Size of a header block size field. -const size_t kSizeOfSizeField = sizeof(uint32_t); -// Per-header overhead for block size accounting in bytes. -const size_t kPerHeaderOverhead = 32; -// Initial window size for a stream in bytes. -const int32_t kInitialStreamWindowSize = 64 * 1024 - 1; -// Initial window size for a session in bytes. -const int32_t kInitialSessionWindowSize = 64 * 1024 - 1; -// The NPN string for HTTP2, "h2". -extern const char* const kHttp2Npn; -// An estimate size of the HPACK overhead for each header field. 1 bytes for -// indexed literal, 1 bytes for key literal and length encoding, and 2 bytes for -// value literal and length encoding. -const size_t kPerHeaderHpackOverhead = 4; - -// Names of pseudo-headers defined for HTTP/2 requests. -SPDY_EXPORT_PRIVATE extern const char* const kHttp2AuthorityHeader; -SPDY_EXPORT_PRIVATE extern const char* const kHttp2MethodHeader; -SPDY_EXPORT_PRIVATE extern const char* const kHttp2PathHeader; -SPDY_EXPORT_PRIVATE extern const char* const kHttp2SchemeHeader; -SPDY_EXPORT_PRIVATE extern const char* const kHttp2ProtocolHeader; - -// Name of pseudo-header defined for HTTP/2 responses. -SPDY_EXPORT_PRIVATE extern const char* const kHttp2StatusHeader; - -SPDY_EXPORT_PRIVATE size_t GetNumberRequiredContinuationFrames(size_t size); - -// Variant type (i.e. tagged union) that is either a SPDY 3.x priority value, -// or else an HTTP/2 stream dependency tuple {parent stream ID, weight, -// exclusive bit}. Templated to allow for use by QUIC code; SPDY and HTTP/2 -// code should use the concrete type instantiation SpdyStreamPrecedence. -template <typename StreamIdType> -class StreamPrecedence { - public: - // Constructs instance that is a SPDY 3.x priority. Clamps priority value to - // the valid range [0, 7]. - explicit StreamPrecedence(SpdyPriority priority) - : is_spdy3_priority_(true), - spdy3_priority_(ClampSpdy3Priority(priority)) {} - - // Constructs instance that is an HTTP/2 stream weight, parent stream ID, and - // exclusive bit. Clamps stream weight to the valid range [1, 256]. - StreamPrecedence(StreamIdType parent_id, int weight, bool is_exclusive) - : is_spdy3_priority_(false), - http2_stream_dependency_{parent_id, ClampHttp2Weight(weight), - is_exclusive} {} - - // Intentionally copyable, to support pass by value. - StreamPrecedence(const StreamPrecedence& other) = default; - StreamPrecedence& operator=(const StreamPrecedence& other) = default; - - // Returns true if this instance is a SPDY 3.x priority, or false if this - // instance is an HTTP/2 stream dependency. - bool is_spdy3_priority() const { return is_spdy3_priority_; } - - // Returns SPDY 3.x priority value. If |is_spdy3_priority()| is true, this is - // the value provided at construction, clamped to the legal priority - // range. Otherwise, it is the HTTP/2 stream weight mapped to a SPDY 3.x - // priority value, where minimum weight 1 corresponds to priority 7 (lowest - // precedence) and maximum weight 256 corresponds to priority 0 (highest - // precedence). - SpdyPriority spdy3_priority() const { - return is_spdy3_priority_ - ? spdy3_priority_ - : Http2WeightToSpdy3Priority(http2_stream_dependency_.weight); - } - - // Returns HTTP/2 parent stream ID. If |is_spdy3_priority()| is false, this is - // the value provided at construction, otherwise it is |kHttp2RootStreamId|. - StreamIdType parent_id() const { - return is_spdy3_priority_ ? kHttp2RootStreamId - : http2_stream_dependency_.parent_id; - } - - // Returns HTTP/2 stream weight. If |is_spdy3_priority()| is false, this is - // the value provided at construction, clamped to the legal weight - // range. Otherwise, it is the SPDY 3.x priority value mapped to an HTTP/2 - // stream weight, where priority 0 (i.e. highest precedence) corresponds to - // maximum weight 256 and priority 7 (lowest precedence) corresponds to - // minimum weight 1. - int weight() const { - return is_spdy3_priority_ ? Spdy3PriorityToHttp2Weight(spdy3_priority_) - : http2_stream_dependency_.weight; - } - - // Returns HTTP/2 parent stream exclusivity. If |is_spdy3_priority()| is - // false, this is the value provided at construction, otherwise it is false. - bool is_exclusive() const { - return !is_spdy3_priority_ && http2_stream_dependency_.is_exclusive; - } - - // Facilitates test assertions. - bool operator==(const StreamPrecedence& other) const { - if (is_spdy3_priority()) { - return other.is_spdy3_priority() && - (spdy3_priority() == other.spdy3_priority()); - } else { - return !other.is_spdy3_priority() && (parent_id() == other.parent_id()) && - (weight() == other.weight()) && - (is_exclusive() == other.is_exclusive()); - } - } - - bool operator!=(const StreamPrecedence& other) const { - return !(*this == other); - } - - private: - struct Http2StreamDependency { - StreamIdType parent_id; - int weight; - bool is_exclusive; - }; - - bool is_spdy3_priority_; - union { - SpdyPriority spdy3_priority_; - Http2StreamDependency http2_stream_dependency_; - }; -}; - -typedef StreamPrecedence<SpdyStreamId> SpdyStreamPrecedence; - -class SpdyFrameVisitor; - -// Intermediate representation for HTTP2 frames. -class SPDY_EXPORT_PRIVATE SpdyFrameIR { - public: - virtual ~SpdyFrameIR() {} - - virtual void Visit(SpdyFrameVisitor* visitor) const = 0; - virtual SpdyFrameType frame_type() const = 0; - SpdyStreamId stream_id() const { return stream_id_; } - virtual bool fin() const; - // Returns an estimate of the size of the serialized frame, without applying - // compression. May not be exact. - virtual size_t size() const = 0; - - // Returns the number of bytes of flow control window that would be consumed - // by this frame if written to the wire. - virtual int flow_control_window_consumed() const; - - protected: - SpdyFrameIR() : stream_id_(0) {} - explicit SpdyFrameIR(SpdyStreamId stream_id) : stream_id_(stream_id) {} - SpdyFrameIR(const SpdyFrameIR&) = delete; - SpdyFrameIR& operator=(const SpdyFrameIR&) = delete; - - private: - SpdyStreamId stream_id_; -}; - -// Abstract class intended to be inherited by IRs that have the option of a FIN -// flag. -class SPDY_EXPORT_PRIVATE SpdyFrameWithFinIR : public SpdyFrameIR { - public: - ~SpdyFrameWithFinIR() override {} - bool fin() const override; - void set_fin(bool fin) { fin_ = fin; } - - protected: - explicit SpdyFrameWithFinIR(SpdyStreamId stream_id) - : SpdyFrameIR(stream_id), fin_(false) {} - SpdyFrameWithFinIR(const SpdyFrameWithFinIR&) = delete; - SpdyFrameWithFinIR& operator=(const SpdyFrameWithFinIR&) = delete; - - private: - bool fin_; -}; - -// Abstract class intended to be inherited by IRs that contain a header -// block. Implies SpdyFrameWithFinIR. -class SPDY_EXPORT_PRIVATE SpdyFrameWithHeaderBlockIR - : public SpdyFrameWithFinIR { - public: - ~SpdyFrameWithHeaderBlockIR() override; - - const SpdyHeaderBlock& header_block() const { return header_block_; } - void set_header_block(SpdyHeaderBlock header_block) { - // Deep copy. - header_block_ = std::move(header_block); - } - void SetHeader(SpdyStringPiece name, SpdyStringPiece value) { - header_block_[name] = value; - } - - protected: - SpdyFrameWithHeaderBlockIR(SpdyStreamId stream_id, - SpdyHeaderBlock header_block); - SpdyFrameWithHeaderBlockIR(const SpdyFrameWithHeaderBlockIR&) = delete; - SpdyFrameWithHeaderBlockIR& operator=(const SpdyFrameWithHeaderBlockIR&) = - delete; - - private: - SpdyHeaderBlock header_block_; -}; - -class SPDY_EXPORT_PRIVATE SpdyDataIR : public SpdyFrameWithFinIR { - public: - // Performs a deep copy on data. - SpdyDataIR(SpdyStreamId stream_id, SpdyStringPiece data); - - // Performs a deep copy on data. - SpdyDataIR(SpdyStreamId stream_id, const char* data); - - // Moves data into data_store_. Makes a copy if passed a non-movable string. - SpdyDataIR(SpdyStreamId stream_id, SpdyString data); - - // Use in conjunction with SetDataShallow() for shallow-copy on data. - explicit SpdyDataIR(SpdyStreamId stream_id); - SpdyDataIR(const SpdyDataIR&) = delete; - SpdyDataIR& operator=(const SpdyDataIR&) = delete; - - ~SpdyDataIR() override; - - const char* data() const { return data_; } - size_t data_len() const { return data_len_; } - - bool padded() const { return padded_; } - - int padding_payload_len() const { return padding_payload_len_; } - - void set_padding_len(int padding_len) { - DCHECK_GT(padding_len, 0); - DCHECK_LE(padding_len, kPaddingSizePerFrame); - padded_ = true; - // The pad field takes one octet on the wire. - padding_payload_len_ = padding_len - 1; - } - - // Deep-copy of data (keep private copy). - void SetDataDeep(SpdyStringPiece data) { - data_store_ = SpdyMakeUnique<SpdyString>(data.data(), data.size()); - data_ = data_store_->data(); - data_len_ = data.size(); - } - - // Shallow-copy of data (do not keep private copy). - void SetDataShallow(SpdyStringPiece data) { - data_store_.reset(); - data_ = data.data(); - data_len_ = data.size(); - } - - // Use this method if we don't have a contiguous buffer and only - // need a length. - void SetDataShallow(size_t len) { - data_store_.reset(); - data_ = nullptr; - data_len_ = len; - } - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - int flow_control_window_consumed() const override; - - size_t size() const override; - - private: - // Used to store data that this SpdyDataIR should own. - std::unique_ptr<SpdyString> data_store_; - const char* data_; - size_t data_len_; - - bool padded_; - // padding_payload_len_ = desired padding length - len(padding length field). - int padding_payload_len_; -}; - -class SPDY_EXPORT_PRIVATE SpdyRstStreamIR : public SpdyFrameIR { - public: - SpdyRstStreamIR(SpdyStreamId stream_id, SpdyErrorCode error_code); - SpdyRstStreamIR(const SpdyRstStreamIR&) = delete; - SpdyRstStreamIR& operator=(const SpdyRstStreamIR&) = delete; - - ~SpdyRstStreamIR() override; - - SpdyErrorCode error_code() const { return error_code_; } - void set_error_code(SpdyErrorCode error_code) { error_code_ = error_code; } - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - size_t size() const override; - - private: - SpdyErrorCode error_code_; -}; - -class SPDY_EXPORT_PRIVATE SpdySettingsIR : public SpdyFrameIR { - public: - SpdySettingsIR(); - SpdySettingsIR(const SpdySettingsIR&) = delete; - SpdySettingsIR& operator=(const SpdySettingsIR&) = delete; - ~SpdySettingsIR() override; - - // Overwrites as appropriate. - const SettingsMap& values() const { return values_; } - void AddSetting(SpdySettingsId id, int32_t value) { values_[id] = value; } - - bool is_ack() const { return is_ack_; } - void set_is_ack(bool is_ack) { is_ack_ = is_ack; } - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - size_t size() const override; - - private: - SettingsMap values_; - bool is_ack_; -}; - -class SPDY_EXPORT_PRIVATE SpdyPingIR : public SpdyFrameIR { - public: - explicit SpdyPingIR(SpdyPingId id) : id_(id), is_ack_(false) {} - SpdyPingIR(const SpdyPingIR&) = delete; - SpdyPingIR& operator=(const SpdyPingIR&) = delete; - SpdyPingId id() const { return id_; } - - bool is_ack() const { return is_ack_; } - void set_is_ack(bool is_ack) { is_ack_ = is_ack; } - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - size_t size() const override; - - private: - SpdyPingId id_; - bool is_ack_; -}; - -class SPDY_EXPORT_PRIVATE SpdyGoAwayIR : public SpdyFrameIR { - public: - // References description, doesn't copy it, so description must outlast - // this SpdyGoAwayIR. - SpdyGoAwayIR(SpdyStreamId last_good_stream_id, - SpdyErrorCode error_code, - SpdyStringPiece description); - - // References description, doesn't copy it, so description must outlast - // this SpdyGoAwayIR. - SpdyGoAwayIR(SpdyStreamId last_good_stream_id, - SpdyErrorCode error_code, - const char* description); - - // Moves description into description_store_, so caller doesn't need to - // keep description live after constructing this SpdyGoAwayIR. - SpdyGoAwayIR(SpdyStreamId last_good_stream_id, - SpdyErrorCode error_code, - SpdyString description); - SpdyGoAwayIR(const SpdyGoAwayIR&) = delete; - SpdyGoAwayIR& operator=(const SpdyGoAwayIR&) = delete; - - ~SpdyGoAwayIR() override; - - SpdyStreamId last_good_stream_id() const { return last_good_stream_id_; } - void set_last_good_stream_id(SpdyStreamId last_good_stream_id) { - DCHECK_EQ(0u, last_good_stream_id & ~kStreamIdMask); - last_good_stream_id_ = last_good_stream_id; - } - SpdyErrorCode error_code() const { return error_code_; } - void set_error_code(SpdyErrorCode error_code) { - // TODO(hkhalil): Check valid ranges of error_code? - error_code_ = error_code; - } - - const SpdyStringPiece& description() const { return description_; } - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - size_t size() const override; - - private: - SpdyStreamId last_good_stream_id_; - SpdyErrorCode error_code_; - const SpdyString description_store_; - const SpdyStringPiece description_; -}; - -class SPDY_EXPORT_PRIVATE SpdyHeadersIR : public SpdyFrameWithHeaderBlockIR { - public: - explicit SpdyHeadersIR(SpdyStreamId stream_id) - : SpdyHeadersIR(stream_id, SpdyHeaderBlock()) {} - SpdyHeadersIR(SpdyStreamId stream_id, SpdyHeaderBlock header_block) - : SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)) {} - SpdyHeadersIR(const SpdyHeadersIR&) = delete; - SpdyHeadersIR& operator=(const SpdyHeadersIR&) = delete; - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - size_t size() const override; - - bool has_priority() const { return has_priority_; } - void set_has_priority(bool has_priority) { has_priority_ = has_priority; } - int weight() const { return weight_; } - void set_weight(int weight) { weight_ = weight; } - SpdyStreamId parent_stream_id() const { return parent_stream_id_; } - void set_parent_stream_id(SpdyStreamId id) { parent_stream_id_ = id; } - bool exclusive() const { return exclusive_; } - void set_exclusive(bool exclusive) { exclusive_ = exclusive; } - bool padded() const { return padded_; } - int padding_payload_len() const { return padding_payload_len_; } - void set_padding_len(int padding_len) { - DCHECK_GT(padding_len, 0); - DCHECK_LE(padding_len, kPaddingSizePerFrame); - padded_ = true; - // The pad field takes one octet on the wire. - padding_payload_len_ = padding_len - 1; - } - - private: - bool has_priority_ = false; - int weight_ = kHttp2DefaultStreamWeight; - SpdyStreamId parent_stream_id_ = 0; - bool exclusive_ = false; - bool padded_ = false; - int padding_payload_len_ = 0; -}; - -class SPDY_EXPORT_PRIVATE SpdyWindowUpdateIR : public SpdyFrameIR { - public: - SpdyWindowUpdateIR(SpdyStreamId stream_id, int32_t delta) - : SpdyFrameIR(stream_id) { - set_delta(delta); - } - SpdyWindowUpdateIR(const SpdyWindowUpdateIR&) = delete; - SpdyWindowUpdateIR& operator=(const SpdyWindowUpdateIR&) = delete; - - int32_t delta() const { return delta_; } - void set_delta(int32_t delta) { - DCHECK_LE(0, delta); - DCHECK_LE(delta, kSpdyMaximumWindowSize); - delta_ = delta; - } - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - size_t size() const override; - - private: - int32_t delta_; -}; - -class SPDY_EXPORT_PRIVATE SpdyPushPromiseIR - : public SpdyFrameWithHeaderBlockIR { - public: - SpdyPushPromiseIR(SpdyStreamId stream_id, SpdyStreamId promised_stream_id) - : SpdyPushPromiseIR(stream_id, promised_stream_id, SpdyHeaderBlock()) {} - SpdyPushPromiseIR(SpdyStreamId stream_id, - SpdyStreamId promised_stream_id, - SpdyHeaderBlock header_block) - : SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)), - promised_stream_id_(promised_stream_id), - padded_(false), - padding_payload_len_(0) {} - SpdyPushPromiseIR(const SpdyPushPromiseIR&) = delete; - SpdyPushPromiseIR& operator=(const SpdyPushPromiseIR&) = delete; - SpdyStreamId promised_stream_id() const { return promised_stream_id_; } - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - size_t size() const override; - - bool padded() const { return padded_; } - int padding_payload_len() const { return padding_payload_len_; } - void set_padding_len(int padding_len) { - DCHECK_GT(padding_len, 0); - DCHECK_LE(padding_len, kPaddingSizePerFrame); - padded_ = true; - // The pad field takes one octet on the wire. - padding_payload_len_ = padding_len - 1; - } - - private: - SpdyStreamId promised_stream_id_; - - bool padded_; - int padding_payload_len_; -}; - -class SPDY_EXPORT_PRIVATE SpdyContinuationIR : public SpdyFrameIR { - public: - explicit SpdyContinuationIR(SpdyStreamId stream_id); - SpdyContinuationIR(const SpdyContinuationIR&) = delete; - SpdyContinuationIR& operator=(const SpdyContinuationIR&) = delete; - ~SpdyContinuationIR() override; - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - bool end_headers() const { return end_headers_; } - void set_end_headers(bool end_headers) { end_headers_ = end_headers; } - const SpdyString& encoding() const { return *encoding_; } - void take_encoding(std::unique_ptr<SpdyString> encoding) { - encoding_ = std::move(encoding); - } - size_t size() const override; - - private: - std::unique_ptr<SpdyString> encoding_; - bool end_headers_; -}; - -class SPDY_EXPORT_PRIVATE SpdyAltSvcIR : public SpdyFrameIR { - public: - explicit SpdyAltSvcIR(SpdyStreamId stream_id); - SpdyAltSvcIR(const SpdyAltSvcIR&) = delete; - SpdyAltSvcIR& operator=(const SpdyAltSvcIR&) = delete; - ~SpdyAltSvcIR() override; - - SpdyString origin() const { return origin_; } - const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector() const { - return altsvc_vector_; - } - - void set_origin(SpdyString origin) { origin_ = std::move(origin); } - void add_altsvc(const SpdyAltSvcWireFormat::AlternativeService& altsvc) { - altsvc_vector_.push_back(altsvc); - } - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - size_t size() const override; - - private: - SpdyString origin_; - SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_; -}; - -class SPDY_EXPORT_PRIVATE SpdyPriorityIR : public SpdyFrameIR { - public: - SpdyPriorityIR(SpdyStreamId stream_id, - SpdyStreamId parent_stream_id, - int weight, - bool exclusive) - : SpdyFrameIR(stream_id), - parent_stream_id_(parent_stream_id), - weight_(weight), - exclusive_(exclusive) {} - SpdyPriorityIR(const SpdyPriorityIR&) = delete; - SpdyPriorityIR& operator=(const SpdyPriorityIR&) = delete; - SpdyStreamId parent_stream_id() const { return parent_stream_id_; } - int weight() const { return weight_; } - bool exclusive() const { return exclusive_; } - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - size_t size() const override; - - private: - SpdyStreamId parent_stream_id_; - int weight_; - bool exclusive_; -}; - -// Represents a frame of unrecognized type. -class SPDY_EXPORT_PRIVATE SpdyUnknownIR : public SpdyFrameIR { - public: - SpdyUnknownIR(SpdyStreamId stream_id, - uint8_t type, - uint8_t flags, - SpdyString payload) - : SpdyFrameIR(stream_id), - type_(type), - flags_(flags), - length_(payload.size()), - payload_(std::move(payload)) {} - SpdyUnknownIR(const SpdyUnknownIR&) = delete; - SpdyUnknownIR& operator=(const SpdyUnknownIR&) = delete; - uint8_t type() const { return type_; } - uint8_t flags() const { return flags_; } - size_t length() const { return length_; } - const SpdyString& payload() const { return payload_; } - - void Visit(SpdyFrameVisitor* visitor) const override; - - SpdyFrameType frame_type() const override; - - int flow_control_window_consumed() const override; - - size_t size() const override; - - protected: - // Allows subclasses to overwrite the default payload length. - void set_length(size_t length) { length_ = length; } - - private: - uint8_t type_; - uint8_t flags_; - size_t length_; - const SpdyString payload_; -}; - -class SPDY_EXPORT_PRIVATE SpdySerializedFrame { - public: - SpdySerializedFrame() - : frame_(const_cast<char*>("")), size_(0), owns_buffer_(false) {} - - // Create a valid SpdySerializedFrame using a pre-created buffer. - // If |owns_buffer| is true, this class takes ownership of the buffer and will - // delete it on cleanup. The buffer must have been created using new char[]. - // If |owns_buffer| is false, the caller retains ownership of the buffer and - // is responsible for making sure the buffer outlives this frame. In other - // words, this class does NOT create a copy of the buffer. - SpdySerializedFrame(char* data, size_t size, bool owns_buffer) - : frame_(data), size_(size), owns_buffer_(owns_buffer) {} - - SpdySerializedFrame(SpdySerializedFrame&& other) - : frame_(other.frame_), - size_(other.size_), - owns_buffer_(other.owns_buffer_) { - // |other| is no longer responsible for the buffer. - other.owns_buffer_ = false; - } - SpdySerializedFrame(const SpdySerializedFrame&) = delete; - SpdySerializedFrame& operator=(const SpdySerializedFrame&) = delete; - - SpdySerializedFrame& operator=(SpdySerializedFrame&& other) { - // Free buffer if necessary. - if (owns_buffer_) { - delete[] frame_; - } - // Take over |other|. - frame_ = other.frame_; - size_ = other.size_; - owns_buffer_ = other.owns_buffer_; - // |other| is no longer responsible for the buffer. - other.owns_buffer_ = false; - return *this; - } - - ~SpdySerializedFrame() { - if (owns_buffer_) { - delete[] frame_; - } - } - - // Provides access to the frame bytes, which is a buffer containing the frame - // packed as expected for sending over the wire. - char* data() const { return frame_; } - - // Returns the actual size of the underlying buffer. - size_t size() const { return size_; } - - // Returns a buffer containing the contents of the frame, of which the caller - // takes ownership, and clears this SpdySerializedFrame. - char* ReleaseBuffer() { - char* buffer; - if (owns_buffer_) { - // If the buffer is owned, relinquish ownership to the caller. - buffer = frame_; - owns_buffer_ = false; - } else { - // Otherwise, we need to make a copy to give to the caller. - buffer = new char[size_]; - memcpy(buffer, frame_, size_); - } - *this = SpdySerializedFrame(); - return buffer; - } - - // Returns the estimate of dynamically allocated memory in bytes. - size_t EstimateMemoryUsage() const { return owns_buffer_ ? size_ : 0; } - - protected: - char* frame_; - - private: - size_t size_; - bool owns_buffer_; -}; - -// This interface is for classes that want to process SpdyFrameIRs without -// having to know what type they are. An instance of this interface can be -// passed to a SpdyFrameIR's Visit method, and the appropriate type-specific -// method of this class will be called. -class SPDY_EXPORT_PRIVATE SpdyFrameVisitor { - public: - virtual void VisitRstStream(const SpdyRstStreamIR& rst_stream) = 0; - virtual void VisitSettings(const SpdySettingsIR& settings) = 0; - virtual void VisitPing(const SpdyPingIR& ping) = 0; - virtual void VisitGoAway(const SpdyGoAwayIR& goaway) = 0; - virtual void VisitHeaders(const SpdyHeadersIR& headers) = 0; - virtual void VisitWindowUpdate(const SpdyWindowUpdateIR& window_update) = 0; - virtual void VisitPushPromise(const SpdyPushPromiseIR& push_promise) = 0; - virtual void VisitContinuation(const SpdyContinuationIR& continuation) = 0; - virtual void VisitAltSvc(const SpdyAltSvcIR& altsvc) = 0; - virtual void VisitPriority(const SpdyPriorityIR& priority) = 0; - virtual void VisitData(const SpdyDataIR& data) = 0; - virtual void VisitUnknown(const SpdyUnknownIR& unknown) { - // TODO(birenroy): make abstract. - } - - protected: - SpdyFrameVisitor() {} - SpdyFrameVisitor(const SpdyFrameVisitor&) = delete; - SpdyFrameVisitor& operator=(const SpdyFrameVisitor&) = delete; - virtual ~SpdyFrameVisitor() {} -}; - -// Optionally, and in addition to SpdyFramerVisitorInterface, a class supporting -// SpdyFramerDebugVisitorInterface may be used in conjunction with SpdyFramer in -// order to extract debug/internal information about the SpdyFramer as it -// operates. -// -// Most HTTP2 implementations need not bother with this interface at all. -class SPDY_EXPORT_PRIVATE SpdyFramerDebugVisitorInterface { - public: - virtual ~SpdyFramerDebugVisitorInterface() {} - - // Called after compressing a frame with a payload of - // a list of name-value pairs. - // |payload_len| is the uncompressed payload size. - // |frame_len| is the compressed frame size. - virtual void OnSendCompressedFrame(SpdyStreamId stream_id, - SpdyFrameType type, - size_t payload_len, - size_t frame_len) {} - - // Called when a frame containing a compressed payload of - // name-value pairs is received. - // |frame_len| is the compressed frame size. - virtual void OnReceiveCompressedFrame(SpdyStreamId stream_id, - SpdyFrameType type, - size_t frame_len) {} -}; - -// Calculates the number of bytes required to serialize a SpdyHeadersIR, not -// including the bytes to be used for the encoded header set. -size_t GetHeaderFrameSizeSansBlock(const SpdyHeadersIR& header_ir); - -// Calculates the number of bytes required to serialize a SpdyPushPromiseIR, -// not including the bytes to be used for the encoded header set. -size_t GetPushPromiseFrameSizeSansBlock( - const SpdyPushPromiseIR& push_promise_ir); - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_PROTOCOL_H_
diff --git a/net/third_party/spdy/core/spdy_protocol_test.cc b/net/third_party/spdy/core/spdy_protocol_test.cc deleted file mode 100644 index 969db05..0000000 --- a/net/third_party/spdy/core/spdy_protocol_test.cc +++ /dev/null
@@ -1,270 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_protocol.h" - -#include <iostream> -#include <limits> -#include <memory> - -#include "net/third_party/spdy/core/spdy_bitmasks.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { - -std::ostream& operator<<(std::ostream& os, - const SpdyStreamPrecedence precedence) { - if (precedence.is_spdy3_priority()) { - os << "SpdyStreamPrecedence[spdy3_priority=" << precedence.spdy3_priority() - << "]"; - } else { - os << "SpdyStreamPrecedence[parent_id=" << precedence.parent_id() - << ", weight=" << precedence.weight() - << ", is_exclusive=" << precedence.is_exclusive() << "]"; - } - return os; -} - -namespace test { - -TEST(SpdyProtocolTest, ClampSpdy3Priority) { - EXPECT_SPDY_BUG(EXPECT_EQ(7, ClampSpdy3Priority(8)), "Invalid priority: 8"); - EXPECT_EQ(kV3LowestPriority, ClampSpdy3Priority(kV3LowestPriority)); - EXPECT_EQ(kV3HighestPriority, ClampSpdy3Priority(kV3HighestPriority)); -} - -TEST(SpdyProtocolTest, ClampHttp2Weight) { - EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2MinStreamWeight, ClampHttp2Weight(0)), - "Invalid weight: 0"); - EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2MaxStreamWeight, ClampHttp2Weight(300)), - "Invalid weight: 300"); - EXPECT_EQ(kHttp2MinStreamWeight, ClampHttp2Weight(kHttp2MinStreamWeight)); - EXPECT_EQ(kHttp2MaxStreamWeight, ClampHttp2Weight(kHttp2MaxStreamWeight)); -} - -TEST(SpdyProtocolTest, Spdy3PriorityToHttp2Weight) { - EXPECT_EQ(256, Spdy3PriorityToHttp2Weight(0)); - EXPECT_EQ(220, Spdy3PriorityToHttp2Weight(1)); - EXPECT_EQ(183, Spdy3PriorityToHttp2Weight(2)); - EXPECT_EQ(147, Spdy3PriorityToHttp2Weight(3)); - EXPECT_EQ(110, Spdy3PriorityToHttp2Weight(4)); - EXPECT_EQ(74, Spdy3PriorityToHttp2Weight(5)); - EXPECT_EQ(37, Spdy3PriorityToHttp2Weight(6)); - EXPECT_EQ(1, Spdy3PriorityToHttp2Weight(7)); -} - -TEST(SpdyProtocolTest, Http2WeightToSpdy3Priority) { - EXPECT_EQ(0u, Http2WeightToSpdy3Priority(256)); - EXPECT_EQ(0u, Http2WeightToSpdy3Priority(221)); - EXPECT_EQ(1u, Http2WeightToSpdy3Priority(220)); - EXPECT_EQ(1u, Http2WeightToSpdy3Priority(184)); - EXPECT_EQ(2u, Http2WeightToSpdy3Priority(183)); - EXPECT_EQ(2u, Http2WeightToSpdy3Priority(148)); - EXPECT_EQ(3u, Http2WeightToSpdy3Priority(147)); - EXPECT_EQ(3u, Http2WeightToSpdy3Priority(111)); - EXPECT_EQ(4u, Http2WeightToSpdy3Priority(110)); - EXPECT_EQ(4u, Http2WeightToSpdy3Priority(75)); - EXPECT_EQ(5u, Http2WeightToSpdy3Priority(74)); - EXPECT_EQ(5u, Http2WeightToSpdy3Priority(38)); - EXPECT_EQ(6u, Http2WeightToSpdy3Priority(37)); - EXPECT_EQ(6u, Http2WeightToSpdy3Priority(2)); - EXPECT_EQ(7u, Http2WeightToSpdy3Priority(1)); -} - -TEST(SpdyProtocolTest, IsValidHTTP2FrameStreamId) { - // Stream-specific frames must have non-zero stream ids - EXPECT_TRUE(IsValidHTTP2FrameStreamId(1, SpdyFrameType::DATA)); - EXPECT_FALSE(IsValidHTTP2FrameStreamId(0, SpdyFrameType::DATA)); - EXPECT_TRUE(IsValidHTTP2FrameStreamId(1, SpdyFrameType::HEADERS)); - EXPECT_FALSE(IsValidHTTP2FrameStreamId(0, SpdyFrameType::HEADERS)); - EXPECT_TRUE(IsValidHTTP2FrameStreamId(1, SpdyFrameType::PRIORITY)); - EXPECT_FALSE(IsValidHTTP2FrameStreamId(0, SpdyFrameType::PRIORITY)); - EXPECT_TRUE(IsValidHTTP2FrameStreamId(1, SpdyFrameType::RST_STREAM)); - EXPECT_FALSE(IsValidHTTP2FrameStreamId(0, SpdyFrameType::RST_STREAM)); - EXPECT_TRUE(IsValidHTTP2FrameStreamId(1, SpdyFrameType::CONTINUATION)); - EXPECT_FALSE(IsValidHTTP2FrameStreamId(0, SpdyFrameType::CONTINUATION)); - EXPECT_TRUE(IsValidHTTP2FrameStreamId(1, SpdyFrameType::PUSH_PROMISE)); - EXPECT_FALSE(IsValidHTTP2FrameStreamId(0, SpdyFrameType::PUSH_PROMISE)); - - // Connection-level frames must have zero stream ids - EXPECT_FALSE(IsValidHTTP2FrameStreamId(1, SpdyFrameType::GOAWAY)); - EXPECT_TRUE(IsValidHTTP2FrameStreamId(0, SpdyFrameType::GOAWAY)); - EXPECT_FALSE(IsValidHTTP2FrameStreamId(1, SpdyFrameType::SETTINGS)); - EXPECT_TRUE(IsValidHTTP2FrameStreamId(0, SpdyFrameType::SETTINGS)); - EXPECT_FALSE(IsValidHTTP2FrameStreamId(1, SpdyFrameType::PING)); - EXPECT_TRUE(IsValidHTTP2FrameStreamId(0, SpdyFrameType::PING)); - - // Frames that are neither stream-specific nor connection-level - // should not have their stream id declared invalid - EXPECT_TRUE(IsValidHTTP2FrameStreamId(1, SpdyFrameType::WINDOW_UPDATE)); - EXPECT_TRUE(IsValidHTTP2FrameStreamId(0, SpdyFrameType::WINDOW_UPDATE)); -} - -TEST(SpdyProtocolTest, ParseSettingsId) { - SpdyKnownSettingsId setting_id; - EXPECT_FALSE(ParseSettingsId(0, &setting_id)); - EXPECT_TRUE(ParseSettingsId(1, &setting_id)); - EXPECT_EQ(SETTINGS_HEADER_TABLE_SIZE, setting_id); - EXPECT_TRUE(ParseSettingsId(2, &setting_id)); - EXPECT_EQ(SETTINGS_ENABLE_PUSH, setting_id); - EXPECT_TRUE(ParseSettingsId(3, &setting_id)); - EXPECT_EQ(SETTINGS_MAX_CONCURRENT_STREAMS, setting_id); - EXPECT_TRUE(ParseSettingsId(4, &setting_id)); - EXPECT_EQ(SETTINGS_INITIAL_WINDOW_SIZE, setting_id); - EXPECT_TRUE(ParseSettingsId(5, &setting_id)); - EXPECT_EQ(SETTINGS_MAX_FRAME_SIZE, setting_id); - EXPECT_TRUE(ParseSettingsId(6, &setting_id)); - EXPECT_EQ(SETTINGS_MAX_HEADER_LIST_SIZE, setting_id); - EXPECT_FALSE(ParseSettingsId(7, &setting_id)); - EXPECT_TRUE(ParseSettingsId(8, &setting_id)); - EXPECT_EQ(SETTINGS_ENABLE_CONNECT_PROTOCOL, setting_id); - EXPECT_FALSE(ParseSettingsId(9, &setting_id)); - EXPECT_FALSE(ParseSettingsId(0xFF44, &setting_id)); - EXPECT_TRUE(ParseSettingsId(0xFF45, &setting_id)); - EXPECT_EQ(SETTINGS_EXPERIMENT_SCHEDULER, setting_id); - EXPECT_FALSE(ParseSettingsId(0xFF46, &setting_id)); -} - -TEST(SpdyProtocolTest, SettingsIdToString) { - struct { - SpdySettingsId setting_id; - const SpdyString expected_string; - } test_cases[] = { - {0, "SETTINGS_UNKNOWN_0"}, - {SETTINGS_HEADER_TABLE_SIZE, "SETTINGS_HEADER_TABLE_SIZE"}, - {SETTINGS_ENABLE_PUSH, "SETTINGS_ENABLE_PUSH"}, - {SETTINGS_MAX_CONCURRENT_STREAMS, "SETTINGS_MAX_CONCURRENT_STREAMS"}, - {SETTINGS_INITIAL_WINDOW_SIZE, "SETTINGS_INITIAL_WINDOW_SIZE"}, - {SETTINGS_MAX_FRAME_SIZE, "SETTINGS_MAX_FRAME_SIZE"}, - {SETTINGS_MAX_HEADER_LIST_SIZE, "SETTINGS_MAX_HEADER_LIST_SIZE"}, - {7, "SETTINGS_UNKNOWN_7"}, - {SETTINGS_ENABLE_CONNECT_PROTOCOL, "SETTINGS_ENABLE_CONNECT_PROTOCOL"}, - {9, "SETTINGS_UNKNOWN_9"}, - {0xFF44, "SETTINGS_UNKNOWN_ff44"}, - {0xFF45, "SETTINGS_EXPERIMENT_SCHEDULER"}, - {0xFF46, "SETTINGS_UNKNOWN_ff46"}}; - for (auto test_case : test_cases) { - EXPECT_EQ(test_case.expected_string, - SettingsIdToString(test_case.setting_id)); - } -} - -TEST(SpdyStreamPrecedenceTest, Basic) { - SpdyStreamPrecedence spdy3_prec(2); - EXPECT_TRUE(spdy3_prec.is_spdy3_priority()); - EXPECT_EQ(2, spdy3_prec.spdy3_priority()); - EXPECT_EQ(kHttp2RootStreamId, spdy3_prec.parent_id()); - EXPECT_EQ(Spdy3PriorityToHttp2Weight(2), spdy3_prec.weight()); - EXPECT_FALSE(spdy3_prec.is_exclusive()); - - for (bool is_exclusive : {true, false}) { - SpdyStreamPrecedence h2_prec(7, 123, is_exclusive); - EXPECT_FALSE(h2_prec.is_spdy3_priority()); - EXPECT_EQ(Http2WeightToSpdy3Priority(123), h2_prec.spdy3_priority()); - EXPECT_EQ(7u, h2_prec.parent_id()); - EXPECT_EQ(123, h2_prec.weight()); - EXPECT_EQ(is_exclusive, h2_prec.is_exclusive()); - } -} - -TEST(SpdyStreamPrecedenceTest, Clamping) { - EXPECT_SPDY_BUG(EXPECT_EQ(7, SpdyStreamPrecedence(8).spdy3_priority()), - "Invalid priority: 8"); - EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2MinStreamWeight, - SpdyStreamPrecedence(3, 0, false).weight()), - "Invalid weight: 0"); - EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2MaxStreamWeight, - SpdyStreamPrecedence(3, 300, false).weight()), - "Invalid weight: 300"); -} - -TEST(SpdyStreamPrecedenceTest, Copying) { - SpdyStreamPrecedence prec1(3); - SpdyStreamPrecedence copy1(prec1); - EXPECT_TRUE(copy1.is_spdy3_priority()); - EXPECT_EQ(3, copy1.spdy3_priority()); - - SpdyStreamPrecedence prec2(4, 5, true); - SpdyStreamPrecedence copy2(prec2); - EXPECT_FALSE(copy2.is_spdy3_priority()); - EXPECT_EQ(4u, copy2.parent_id()); - EXPECT_EQ(5, copy2.weight()); - EXPECT_TRUE(copy2.is_exclusive()); - - copy1 = prec2; - EXPECT_FALSE(copy1.is_spdy3_priority()); - EXPECT_EQ(4u, copy1.parent_id()); - EXPECT_EQ(5, copy1.weight()); - EXPECT_TRUE(copy1.is_exclusive()); - - copy2 = prec1; - EXPECT_TRUE(copy2.is_spdy3_priority()); - EXPECT_EQ(3, copy2.spdy3_priority()); -} - -TEST(SpdyStreamPrecedenceTest, Equals) { - EXPECT_EQ(SpdyStreamPrecedence(3), SpdyStreamPrecedence(3)); - EXPECT_NE(SpdyStreamPrecedence(3), SpdyStreamPrecedence(4)); - - EXPECT_EQ(SpdyStreamPrecedence(1, 2, false), - SpdyStreamPrecedence(1, 2, false)); - EXPECT_NE(SpdyStreamPrecedence(1, 2, false), - SpdyStreamPrecedence(2, 2, false)); - EXPECT_NE(SpdyStreamPrecedence(1, 2, false), - SpdyStreamPrecedence(1, 3, false)); - EXPECT_NE(SpdyStreamPrecedence(1, 2, false), - SpdyStreamPrecedence(1, 2, true)); - - SpdyStreamPrecedence spdy3_prec(3); - SpdyStreamPrecedence h2_prec(spdy3_prec.parent_id(), spdy3_prec.weight(), - spdy3_prec.is_exclusive()); - EXPECT_NE(spdy3_prec, h2_prec); -} - -TEST(SpdyDataIRTest, Construct) { - // Confirm that it makes a string of zero length from a - // SpdyStringPiece(nullptr). - SpdyStringPiece s1; - SpdyDataIR d1(/* stream_id = */ 1, s1); - EXPECT_EQ(0u, d1.data_len()); - EXPECT_NE(nullptr, d1.data()); - - // Confirms makes a copy of char array. - const char s2[] = "something"; - SpdyDataIR d2(/* stream_id = */ 2, s2); - EXPECT_EQ(SpdyStringPiece(d2.data(), d2.data_len()), s2); - EXPECT_NE(SpdyStringPiece(d1.data(), d1.data_len()), s2); - EXPECT_EQ((int)d1.data_len(), d1.flow_control_window_consumed()); - - // Confirm copies a const string. - const SpdyString foo = "foo"; - SpdyDataIR d3(/* stream_id = */ 3, foo); - EXPECT_EQ(foo, d3.data()); - EXPECT_EQ((int)d3.data_len(), d3.flow_control_window_consumed()); - - // Confirm copies a non-const string. - SpdyString bar = "bar"; - SpdyDataIR d4(/* stream_id = */ 4, bar); - EXPECT_EQ("bar", bar); - EXPECT_EQ("bar", SpdyStringPiece(d4.data(), d4.data_len())); - - // Confirm moves an rvalue reference. Note that the test string "baz" is too - // short to trigger the move optimization, and instead a copy occurs. - SpdyString baz = "the quick brown fox"; - SpdyDataIR d5(/* stream_id = */ 5, std::move(baz)); - EXPECT_EQ("", baz); - EXPECT_EQ(SpdyStringPiece(d5.data(), d5.data_len()), "the quick brown fox"); - - // Confirms makes a copy of string literal. - SpdyDataIR d7(/* stream_id = */ 7, "something else"); - EXPECT_EQ(SpdyStringPiece(d7.data(), d7.data_len()), "something else"); - - SpdyDataIR d8(/* stream_id = */ 8, "shawarma"); - d8.set_padding_len(20); - EXPECT_EQ(28, d8.flow_control_window_consumed()); -} - -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_protocol_test_utils.cc b/net/third_party/spdy/core/spdy_protocol_test_utils.cc deleted file mode 100644 index 3e39dc9f..0000000 --- a/net/third_party/spdy/core/spdy_protocol_test_utils.cc +++ /dev/null
@@ -1,155 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_protocol_test_utils.h" - -#include <cstdint> - -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" - -namespace spdy { -namespace test { - -// TODO(jamessynge): Where it makes sense in these functions, it would be nice -// to make use of the existing gMock matchers here, instead of rolling our own. - -::testing::AssertionResult VerifySpdyFrameWithHeaderBlockIREquals( - const SpdyFrameWithHeaderBlockIR& expected, - const SpdyFrameWithHeaderBlockIR& actual) { - VLOG(1) << "VerifySpdyFrameWithHeaderBlockIREquals"; - VERIFY_TRUE(actual.header_block() == expected.header_block()); - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyAltSvcIR& expected, - const SpdyAltSvcIR& actual) { - VERIFY_EQ(expected.stream_id(), actual.stream_id()); - VERIFY_EQ(expected.origin(), actual.origin()); - VERIFY_THAT(actual.altsvc_vector(), - ::testing::ContainerEq(expected.altsvc_vector())); - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdyContinuationIR& expected, - const SpdyContinuationIR& actual) { - return ::testing::AssertionFailure() - << "VerifySpdyFrameIREquals SpdyContinuationIR not yet implemented"; -} - -::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyDataIR& expected, - const SpdyDataIR& actual) { - VLOG(1) << "VerifySpdyFrameIREquals SpdyDataIR"; - VERIFY_EQ(expected.stream_id(), actual.stream_id()); - VERIFY_EQ(expected.fin(), actual.fin()); - VERIFY_EQ(expected.data_len(), actual.data_len()); - if (expected.data() == nullptr) { - VERIFY_EQ(nullptr, actual.data()); - } else { - VERIFY_EQ(SpdyStringPiece(expected.data(), expected.data_len()), - SpdyStringPiece(actual.data(), actual.data_len())); - } - VERIFY_SUCCESS(VerifySpdyFrameWithPaddingIREquals(expected, actual)); - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyGoAwayIR& expected, - const SpdyGoAwayIR& actual) { - VLOG(1) << "VerifySpdyFrameIREquals SpdyGoAwayIR"; - VERIFY_EQ(expected.last_good_stream_id(), actual.last_good_stream_id()); - VERIFY_EQ(expected.error_code(), actual.error_code()); - VERIFY_EQ(expected.description(), actual.description()); - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdyHeadersIR& expected, - const SpdyHeadersIR& actual) { - VLOG(1) << "VerifySpdyFrameIREquals SpdyHeadersIR"; - VERIFY_EQ(expected.stream_id(), actual.stream_id()); - VERIFY_EQ(expected.fin(), actual.fin()); - VERIFY_SUCCESS(VerifySpdyFrameWithHeaderBlockIREquals(expected, actual)); - VERIFY_EQ(expected.has_priority(), actual.has_priority()); - if (expected.has_priority()) { - VERIFY_SUCCESS(VerifySpdyFrameWithPriorityIREquals(expected, actual)); - } - VERIFY_SUCCESS(VerifySpdyFrameWithPaddingIREquals(expected, actual)); - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyPingIR& expected, - const SpdyPingIR& actual) { - VLOG(1) << "VerifySpdyFrameIREquals SpdyPingIR"; - VERIFY_EQ(expected.id(), actual.id()); - VERIFY_EQ(expected.is_ack(), actual.is_ack()); - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdyPriorityIR& expected, - const SpdyPriorityIR& actual) { - VLOG(1) << "VerifySpdyFrameIREquals SpdyPriorityIR"; - VERIFY_EQ(expected.stream_id(), actual.stream_id()); - VERIFY_SUCCESS(VerifySpdyFrameWithPriorityIREquals(expected, actual)); - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdyPushPromiseIR& expected, - const SpdyPushPromiseIR& actual) { - VLOG(1) << "VerifySpdyFrameIREquals SpdyPushPromiseIR"; - VERIFY_EQ(expected.stream_id(), actual.stream_id()); - VERIFY_SUCCESS(VerifySpdyFrameWithPaddingIREquals(expected, actual)); - VERIFY_EQ(expected.promised_stream_id(), actual.promised_stream_id()); - VERIFY_SUCCESS(VerifySpdyFrameWithHeaderBlockIREquals(expected, actual)); - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdyRstStreamIR& expected, - const SpdyRstStreamIR& actual) { - VLOG(1) << "VerifySpdyFrameIREquals SpdyRstStreamIR"; - VERIFY_EQ(expected.stream_id(), actual.stream_id()); - VERIFY_EQ(expected.error_code(), actual.error_code()); - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdySettingsIR& expected, - const SpdySettingsIR& actual) { - VLOG(1) << "VerifySpdyFrameIREquals SpdySettingsIR"; - // Note, ignoring non-HTTP/2 fields such as clear_settings. - VERIFY_EQ(expected.is_ack(), actual.is_ack()); - - // Note, the following doesn't work because there isn't a comparator and - // formatter for SpdySettingsIR::Value. Fixable if we cared. - // - // VERIFY_THAT(actual.values(), ::testing::ContainerEq(actual.values())); - - VERIFY_EQ(expected.values().size(), actual.values().size()); - for (const auto& entry : expected.values()) { - const auto& param = entry.first; - auto actual_itr = actual.values().find(param); - VERIFY_TRUE(!(actual_itr == actual.values().end())) - << "actual doesn't contain param: " << param; - uint32_t expected_value = entry.second; - uint32_t actual_value = actual_itr->second; - VERIFY_EQ(expected_value, actual_value) - << "Values don't match for parameter: " << param; - } - - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdyWindowUpdateIR& expected, - const SpdyWindowUpdateIR& actual) { - VLOG(1) << "VerifySpdyFrameIREquals SpdyWindowUpdateIR"; - VERIFY_EQ(expected.stream_id(), actual.stream_id()); - VERIFY_EQ(expected.delta(), actual.delta()); - return ::testing::AssertionSuccess(); -} - -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_protocol_test_utils.h b/net/third_party/spdy/core/spdy_protocol_test_utils.h deleted file mode 100644 index 75860ef..0000000 --- a/net/third_party/spdy/core/spdy_protocol_test_utils.h +++ /dev/null
@@ -1,149 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_PROTOCOL_TEST_UTILS_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_PROTOCOL_TEST_UTILS_H_ - -// These functions support tests that need to compare two concrete SpdyFrameIR -// instances for equality. They return AssertionResult, so they may be used as -// follows: -// -// SomeSpdyFrameIRSubClass expected_ir(...); -// std::unique_ptr<SpdyFrameIR> collected_frame; -// ... some test code that may fill in collected_frame ... -// ASSERT_TRUE(VerifySpdyFrameIREquals(expected_ir, collected_frame.get())); -// -// TODO(jamessynge): Where it makes sense in these functions, it would be nice -// to make use of the existing gMock matchers here, instead of rolling our own. - -#include <typeinfo> - -#include "base/logging.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/core/spdy_test_utils.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { -namespace test { - -// Verify the header entries in two SpdyFrameWithHeaderBlockIR instances -// are the same. -::testing::AssertionResult VerifySpdyFrameWithHeaderBlockIREquals( - const SpdyFrameWithHeaderBlockIR& expected, - const SpdyFrameWithHeaderBlockIR& actual); - -// Verify that the padding in two frames of type T is the same. -template <class T> -::testing::AssertionResult VerifySpdyFrameWithPaddingIREquals(const T& expected, - const T& actual) { - VLOG(1) << "VerifySpdyFrameWithPaddingIREquals"; - VERIFY_EQ(expected.padded(), actual.padded()); - if (expected.padded()) { - VERIFY_EQ(expected.padding_payload_len(), actual.padding_payload_len()); - } - - return ::testing::AssertionSuccess(); -} - -// Verify the priority fields in two frames of type T are the same. -template <class T> -::testing::AssertionResult VerifySpdyFrameWithPriorityIREquals( - const T& expected, - const T& actual) { - VLOG(1) << "VerifySpdyFrameWithPriorityIREquals"; - VERIFY_EQ(expected.parent_stream_id(), actual.parent_stream_id()); - VERIFY_EQ(expected.weight(), actual.weight()); - VERIFY_EQ(expected.exclusive(), actual.exclusive()); - return ::testing::AssertionSuccess(); -} - -// Verify that two SpdyAltSvcIR frames are the same. -::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyAltSvcIR& expected, - const SpdyAltSvcIR& actual); - -// VerifySpdyFrameIREquals for SpdyContinuationIR frames isn't really needed -// because we don't really make use of SpdyContinuationIR, instead creating -// SpdyHeadersIR or SpdyPushPromiseIR with the pre-encoding form of the HPACK -// block (i.e. we don't yet have a CONTINUATION frame). -// -// ::testing::AssertionResult VerifySpdyFrameIREquals( -// const SpdyContinuationIR& expected, -// const SpdyContinuationIR& actual) { -// return ::testing::AssertionFailure() -// << "VerifySpdyFrameIREquals SpdyContinuationIR NYI"; -// } - -// Verify that two SpdyDataIR frames are the same. -::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyDataIR& expected, - const SpdyDataIR& actual); - -// Verify that two SpdyGoAwayIR frames are the same. -::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyGoAwayIR& expected, - const SpdyGoAwayIR& actual); - -// Verify that two SpdyHeadersIR frames are the same. -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdyHeadersIR& expected, - const SpdyHeadersIR& actual); - -// Verify that two SpdyPingIR frames are the same. -::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyPingIR& expected, - const SpdyPingIR& actual); - -// Verify that two SpdyPriorityIR frames are the same. -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdyPriorityIR& expected, - const SpdyPriorityIR& actual); - -// Verify that two SpdyPushPromiseIR frames are the same. -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdyPushPromiseIR& expected, - const SpdyPushPromiseIR& actual); - -// Verify that two SpdyRstStreamIR frames are the same. -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdyRstStreamIR& expected, - const SpdyRstStreamIR& actual); - -// Verify that two SpdySettingsIR frames are the same. -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdySettingsIR& expected, - const SpdySettingsIR& actual); - -// Verify that two SpdyWindowUpdateIR frames are the same. -::testing::AssertionResult VerifySpdyFrameIREquals( - const SpdyWindowUpdateIR& expected, - const SpdyWindowUpdateIR& actual); - -// Verify that either expected and actual are both nullptr, or that both are not -// nullptr, and that actual is of type E, and that it matches expected. -template <class E> -::testing::AssertionResult VerifySpdyFrameIREquals(const E* expected, - const SpdyFrameIR* actual) { - if (expected == nullptr || actual == nullptr) { - VLOG(1) << "VerifySpdyFrameIREquals one null"; - VERIFY_EQ(expected, nullptr); - VERIFY_EQ(actual, nullptr); - return ::testing::AssertionSuccess(); - } - VLOG(1) << "VerifySpdyFrameIREquals not null"; - VERIFY_EQ(actual->frame_type(), expected->frame_type()); - const E* actual2 = static_cast<const E*>(actual); - return VerifySpdyFrameIREquals(*expected, *actual2); -} - -// Verify that actual is not nullptr, that it is of type E and that it -// matches expected. -template <class E> -::testing::AssertionResult VerifySpdyFrameIREquals(const E& expected, - const SpdyFrameIR* actual) { - VLOG(1) << "VerifySpdyFrameIREquals"; - return VerifySpdyFrameIREquals(&expected, actual); -} - -} // namespace test -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_PROTOCOL_TEST_UTILS_H_
diff --git a/net/third_party/spdy/core/spdy_test_utils.cc b/net/third_party/spdy/core/spdy_test_utils.cc deleted file mode 100644 index e1bf36c..0000000 --- a/net/third_party/spdy/core/spdy_test_utils.cc +++ /dev/null
@@ -1,119 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/core/spdy_test_utils.h" - -#include <algorithm> -#include <cstring> -#include <memory> -#include <new> -#include <utility> -#include <vector> - -#include "base/logging.h" -#include "net/third_party/spdy/platform/api/spdy_endianness_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { -namespace test { - -SpdyString HexDumpWithMarks(const unsigned char* data, - int length, - const bool* marks, - int mark_length) { - static const char kHexChars[] = "0123456789abcdef"; - static const int kColumns = 4; - - const int kSizeLimit = 1024; - if (length > kSizeLimit || mark_length > kSizeLimit) { - LOG(ERROR) << "Only dumping first " << kSizeLimit << " bytes."; - length = std::min(length, kSizeLimit); - mark_length = std::min(mark_length, kSizeLimit); - } - - SpdyString hex; - for (const unsigned char* row = data; length > 0; - row += kColumns, length -= kColumns) { - for (const unsigned char* p = row; p < row + 4; ++p) { - if (p < row + length) { - const bool mark = - (marks && (p - data) < mark_length && marks[p - data]); - hex += mark ? '*' : ' '; - hex += kHexChars[(*p & 0xf0) >> 4]; - hex += kHexChars[*p & 0x0f]; - hex += mark ? '*' : ' '; - } else { - hex += " "; - } - } - hex = hex + " "; - - for (const unsigned char* p = row; p < row + 4 && p < row + length; ++p) { - hex += (*p >= 0x20 && *p <= 0x7f) ? (*p) : '.'; - } - - hex = hex + '\n'; - } - return hex; -} - -void CompareCharArraysWithHexError(const SpdyString& description, - const unsigned char* actual, - const int actual_len, - const unsigned char* expected, - const int expected_len) { - const int min_len = std::min(actual_len, expected_len); - const int max_len = std::max(actual_len, expected_len); - std::unique_ptr<bool[]> marks(new bool[max_len]); - bool identical = (actual_len == expected_len); - for (int i = 0; i < min_len; ++i) { - if (actual[i] != expected[i]) { - marks[i] = true; - identical = false; - } else { - marks[i] = false; - } - } - for (int i = min_len; i < max_len; ++i) { - marks[i] = true; - } - if (identical) - return; - ADD_FAILURE() << "Description:\n" - << description << "\n\nExpected:\n" - << HexDumpWithMarks(expected, expected_len, marks.get(), - max_len) - << "\nActual:\n" - << HexDumpWithMarks(actual, actual_len, marks.get(), max_len); -} - -void SetFrameFlags(SpdySerializedFrame* frame, uint8_t flags) { - frame->data()[4] = flags; -} - -void SetFrameLength(SpdySerializedFrame* frame, size_t length) { - CHECK_GT(1u << 14, length); - { - int32_t wire_length = SpdyHostToNet32(length); - memcpy(frame->data(), reinterpret_cast<char*>(&wire_length) + 1, 3); - } -} - -void TestHeadersHandler::OnHeaderBlockStart() { - block_.clear(); -} - -void TestHeadersHandler::OnHeader(SpdyStringPiece name, SpdyStringPiece value) { - block_.AppendValueOrAddHeader(name, value); -} - -void TestHeadersHandler::OnHeaderBlockEnd( - size_t header_bytes_parsed, - size_t compressed_header_bytes_parsed) { - header_bytes_parsed_ = header_bytes_parsed; - compressed_header_bytes_parsed_ = compressed_header_bytes_parsed; -} - -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/core/spdy_test_utils.h b/net/third_party/spdy/core/spdy_test_utils.h deleted file mode 100644 index 334fd47..0000000 --- a/net/third_party/spdy/core/spdy_test_utils.h +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_SPDY_TEST_UTILS_H_ -#define NET_THIRD_PARTY_SPDY_CORE_SPDY_TEST_UTILS_H_ - -#include <cstddef> -#include <cstdint> - -#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h" -#include "net/third_party/spdy/core/spdy_header_block.h" -#include "net/third_party/spdy/core/spdy_headers_handler_interface.h" -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/platform/api/spdy_bug_tracker.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" -#include "net/third_party/spdy/platform/api/spdy_test_helpers.h" - -namespace spdy { - -inline bool operator==(SpdyStringPiece x, - const SpdyHeaderBlock::ValueProxy& y) { - return x == y.as_string(); -} - -namespace test { - -SpdyString HexDumpWithMarks(const unsigned char* data, - int length, - const bool* marks, - int mark_length); - -void CompareCharArraysWithHexError(const SpdyString& description, - const unsigned char* actual, - const int actual_len, - const unsigned char* expected, - const int expected_len); - -void SetFrameFlags(SpdySerializedFrame* frame, uint8_t flags); - -void SetFrameLength(SpdySerializedFrame* frame, size_t length); - -// A test implementation of SpdyHeadersHandlerInterface that correctly -// reconstructs multiple header values for the same name. -class TestHeadersHandler : public SpdyHeadersHandlerInterface { - public: - TestHeadersHandler() {} - TestHeadersHandler(const TestHeadersHandler&) = delete; - TestHeadersHandler& operator=(const TestHeadersHandler&) = delete; - - void OnHeaderBlockStart() override; - - void OnHeader(SpdyStringPiece name, SpdyStringPiece value) override; - - void OnHeaderBlockEnd(size_t header_bytes_parsed, - size_t compressed_header_bytes_parsed) override; - - const SpdyHeaderBlock& decoded_block() const { return block_; } - size_t header_bytes_parsed() const { return header_bytes_parsed_; } - size_t compressed_header_bytes_parsed() const { - return compressed_header_bytes_parsed_; - } - - private: - SpdyHeaderBlock block_; - size_t header_bytes_parsed_ = 0; - size_t compressed_header_bytes_parsed_ = 0; -}; - -} // namespace test -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_SPDY_TEST_UTILS_H_
diff --git a/net/third_party/spdy/core/write_scheduler.h b/net/third_party/spdy/core/write_scheduler.h deleted file mode 100644 index 2494016..0000000 --- a/net/third_party/spdy/core/write_scheduler.h +++ /dev/null
@@ -1,156 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_WRITE_SCHEDULER_H_ -#define NET_THIRD_PARTY_SPDY_CORE_WRITE_SCHEDULER_H_ - -#include <cstdint> -#include <tuple> -#include <vector> - -#include "net/third_party/spdy/core/spdy_protocol.h" -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/api/spdy_string.h" - -namespace spdy { - -// Abstract superclass for classes that decide which SPDY or HTTP/2 stream to -// write next. Concrete subclasses implement various scheduling policies: -// -// PriorityWriteScheduler: implements SPDY priority-based stream scheduling, -// where (writable) higher-priority streams are always given precedence -// over lower-priority streams. -// -// Http2PriorityWriteScheduler: implements SPDY priority-based stream -// scheduling coupled with the HTTP/2 stream dependency model. This is only -// intended as a transitional step towards Http2WeightedWriteScheduler. -// -// Http2WeightedWriteScheduler (coming soon): implements the HTTP/2 stream -// dependency model with weighted stream scheduling, fully conforming to -// RFC 7540. -// -// The type used to represent stream IDs (StreamIdType) is templated in order -// to allow for use by both SPDY and QUIC codebases. It must be a POD that -// supports comparison (i.e., a numeric type). -// -// Each stream can be in one of two states: ready or not ready (for writing). -// Ready state is changed by calling the MarkStreamReady() and -// MarkStreamNotReady() methods. Only streams in the ready state can be -// returned by PopNextReadyStream(); when returned by that method, the stream's -// state changes to not ready. -template <typename StreamIdType> -class SPDY_EXPORT_PRIVATE WriteScheduler { - public: - typedef StreamPrecedence<StreamIdType> StreamPrecedenceType; - - virtual ~WriteScheduler() {} - - // Registers new stream |stream_id| with the scheduler, assigning it the - // given precedence. If the scheduler supports stream dependencies, the - // stream is inserted into the dependency tree under - // |precedence.parent_id()|. - // - // Preconditions: |stream_id| should be unregistered, and - // |precedence.parent_id()| should be registered or |kHttp2RootStreamId|. - virtual void RegisterStream(StreamIdType stream_id, - const StreamPrecedenceType& precedence) = 0; - - // Unregisters the given stream from the scheduler, which will no longer keep - // state for it. - // - // Preconditions: |stream_id| should be registered. - virtual void UnregisterStream(StreamIdType stream_id) = 0; - - // Returns true if the given stream is currently registered. - virtual bool StreamRegistered(StreamIdType stream_id) const = 0; - - // Returns the precedence of the specified stream. If the scheduler supports - // stream dependencies, calling |parent_id()| on the return value returns the - // stream's parent, and calling |exclusive()| returns true iff the specified - // stream is an only child of the parent stream. - // - // Preconditions: |stream_id| should be registered. - virtual StreamPrecedenceType GetStreamPrecedence( - StreamIdType stream_id) const = 0; - - // Updates the precedence of the given stream. If the scheduler supports - // stream dependencies, |stream_id|'s parent will be updated to be - // |precedence.parent_id()| if it is not already. - // - // Preconditions: |stream_id| should be unregistered, and - // |precedence.parent_id()| should be registered or |kHttp2RootStreamId|. - virtual void UpdateStreamPrecedence( - StreamIdType stream_id, - const StreamPrecedenceType& precedence) = 0; - - // Returns child streams of the given stream, if any. If the scheduler - // doesn't support stream dependencies, returns an empty vector. - // - // Preconditions: |stream_id| should be registered. - virtual std::vector<StreamIdType> GetStreamChildren( - StreamIdType stream_id) const = 0; - - // Records time (in microseconds) of a read/write event for the given - // stream. - // - // Preconditions: |stream_id| should be registered. - virtual void RecordStreamEventTime(StreamIdType stream_id, - int64_t now_in_usec) = 0; - - // Returns time (in microseconds) of the last read/write event for a stream - // with higher priority than the priority of the given stream, or 0 if there - // is no such event. - // - // Preconditions: |stream_id| should be registered. - virtual int64_t GetLatestEventWithPrecedence( - StreamIdType stream_id) const = 0; - - // If the scheduler has any ready streams, returns the next scheduled - // ready stream, in the process transitioning the stream from ready to not - // ready. - // - // Preconditions: |HasReadyStreams() == true| - virtual StreamIdType PopNextReadyStream() = 0; - - // If the scheduler has any ready streams, returns the next scheduled - // ready stream and its priority, in the process transitioning the stream from - // ready to not ready. - // - // Preconditions: |HasReadyStreams() == true| - virtual std::tuple<StreamIdType, StreamPrecedenceType> - PopNextReadyStreamAndPrecedence() = 0; - - // Returns true if there's another stream ahead of the given stream in the - // scheduling queue. This function can be called to see if the given stream - // should yield work to another stream. - // - // Preconditions: |stream_id| should be registered. - virtual bool ShouldYield(StreamIdType stream_id) const = 0; - - // Marks the stream as ready to write. If the stream was already ready, does - // nothing. If add_to_front is true, the stream is scheduled ahead of other - // streams of the same priority/weight, otherwise it is scheduled behind them. - // - // Preconditions: |stream_id| should be registered. - virtual void MarkStreamReady(StreamIdType stream_id, bool add_to_front) = 0; - - // Marks the stream as not ready to write. If the stream is not registered or - // not ready, does nothing. - // - // Preconditions: |stream_id| should be registered. - virtual void MarkStreamNotReady(StreamIdType stream_id) = 0; - - // Returns true iff the scheduler has any ready streams. - virtual bool HasReadyStreams() const = 0; - - // Returns the number of streams currently marked ready. - virtual size_t NumReadyStreams() const = 0; - - // Returns summary of internal state, for logging/debugging. - virtual SpdyString DebugString() const = 0; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_WRITE_SCHEDULER_H_
diff --git a/net/third_party/spdy/core/zero_copy_output_buffer.h b/net/third_party/spdy/core/zero_copy_output_buffer.h deleted file mode 100644 index 81f8333..0000000 --- a/net/third_party/spdy/core/zero_copy_output_buffer.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_CORE_ZERO_COPY_OUTPUT_BUFFER_H_ -#define NET_THIRD_PARTY_SPDY_CORE_ZERO_COPY_OUTPUT_BUFFER_H_ - -#include <cstdint> - -namespace spdy { - -class ZeroCopyOutputBuffer { - public: - virtual ~ZeroCopyOutputBuffer() {} - - // Returns the next available segment of memory to write. Will always return - // the same segment until AdvanceWritePtr is called. - virtual void Next(char** data, int* size) = 0; - - // After writing to a buffer returned from Next(), the caller should call - // this method to indicate how many bytes were written. - virtual void AdvanceWritePtr(int64_t count) = 0; - - // Returns the available capacity of the buffer. - virtual uint64_t BytesFree() const = 0; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_CORE_ZERO_COPY_OUTPUT_BUFFER_H_
diff --git a/net/third_party/spdy/platform/api/spdy_arraysize.h b/net/third_party/spdy/platform/api/spdy_arraysize.h deleted file mode 100644 index ac1f9d6a2..0000000 --- a/net/third_party/spdy/platform/api/spdy_arraysize.h +++ /dev/null
@@ -1,12 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_ARRAYSIZE_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_ARRAYSIZE_H_ - -#include "net/third_party/spdy/platform/impl/spdy_arraysize_impl.h" - -#define SPDY_ARRAYSIZE(x) SPDY_ARRAYSIZE_IMPL(x) - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_ARRAYSIZE_H_
diff --git a/net/third_party/spdy/platform/api/spdy_bug_tracker.h b/net/third_party/spdy/platform/api/spdy_bug_tracker.h deleted file mode 100644 index c64ebd7..0000000 --- a/net/third_party/spdy/platform/api/spdy_bug_tracker.h +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_BUG_TRACKER_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_BUG_TRACKER_H_ - -#include "net/third_party/spdy/platform/impl/spdy_bug_tracker_impl.h" - -#define SPDY_BUG SPDY_BUG_IMPL -#define SPDY_BUG_IF(condition) SPDY_BUG_IF_IMPL(condition) -#define FLAGS_spdy_always_log_bugs_for_tests \ - FLAGS_spdy_always_log_bugs_for_tests_impl - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_BUG_TRACKER_H_
diff --git a/net/third_party/spdy/platform/api/spdy_containers.h b/net/third_party/spdy/platform/api/spdy_containers.h deleted file mode 100644 index b53643b0..0000000 --- a/net/third_party/spdy/platform/api/spdy_containers.h +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_CONTAINERS_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_CONTAINERS_H_ - -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" -#include "net/third_party/spdy/platform/impl/spdy_containers_impl.h" - -namespace spdy { - -template <typename KeyType> -using SpdyHash = SpdyHashImpl<KeyType>; - -// SpdyHashMap does not guarantee pointer stability. -template <typename KeyType, - typename ValueType, - typename Hash = SpdyHash<KeyType>> -using SpdyHashMap = SpdyHashMapImpl<KeyType, ValueType, Hash>; - -// SpdyHashSet does not guarantee pointer stability. -template <typename ElementType, typename Hasher, typename Eq> -using SpdyHashSet = SpdyHashSetImpl<ElementType, Hasher, Eq>; - -// A map which offers insertion-ordered iteration. -template <typename Key, typename Value, typename Hash = SpdyHash<Key>> -using SpdyLinkedHashMap = SpdyLinkedHashMapImpl<Key, Value, Hash>; - -// A vector optimized for small sizes. Provides the same APIs as a std::vector. -template <typename T, size_t N, typename A = std::allocator<T>> -using SpdyInlinedVector = SpdyInlinedVectorImpl<T, N, A>; - -using SpdyStringPieceHash = SpdyStringPieceHashImpl; - -inline size_t SpdyHashStringPair(SpdyStringPiece a, SpdyStringPiece b) { - return SpdyHashStringPairImpl(a, b); -} - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_CONTAINERS_H_
diff --git a/net/third_party/spdy/platform/api/spdy_endianness_util.h b/net/third_party/spdy/platform/api/spdy_endianness_util.h deleted file mode 100644 index d14ad8b..0000000 --- a/net/third_party/spdy/platform/api/spdy_endianness_util.h +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_ENDIANNESS_UTIL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_ENDIANNESS_UTIL_H_ - -#include <stdint.h> - -#include "net/third_party/spdy/platform/impl/spdy_endianness_util_impl.h" - -namespace spdy { - -// Converts the bytes in |x| from network to host order (endianness), and -// returns the result. -inline uint16_t SpdyNetToHost16(uint16_t x) { - return SpdyNetToHost16Impl(x); -} - -inline uint32_t SpdyNetToHost32(uint32_t x) { - return SpdyNetToHost32Impl(x); -} - -inline uint64_t SpdyNetToHost64(uint64_t x) { - return SpdyNetToHost64Impl(x); -} - -// Converts the bytes in |x| from host to network order (endianness), and -// returns the result. -inline uint16_t SpdyHostToNet16(uint16_t x) { - return SpdyHostToNet16Impl(x); -} - -inline uint32_t SpdyHostToNet32(uint32_t x) { - return SpdyHostToNet32Impl(x); -} - -inline uint64_t SpdyHostToNet64(uint64_t x) { - return SpdyHostToNet64Impl(x); -} - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_ENDIANNESS_UTIL_H_
diff --git a/net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h b/net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h deleted file mode 100644 index 6b2c529fc..0000000 --- a/net/third_party/spdy/platform/api/spdy_estimate_memory_usage.h +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_ESTIMATE_MEMORY_USAGE_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_ESTIMATE_MEMORY_USAGE_H_ - -#include <cstddef> - -#include "net/third_party/spdy/platform/impl/spdy_estimate_memory_usage_impl.h" - -namespace spdy { - -template <class T> -size_t SpdyEstimateMemoryUsage(const T& object) { - return SpdyEstimateMemoryUsageImpl(object); -} - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_ESTIMATE_MEMORY_USAGE_H_
diff --git a/net/third_party/spdy/platform/api/spdy_export.h b/net/third_party/spdy/platform/api/spdy_export.h deleted file mode 100644 index 8b3ee22..0000000 --- a/net/third_party/spdy/platform/api/spdy_export.h +++ /dev/null
@@ -1,10 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_EXPORT_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_EXPORT_H_ - -#include "net/third_party/spdy/platform/impl/spdy_export_impl.h" - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_EXPORT_H_
diff --git a/net/third_party/spdy/platform/api/spdy_flags.h b/net/third_party/spdy/platform/api/spdy_flags.h deleted file mode 100644 index be11e2ba..0000000 --- a/net/third_party/spdy/platform/api/spdy_flags.h +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_FLAGS_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_FLAGS_H_ - -#include "net/third_party/spdy/platform/impl/spdy_flags_impl.h" - -#define GetSpdyReloadableFlag(flag) GetSpdyReloadableFlagImpl(flag) -#define GetSpdyRestartFlag(flag) GetSpdyRestartFlagImpl(flag) - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_FLAGS_H_
diff --git a/net/third_party/spdy/platform/api/spdy_macros.h b/net/third_party/spdy/platform/api/spdy_macros.h deleted file mode 100644 index 30ea23a..0000000 --- a/net/third_party/spdy/platform/api/spdy_macros.h +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_MACROS_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_MACROS_H_ - -#include "net/third_party/spdy/platform/impl/spdy_macros_impl.h" - -#define SPDY_MUST_USE_RESULT SPDY_MUST_USE_RESULT_IMPL -#define SPDY_UNUSED SPDY_UNUSED_IMPL - -#define SPDY_DVLOG_IF SPDY_DVLOG_IF_IMPL - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_MACROS_H_
diff --git a/net/third_party/spdy/platform/api/spdy_mem_slice.h b/net/third_party/spdy/platform/api/spdy_mem_slice.h deleted file mode 100644 index 6d644b23..0000000 --- a/net/third_party/spdy/platform/api/spdy_mem_slice.h +++ /dev/null
@@ -1,54 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_MEM_SLICE_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_MEM_SLICE_H_ - -#include <utility> - -#include "net/third_party/spdy/platform/api/spdy_export.h" -#include "net/third_party/spdy/platform/impl/spdy_mem_slice_impl.h" - -namespace spdy { - -// SpdyMemSlice is an internally reference counted data buffer used as the -// source buffers for write operations. SpdyMemSlice implicitly maintains a -// reference count and will free the underlying data buffer when the reference -// count reaches zero. -class SPDY_EXPORT_PRIVATE SpdyMemSlice { - public: - // Constructs an empty SpdyMemSlice with no underlying data and 0 reference - // count. - SpdyMemSlice() = default; - - // Constructs a SpdyMemSlice with reference count 1 to a newly allocated data - // buffer of |length| bytes. - explicit SpdyMemSlice(size_t length) : impl_(length) {} - - // Constructs a SpdyMemSlice from |impl|. It takes the reference away from - // |impl|. - explicit SpdyMemSlice(SpdyMemSliceImpl impl) : impl_(std::move(impl)) {} - - SpdyMemSlice(const SpdyMemSlice& other) = delete; - SpdyMemSlice& operator=(const SpdyMemSlice& other) = delete; - - // Move constructors. |other| will not hold a reference to the data buffer - // after this call completes. - SpdyMemSlice(SpdyMemSlice&& other) = default; - SpdyMemSlice& operator=(SpdyMemSlice&& other) = default; - - ~SpdyMemSlice() = default; - - // Returns a char pointer to underlying data buffer. - const char* data() const { return impl_.data(); } - // Returns the length of underlying data buffer. - size_t length() const { return impl_.length(); } - - private: - SpdyMemSliceImpl impl_; -}; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_MEM_SLICE_H_
diff --git a/net/third_party/spdy/platform/api/spdy_mem_slice_test.cc b/net/third_party/spdy/platform/api/spdy_mem_slice_test.cc deleted file mode 100644 index a49a59c..0000000 --- a/net/third_party/spdy/platform/api/spdy_mem_slice_test.cc +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/platform/api/spdy_mem_slice.h" - -#include <utility> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { -namespace test { -namespace { - -class SpdyMemSliceTest : public ::testing::Test { - public: - SpdyMemSliceTest() { - slice_ = SpdyMemSlice(1024); - orig_data_ = slice_.data(); - orig_length_ = slice_.length(); - } - - SpdyMemSlice slice_; - const char* orig_data_; - size_t orig_length_; -}; - -TEST_F(SpdyMemSliceTest, MoveConstruct) { - SpdyMemSlice moved(std::move(slice_)); - EXPECT_EQ(moved.data(), orig_data_); - EXPECT_EQ(moved.length(), orig_length_); - EXPECT_EQ(nullptr, slice_.data()); - EXPECT_EQ(0u, slice_.length()); -} - -TEST_F(SpdyMemSliceTest, MoveAssign) { - SpdyMemSlice moved; - moved = std::move(slice_); - EXPECT_EQ(moved.data(), orig_data_); - EXPECT_EQ(moved.length(), orig_length_); - EXPECT_EQ(nullptr, slice_.data()); - EXPECT_EQ(0u, slice_.length()); -} - -} // namespace -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/platform/api/spdy_ptr_util.h b/net/third_party/spdy/platform/api/spdy_ptr_util.h deleted file mode 100644 index 74af930..0000000 --- a/net/third_party/spdy/platform/api/spdy_ptr_util.h +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_PTR_UTIL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_PTR_UTIL_H_ - -#include <memory> -#include <utility> - -#include "net/third_party/spdy/platform/impl/spdy_ptr_util_impl.h" - -namespace spdy { - -template <typename T, typename... Args> -std::unique_ptr<T> SpdyMakeUnique(Args&&... args) { - return SpdyMakeUniqueImpl<T>(std::forward<Args>(args)...); -} - -template <typename T> -std::unique_ptr<T> SpdyWrapUnique(T* ptr) { - return SpdyWrapUniqueImpl<T>(ptr); -} - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_PTR_UTIL_H_
diff --git a/net/third_party/spdy/platform/api/spdy_string.h b/net/third_party/spdy/platform/api/spdy_string.h deleted file mode 100644 index 99e6f29..0000000 --- a/net/third_party/spdy/platform/api/spdy_string.h +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_STRING_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_STRING_H_ - -#include "net/third_party/spdy/platform/impl/spdy_string_impl.h" - -namespace spdy { - -using SpdyString = SpdyStringImpl; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_STRING_H_
diff --git a/net/third_party/spdy/platform/api/spdy_string_piece.h b/net/third_party/spdy/platform/api/spdy_string_piece.h deleted file mode 100644 index 9a6b6db..0000000 --- a/net/third_party/spdy/platform/api/spdy_string_piece.h +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_STRING_PIECE_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_STRING_PIECE_H_ - -#include "net/third_party/spdy/platform/impl/spdy_string_piece_impl.h" - -namespace spdy { - -using SpdyStringPiece = SpdyStringPieceImpl; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_STRING_PIECE_H_
diff --git a/net/third_party/spdy/platform/api/spdy_string_utils.h b/net/third_party/spdy/platform/api/spdy_string_utils.h deleted file mode 100644 index f8fd0ca0..0000000 --- a/net/third_party/spdy/platform/api/spdy_string_utils.h +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_STRING_UTILS_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_STRING_UTILS_H_ - -#include <utility> - -// The following header file has to be included from at least -// non-test file in order to avoid strange linking errors. -// TODO(bnc): Remove this include as soon as it is included elsewhere in -// non-test code. -#include "net/third_party/spdy/platform/api/spdy_mem_slice.h" - -#include "net/third_party/spdy/platform/api/spdy_string.h" -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" -#include "net/third_party/spdy/platform/impl/spdy_string_utils_impl.h" - -namespace spdy { - -template <typename... Args> -inline SpdyString SpdyStrCat(const Args&... args) { - return SpdyStrCatImpl(std::forward<const Args&>(args)...); -} - -template <typename... Args> -inline void SpdyStrAppend(SpdyString* output, const Args&... args) { - SpdyStrAppendImpl(output, std::forward<const Args&>(args)...); -} - -inline char SpdyHexDigitToInt(char c) { - return SpdyHexDigitToIntImpl(c); -} - -inline SpdyString SpdyHexDecode(SpdyStringPiece data) { - return SpdyHexDecodeImpl(data); -} - -inline bool SpdyHexDecodeToUInt32(SpdyStringPiece data, uint32_t* out) { - return SpdyHexDecodeToUInt32Impl(data, out); -} - -inline SpdyString SpdyHexEncode(const char* bytes, size_t size) { - return SpdyHexEncodeImpl(bytes, size); -} - -inline SpdyString SpdyHexEncodeUInt32AndTrim(uint32_t data) { - return SpdyHexEncodeUInt32AndTrimImpl(data); -} - -inline SpdyString SpdyHexDump(SpdyStringPiece data) { - return SpdyHexDumpImpl(data); -} - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_STRING_UTILS_H_
diff --git a/net/third_party/spdy/platform/api/spdy_string_utils_test.cc b/net/third_party/spdy/platform/api/spdy_string_utils_test.cc deleted file mode 100644 index 62ca20f..0000000 --- a/net/third_party/spdy/platform/api/spdy_string_utils_test.cc +++ /dev/null
@@ -1,242 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/spdy/platform/api/spdy_string_utils.h" - -#include <cstdint> - -#include "net/third_party/spdy/platform/api/spdy_string_piece.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace spdy { -namespace test { -namespace { - -TEST(SpdyStringUtilsTest, SpdyStrCat) { - // No arguments. - EXPECT_EQ("", SpdyStrCat()); - - // Single string-like argument. - const char kFoo[] = "foo"; - const SpdyString string_foo(kFoo); - const SpdyStringPiece stringpiece_foo(string_foo); - EXPECT_EQ("foo", SpdyStrCat(kFoo)); - EXPECT_EQ("foo", SpdyStrCat(string_foo)); - EXPECT_EQ("foo", SpdyStrCat(stringpiece_foo)); - - // Two string-like arguments. - const char kBar[] = "bar"; - const SpdyStringPiece stringpiece_bar(kBar); - const SpdyString string_bar(kBar); - EXPECT_EQ("foobar", SpdyStrCat(kFoo, kBar)); - EXPECT_EQ("foobar", SpdyStrCat(kFoo, string_bar)); - EXPECT_EQ("foobar", SpdyStrCat(kFoo, stringpiece_bar)); - EXPECT_EQ("foobar", SpdyStrCat(string_foo, kBar)); - EXPECT_EQ("foobar", SpdyStrCat(string_foo, string_bar)); - EXPECT_EQ("foobar", SpdyStrCat(string_foo, stringpiece_bar)); - EXPECT_EQ("foobar", SpdyStrCat(stringpiece_foo, kBar)); - EXPECT_EQ("foobar", SpdyStrCat(stringpiece_foo, string_bar)); - EXPECT_EQ("foobar", SpdyStrCat(stringpiece_foo, stringpiece_bar)); - - // Many-many arguments. - EXPECT_EQ( - "foobarbazquxquuxquuzcorgegraultgarplywaldofredplughxyzzythud", - SpdyStrCat("foo", "bar", "baz", "qux", "quux", "quuz", "corge", "grault", - "garply", "waldo", "fred", "plugh", "xyzzy", "thud")); - - // Numerical arguments. - const int16_t i = 1; - const uint64_t u = 8; - const double d = 3.1415; - - EXPECT_EQ("1 8", SpdyStrCat(i, " ", u)); - EXPECT_EQ("3.14151181", SpdyStrCat(d, i, i, u, i)); - EXPECT_EQ("i: 1, u: 8, d: 3.1415", - SpdyStrCat("i: ", i, ", u: ", u, ", d: ", d)); - - // Boolean arguments. - const bool t = true; - const bool f = false; - - EXPECT_EQ("1", SpdyStrCat(t)); - EXPECT_EQ("0", SpdyStrCat(f)); - EXPECT_EQ("0110", SpdyStrCat(f, t, t, f)); - - // Mixed string-like, numerical, and Boolean arguments. - EXPECT_EQ("foo1foo081bar3.14151", - SpdyStrCat(kFoo, i, string_foo, f, u, t, stringpiece_bar, d, t)); - EXPECT_EQ("3.141511bar18bar13.14150", - SpdyStrCat(d, t, t, string_bar, i, u, kBar, t, d, f)); -} - -TEST(SpdyStringUtilsTest, SpdyStrAppend) { - // No arguments on empty string. - SpdyString output; - SpdyStrAppend(&output); - EXPECT_TRUE(output.empty()); - - // Single string-like argument. - const char kFoo[] = "foo"; - const SpdyString string_foo(kFoo); - const SpdyStringPiece stringpiece_foo(string_foo); - SpdyStrAppend(&output, kFoo); - EXPECT_EQ("foo", output); - SpdyStrAppend(&output, string_foo); - EXPECT_EQ("foofoo", output); - SpdyStrAppend(&output, stringpiece_foo); - EXPECT_EQ("foofoofoo", output); - - // No arguments on non-empty string. - SpdyStrAppend(&output); - EXPECT_EQ("foofoofoo", output); - - output.clear(); - - // Two string-like arguments. - const char kBar[] = "bar"; - const SpdyStringPiece stringpiece_bar(kBar); - const SpdyString string_bar(kBar); - SpdyStrAppend(&output, kFoo, kBar); - EXPECT_EQ("foobar", output); - SpdyStrAppend(&output, kFoo, string_bar); - EXPECT_EQ("foobarfoobar", output); - SpdyStrAppend(&output, kFoo, stringpiece_bar); - EXPECT_EQ("foobarfoobarfoobar", output); - SpdyStrAppend(&output, string_foo, kBar); - EXPECT_EQ("foobarfoobarfoobarfoobar", output); - - output.clear(); - - SpdyStrAppend(&output, string_foo, string_bar); - EXPECT_EQ("foobar", output); - SpdyStrAppend(&output, string_foo, stringpiece_bar); - EXPECT_EQ("foobarfoobar", output); - SpdyStrAppend(&output, stringpiece_foo, kBar); - EXPECT_EQ("foobarfoobarfoobar", output); - SpdyStrAppend(&output, stringpiece_foo, string_bar); - EXPECT_EQ("foobarfoobarfoobarfoobar", output); - - output.clear(); - - SpdyStrAppend(&output, stringpiece_foo, stringpiece_bar); - EXPECT_EQ("foobar", output); - - // Many-many arguments. - SpdyStrAppend(&output, "foo", "bar", "baz", "qux", "quux", "quuz", "corge", - "grault", "garply", "waldo", "fred", "plugh", "xyzzy", "thud"); - EXPECT_EQ( - "foobarfoobarbazquxquuxquuzcorgegraultgarplywaldofredplughxyzzythud", - output); - - output.clear(); - - // Numerical arguments. - const int16_t i = 1; - const uint64_t u = 8; - const double d = 3.1415; - - SpdyStrAppend(&output, i, " ", u); - EXPECT_EQ("1 8", output); - SpdyStrAppend(&output, d, i, i, u, i); - EXPECT_EQ("1 83.14151181", output); - SpdyStrAppend(&output, "i: ", i, ", u: ", u, ", d: ", d); - EXPECT_EQ("1 83.14151181i: 1, u: 8, d: 3.1415", output); - - output.clear(); - - // Boolean arguments. - const bool t = true; - const bool f = false; - - SpdyStrAppend(&output, t); - EXPECT_EQ("1", output); - SpdyStrAppend(&output, f); - EXPECT_EQ("10", output); - SpdyStrAppend(&output, f, t, t, f); - EXPECT_EQ("100110", output); - - output.clear(); - - // Mixed string-like, numerical, and Boolean arguments. - SpdyStrAppend(&output, kFoo, i, string_foo, f, u, t, stringpiece_bar, d, t); - EXPECT_EQ("foo1foo081bar3.14151", output); - SpdyStrAppend(&output, d, t, t, string_bar, i, u, kBar, t, d, f); - EXPECT_EQ("foo1foo081bar3.141513.141511bar18bar13.14150", output); -} - -TEST(SpdyStringUtilsTest, SpdyHexDigitToInt) { - EXPECT_EQ(0, SpdyHexDigitToInt('0')); - EXPECT_EQ(1, SpdyHexDigitToInt('1')); - EXPECT_EQ(2, SpdyHexDigitToInt('2')); - EXPECT_EQ(3, SpdyHexDigitToInt('3')); - EXPECT_EQ(4, SpdyHexDigitToInt('4')); - EXPECT_EQ(5, SpdyHexDigitToInt('5')); - EXPECT_EQ(6, SpdyHexDigitToInt('6')); - EXPECT_EQ(7, SpdyHexDigitToInt('7')); - EXPECT_EQ(8, SpdyHexDigitToInt('8')); - EXPECT_EQ(9, SpdyHexDigitToInt('9')); - - EXPECT_EQ(10, SpdyHexDigitToInt('a')); - EXPECT_EQ(11, SpdyHexDigitToInt('b')); - EXPECT_EQ(12, SpdyHexDigitToInt('c')); - EXPECT_EQ(13, SpdyHexDigitToInt('d')); - EXPECT_EQ(14, SpdyHexDigitToInt('e')); - EXPECT_EQ(15, SpdyHexDigitToInt('f')); - - EXPECT_EQ(10, SpdyHexDigitToInt('A')); - EXPECT_EQ(11, SpdyHexDigitToInt('B')); - EXPECT_EQ(12, SpdyHexDigitToInt('C')); - EXPECT_EQ(13, SpdyHexDigitToInt('D')); - EXPECT_EQ(14, SpdyHexDigitToInt('E')); - EXPECT_EQ(15, SpdyHexDigitToInt('F')); -} - -TEST(SpdyStringUtilsTest, SpdyHexDecodeToUInt32) { - uint32_t out; - EXPECT_TRUE(SpdyHexDecodeToUInt32("0", &out)); - EXPECT_EQ(0u, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("00", &out)); - EXPECT_EQ(0u, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("0000000", &out)); - EXPECT_EQ(0u, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("00000000", &out)); - EXPECT_EQ(0u, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("1", &out)); - EXPECT_EQ(1u, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("ffffFFF", &out)); - EXPECT_EQ(0xFFFFFFFu, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("fFfFffFf", &out)); - EXPECT_EQ(0xFFFFFFFFu, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("01AEF", &out)); - EXPECT_EQ(0x1AEFu, out); - EXPECT_TRUE(SpdyHexDecodeToUInt32("abcde", &out)); - EXPECT_EQ(0xABCDEu, out); - - EXPECT_FALSE(SpdyHexDecodeToUInt32("", &out)); - EXPECT_FALSE(SpdyHexDecodeToUInt32("111111111", &out)); - EXPECT_FALSE(SpdyHexDecodeToUInt32("1111111111", &out)); - EXPECT_FALSE(SpdyHexDecodeToUInt32("0x1111", &out)); -} - -TEST(SpdyStringUtilsTest, SpdyHexEncode) { - unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81}; - EXPECT_EQ("01ff02fe038081", - SpdyHexEncode(reinterpret_cast<char*>(bytes), sizeof(bytes))); -} - -TEST(SpdyStringUtilsTest, SpdyHexEncodeUInt32AndTrim) { - EXPECT_EQ("0", SpdyHexEncodeUInt32AndTrim(0)); - EXPECT_EQ("1", SpdyHexEncodeUInt32AndTrim(1)); - EXPECT_EQ("a", SpdyHexEncodeUInt32AndTrim(0xA)); - EXPECT_EQ("f", SpdyHexEncodeUInt32AndTrim(0xF)); - EXPECT_EQ("a9", SpdyHexEncodeUInt32AndTrim(0xA9)); - EXPECT_EQ("9abcdef", SpdyHexEncodeUInt32AndTrim(0x9ABCDEF)); - EXPECT_EQ("12345678", SpdyHexEncodeUInt32AndTrim(0x12345678)); - EXPECT_EQ("ffffffff", SpdyHexEncodeUInt32AndTrim(0xFFFFFFFF)); - EXPECT_EQ("10000001", SpdyHexEncodeUInt32AndTrim(0x10000001)); -} - -} // namespace -} // namespace test -} // namespace spdy
diff --git a/net/third_party/spdy/platform/api/spdy_test_helpers.h b/net/third_party/spdy/platform/api/spdy_test_helpers.h deleted file mode 100644 index b8f873b..0000000 --- a/net/third_party/spdy/platform/api/spdy_test_helpers.h +++ /dev/null
@@ -1,12 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_TEST_HELPERS_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_TEST_HELPERS_H_ - -#include "net/third_party/spdy/platform/impl/spdy_test_helpers_impl.h" - -#define EXPECT_SPDY_BUG EXPECT_SPDY_BUG_IMPL - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_TEST_HELPERS_H_
diff --git a/net/third_party/spdy/platform/api/spdy_test_utils_prod.h b/net/third_party/spdy/platform/api/spdy_test_utils_prod.h deleted file mode 100644 index 509b223..0000000 --- a/net/third_party/spdy/platform/api/spdy_test_utils_prod.h +++ /dev/null
@@ -1,12 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_TEST_UTILS_PROD_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_TEST_UTILS_PROD_H_ - -#include "net/third_party/spdy/platform/impl/spdy_test_utils_prod_impl.h" - -#define SPDY_FRIEND_TEST SPDY_FRIEND_TEST_IMPL - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_TEST_UTILS_PROD_H_
diff --git a/net/third_party/spdy/platform/api/spdy_unsafe_arena.h b/net/third_party/spdy/platform/api/spdy_unsafe_arena.h deleted file mode 100644 index a692d8b..0000000 --- a/net/third_party/spdy/platform/api/spdy_unsafe_arena.h +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_UNSAFE_ARENA_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_UNSAFE_ARENA_H_ - -#include "net/third_party/spdy/platform/impl/spdy_unsafe_arena_impl.h" - -namespace spdy { - -using SpdyUnsafeArena = SpdyUnsafeArenaImpl; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_API_SPDY_UNSAFE_ARENA_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_arraysize_impl.h b/net/third_party/spdy/platform/impl/spdy_arraysize_impl.h deleted file mode 100644 index be268e5..0000000 --- a/net/third_party/spdy/platform/impl/spdy_arraysize_impl.h +++ /dev/null
@@ -1,12 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_ARRAYSIZE_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_ARRAYSIZE_IMPL_H_ - -#include "base/stl_util.h" - -#define SPDY_ARRAYSIZE_IMPL(x) base::size(x) - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_ARRAYSIZE_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_export_impl.h b/net/third_party/spdy/platform/impl/spdy_export_impl.h deleted file mode 100644 index f933e968..0000000 --- a/net/third_party/spdy/platform/impl/spdy_export_impl.h +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_EXPORT_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_EXPORT_IMPL_H_ - -#include "net/base/net_export.h" - -#define SPDY_EXPORT NET_EXPORT -#define SPDY_EXPORT_PRIVATE NET_EXPORT_PRIVATE - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_EXPORT_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_string_impl.h b/net/third_party/spdy/platform/impl/spdy_string_impl.h deleted file mode 100644 index b262475..0000000 --- a/net/third_party/spdy/platform/impl/spdy_string_impl.h +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_STRING_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_STRING_IMPL_H_ - -#include <string> - -namespace spdy { - -using SpdyStringImpl = std::string; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_STRING_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_string_piece_impl.h b/net/third_party/spdy/platform/impl/spdy_string_piece_impl.h deleted file mode 100644 index 847e625..0000000 --- a/net/third_party/spdy/platform/impl/spdy_string_piece_impl.h +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_STRING_PIECE_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_STRING_PIECE_IMPL_H_ - -#include "base/strings/string_piece.h" - -namespace spdy { - -using SpdyStringPieceImpl = base::StringPiece; - -} // namespace spdy - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_STRING_PIECE_IMPL_H_
diff --git a/net/third_party/spdy/platform/impl/spdy_test_utils_prod_impl.h b/net/third_party/spdy/platform/impl/spdy_test_utils_prod_impl.h deleted file mode 100644 index 77d89b1..0000000 --- a/net/third_party/spdy/platform/impl/spdy_test_utils_prod_impl.h +++ /dev/null
@@ -1,12 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_TEST_UTILS_PROD_IMPL_H_ -#define NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_TEST_UTILS_PROD_IMPL_H_ - -#include "base/gtest_prod_util.h" - -#define SPDY_FRIEND_TEST_IMPL FRIEND_TEST_ALL_PREFIXES - -#endif // NET_THIRD_PARTY_SPDY_PLATFORM_IMPL_SPDY_TEST_UTILS_PROD_IMPL_H_
diff --git a/net/tools/quic/quic_client_message_loop_network_helper.cc b/net/tools/quic/quic_client_message_loop_network_helper.cc index 995ad4f7..41026fa 100644 --- a/net/tools/quic/quic_client_message_loop_network_helper.cc +++ b/net/tools/quic/quic_client_message_loop_network_helper.cc
@@ -27,7 +27,7 @@ #include "net/third_party/quic/core/quic_server_id.h" #include "net/third_party/quic/platform/api/quic_flags.h" #include "net/third_party/quic/platform/api/quic_ptr_util.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" using std::string;
diff --git a/net/tools/quic/quic_http_proxy_backend_stream.h b/net/tools/quic/quic_http_proxy_backend_stream.h index a231433..a64a1cc3 100644 --- a/net/tools/quic/quic_http_proxy_backend_stream.h +++ b/net/tools/quic/quic_http_proxy_backend_stream.h
@@ -32,7 +32,7 @@ #include "net/third_party/quic/tools/quic_backend_response.h" #include "net/third_party/quic/tools/quic_simple_server_backend.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/tools/quic/quic_http_proxy_backend.h" namespace base {
diff --git a/net/tools/quic/quic_http_proxy_backend_stream_test.cc b/net/tools/quic/quic_http_proxy_backend_stream_test.cc index 2a08c31..b0e4372 100644 --- a/net/tools/quic/quic_http_proxy_backend_stream_test.cc +++ b/net/tools/quic/quic_http_proxy_backend_stream_test.cc
@@ -16,6 +16,7 @@ #include "net/test/embedded_test_server/request_handler_util.h" #include "net/third_party/quic/core/quic_connection_id.h" #include "net/third_party/quic/platform/api/quic_test.h" +#include "net/third_party/quic/test_tools/quic_test_utils.h" #include "net/third_party/quic/tools/quic_backend_response.h" #include "net/tools/quic/quic_http_proxy_backend.h" @@ -120,7 +121,7 @@ } quic::QuicConnectionId connection_id() const override { - return quic::QuicConnectionIdFromUInt64(123); + return quic::test::TestConnectionId(123); } quic::QuicStreamId stream_id() const override { return 5; } std::string peer_host() const override { return "127.0.0.1"; }
diff --git a/net/tools/quic/quic_http_proxy_backend_test.cc b/net/tools/quic/quic_http_proxy_backend_test.cc index 069373c..691f304b 100644 --- a/net/tools/quic/quic_http_proxy_backend_test.cc +++ b/net/tools/quic/quic_http_proxy_backend_test.cc
@@ -9,6 +9,7 @@ #include "net/base/url_util.h" #include "net/third_party/quic/core/quic_connection_id.h" #include "net/third_party/quic/platform/api/quic_test.h" +#include "net/third_party/quic/test_tools/quic_test_utils.h" #include "net/tools/quic/quic_http_proxy_backend.h" #include "net/tools/quic/quic_http_proxy_backend_stream.h" @@ -24,7 +25,7 @@ ~TestQuicServerStream() override {} quic::QuicConnectionId connection_id() const override { - return quic::QuicConnectionIdFromUInt64(123); + return quic::test::TestConnectionId(123); }; quic::QuicStreamId stream_id() const override { return 5; }; std::string peer_host() const override { return "127.0.0.1"; };
diff --git a/net/tools/quic/quic_simple_client.cc b/net/tools/quic/quic_simple_client.cc index 40f2f8d9..63aa430 100644 --- a/net/tools/quic/quic_simple_client.cc +++ b/net/tools/quic/quic_simple_client.cc
@@ -27,7 +27,7 @@ #include "net/third_party/quic/core/quic_server_id.h" #include "net/third_party/quic/platform/api/quic_flags.h" #include "net/third_party/quic/platform/api/quic_ptr_util.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" using std::string;
diff --git a/net/tools/quic/quic_simple_client_bin.cc b/net/tools/quic/quic_simple_client_bin.cc index 956b612e..2957aed 100644 --- a/net/tools/quic/quic_simple_client_bin.cc +++ b/net/tools/quic/quic_simple_client_bin.cc
@@ -61,7 +61,7 @@ #include "net/third_party/quic/platform/api/quic_str_cat.h" #include "net/third_party/quic/platform/api/quic_string_piece.h" #include "net/third_party/quic/platform/api/quic_text_utils.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/tools/quic/quic_simple_client.h" #include "net/tools/quic/synchronous_host_resolver.h" #include "url/gurl.h"
diff --git a/net/tools/quic/quic_simple_server_session_helper.cc b/net/tools/quic/quic_simple_server_session_helper.cc index eaef69b..cb35d10 100644 --- a/net/tools/quic/quic_simple_server_session_helper.cc +++ b/net/tools/quic/quic_simple_server_session_helper.cc
@@ -4,6 +4,7 @@ #include "net/tools/quic/quic_simple_server_session_helper.h" #include "net/third_party/quic/core/quic_connection_id.h" +#include "net/third_party/quic/core/quic_utils.h" namespace net { @@ -16,7 +17,7 @@ quic::QuicConnectionId QuicSimpleServerSessionHelper::GenerateConnectionIdForReject( quic::QuicConnectionId /*connection_id*/) const { - return quic::QuicConnectionIdFromUInt64(random_->RandUint64()); + return quic::QuicUtils::CreateRandomConnectionId(random_); } bool QuicSimpleServerSessionHelper::CanAcceptClientHello(
diff --git a/net/tools/quic/quic_simple_server_session_helper_test.cc b/net/tools/quic/quic_simple_server_session_helper_test.cc index 7bf103f..a9c8e16 100644 --- a/net/tools/quic/quic_simple_server_session_helper_test.cc +++ b/net/tools/quic/quic_simple_server_session_helper_test.cc
@@ -3,7 +3,9 @@ // found in the LICENSE file. #include "net/third_party/quic/core/quic_connection_id.h" +#include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/test_tools/mock_random.h" +#include "net/third_party/quic/test_tools/quic_test_utils.h" #include "net/third_party/quic/tools/quic_simple_crypto_server_stream_helper.h" #include "testing/gtest/include/gtest/gtest.h" @@ -14,9 +16,9 @@ quic::test::MockRandom random; quic::QuicSimpleCryptoServerStreamHelper helper(&random); - EXPECT_EQ(quic::QuicConnectionIdFromUInt64(random.RandUint64()), - helper.GenerateConnectionIdForReject( - quic::QuicConnectionIdFromUInt64(42))); + EXPECT_EQ( + quic::QuicUtils::CreateRandomConnectionId(&random), + helper.GenerateConnectionIdForReject(quic::test::TestConnectionId(42))); } } // namespace net
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc index f217c09..c161b7e3 100644 --- a/net/url_request/url_request_test_util.cc +++ b/net/url_request/url_request_test_util.cc
@@ -136,6 +136,10 @@ session_context.http_server_properties = http_server_properties(); session_context.net_log = net_log(); session_context.channel_id_service = channel_id_service(); +#if BUILDFLAG(ENABLE_REPORTING) + session_context.network_error_logging_service = + network_error_logging_service(); +#endif // BUILDFLAG(ENABLE_REPORTING) context_storage_.set_http_network_session( std::make_unique<HttpNetworkSession>(session_params, session_context)); context_storage_.set_http_transaction_factory(std::make_unique<HttpCache>(
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index a31f9fd..6f7b73b 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -150,6 +150,7 @@ #if BUILDFLAG(ENABLE_REPORTING) #include "net/network_error_logging/network_error_logging_service.h" +#include "net/network_error_logging/network_error_logging_test_util.h" #endif // BUILDFLAG(ENABLE_REPORTING) #if defined(OS_ANDROID) || defined(USE_BUILTIN_CERT_VERIFIER) @@ -7050,6 +7051,151 @@ #endif // !defined(OS_IOS) +#if BUILDFLAG(ENABLE_REPORTING) + +TEST_F(URLRequestTestHTTP, NetworkErrorLogging_BasicSuccess) { + EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_test_server.ServeFilesFromSourceDirectory( + base::FilePath(kTestFilePath)); + ASSERT_TRUE(https_test_server.Start()); + GURL request_url = https_test_server.GetURL("/simple.html"); + + TestNetworkErrorLoggingService nel_service; + TestURLRequestContext context(true); + context.set_network_error_logging_service(&nel_service); + context.Init(); + + TestDelegate d; + std::unique_ptr<URLRequest> request(context.CreateRequest( + request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); + request->Start(); + d.RunUntilComplete(); + + ASSERT_EQ(1u, nel_service.errors().size()); + const TestNetworkErrorLoggingService::RequestDetails& error = + nel_service.errors()[0]; + EXPECT_EQ(request_url, error.uri); + EXPECT_EQ(200, error.status_code); + EXPECT_EQ(OK, error.type); +} + +TEST_F(URLRequestTestHTTP, NetworkErrorLogging_BasicError) { + EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_test_server.AddDefaultHandlers(base::FilePath(kTestFilePath)); + ASSERT_TRUE(https_test_server.Start()); + GURL request_url = https_test_server.GetURL("/close-socket"); + + TestNetworkErrorLoggingService nel_service; + TestURLRequestContext context(true); + context.set_network_error_logging_service(&nel_service); + context.Init(); + + TestDelegate d; + std::unique_ptr<URLRequest> request(context.CreateRequest( + request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); + request->Start(); + d.RunUntilComplete(); + + ASSERT_EQ(1u, nel_service.errors().size()); + const TestNetworkErrorLoggingService::RequestDetails& error = + nel_service.errors()[0]; + EXPECT_EQ(request_url, error.uri); + EXPECT_EQ(0, error.status_code); + EXPECT_EQ(ERR_EMPTY_RESPONSE, error.type); +} + +TEST_F(URLRequestTestHTTP, NetworkErrorLogging_Redirect) { + EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_test_server.ServeFilesFromSourceDirectory( + base::FilePath(kTestFilePath)); + ASSERT_TRUE(https_test_server.Start()); + GURL request_url = https_test_server.GetURL("/redirect-test.html"); + GURL redirect_url = https_test_server.GetURL("/with-headers.html"); + + TestNetworkErrorLoggingService nel_service; + TestURLRequestContext context(true); + context.set_network_error_logging_service(&nel_service); + context.Init(); + + TestDelegate d; + std::unique_ptr<URLRequest> request(context.CreateRequest( + request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); + request->Start(); + d.RunUntilComplete(); + + ASSERT_EQ(2u, nel_service.errors().size()); + const TestNetworkErrorLoggingService::RequestDetails& error1 = + nel_service.errors()[0]; + EXPECT_EQ(request_url, error1.uri); + EXPECT_EQ(302, error1.status_code); + EXPECT_EQ(OK, error1.type); + const TestNetworkErrorLoggingService::RequestDetails& error2 = + nel_service.errors()[1]; + EXPECT_EQ(redirect_url, error2.uri); + EXPECT_EQ(200, error2.status_code); + EXPECT_EQ(OK, error2.type); +} + +TEST_F(URLRequestTestHTTP, NetworkErrorLogging_Auth) { + EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_test_server.AddDefaultHandlers(base::FilePath(kTestFilePath)); + ASSERT_TRUE(https_test_server.Start()); + GURL request_url = https_test_server.GetURL("/auth-basic"); + + TestNetworkErrorLoggingService nel_service; + TestURLRequestContext context(true); + context.set_network_error_logging_service(&nel_service); + context.Init(); + + TestDelegate d; + d.set_credentials(AuthCredentials(kUser, kSecret)); + std::unique_ptr<URLRequest> request(context.CreateRequest( + request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); + request->Start(); + d.RunUntilComplete(); + + ASSERT_EQ(2u, nel_service.errors().size()); + const TestNetworkErrorLoggingService::RequestDetails& error1 = + nel_service.errors()[0]; + EXPECT_EQ(request_url, error1.uri); + EXPECT_EQ(401, error1.status_code); + EXPECT_EQ(OK, error1.type); + const TestNetworkErrorLoggingService::RequestDetails& error2 = + nel_service.errors()[1]; + EXPECT_EQ(request_url, error2.uri); + EXPECT_EQ(200, error2.status_code); + EXPECT_EQ(OK, error2.type); +} + +TEST_F(URLRequestTestHTTP, NetworkErrorLogging_Cancel) { + EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_test_server.ServeFilesFromSourceDirectory( + base::FilePath(kTestFilePath)); + ASSERT_TRUE(https_test_server.Start()); + GURL request_url = https_test_server.GetURL("/simple.html"); + + TestNetworkErrorLoggingService nel_service; + TestURLRequestContext context(true); + context.set_network_error_logging_service(&nel_service); + context.Init(); + + TestDelegate d; + d.set_cancel_in_response_started(true); + std::unique_ptr<URLRequest> request(context.CreateRequest( + request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); + request->Start(); + d.RunUntilComplete(); + + ASSERT_EQ(1u, nel_service.errors().size()); + const TestNetworkErrorLoggingService::RequestDetails& error = + nel_service.errors()[0]; + EXPECT_EQ(request_url, error.uri); + EXPECT_EQ(200, error.status_code); + EXPECT_EQ(OK, error.type); +} + +#endif // BUILDFLAG(ENABLE_REPORTING) + TEST_F(URLRequestTestHTTP, ContentTypeNormalizationTest) { ASSERT_TRUE(http_test_server()->Start());
diff --git a/net/websockets/websocket_http2_handshake_stream.h b/net/websockets/websocket_http2_handshake_stream.h index cef1642..968b127 100644 --- a/net/websockets/websocket_http2_handshake_stream.h +++ b/net/websockets/websocket_http2_handshake_stream.h
@@ -18,7 +18,7 @@ #include "net/base/net_export.h" #include "net/base/request_priority.h" #include "net/log/net_log_with_source.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/websockets/websocket_basic_stream_adapters.h" #include "net/websockets/websocket_handshake_stream_base.h" #include "net/websockets/websocket_stream.h"
diff --git a/net/websockets/websocket_stream_test.cc b/net/websockets/websocket_stream_test.cc index ea98e67c..88f051f 100644 --- a/net/websockets/websocket_stream_test.cc +++ b/net/websockets/websocket_stream_test.cc
@@ -32,7 +32,7 @@ #include "net/test/cert_test_util.h" #include "net/test/gtest_util.h" #include "net/test/test_data_directory.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/url_request/url_request_test_util.h" #include "net/websockets/websocket_basic_handshake_stream.h" #include "net/websockets/websocket_frame.h"
diff --git a/net/websockets/websocket_test_util.cc b/net/websockets/websocket_test_util.cc index be5706e..fafb944 100644 --- a/net/websockets/websocket_test_util.cc +++ b/net/websockets/websocket_test_util.cc
@@ -14,7 +14,7 @@ #include "net/http/http_network_session.h" #include "net/proxy_resolution/proxy_resolution_service.h" #include "net/socket/socket_test_util.h" -#include "net/third_party/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/websockets/websocket_basic_handshake_stream.h" #include "url/origin.h"
diff --git a/net/websockets/websocket_test_util.h b/net/websockets/websocket_test_util.h index ef42219..4ab42ee 100644 --- a/net/websockets/websocket_test_util.h +++ b/net/websockets/websocket_test_util.h
@@ -17,7 +17,7 @@ #include "net/http/http_request_headers.h" #include "net/http/http_stream_parser.h" #include "net/socket/client_socket_handle.h" -#include "net/third_party/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/url_request_test_util.h" #include "net/websockets/websocket_handshake_stream_create_helper.h"
diff --git a/printing/BUILD.gn b/printing/BUILD.gn index 83d6eec..cd69105 100644 --- a/printing/BUILD.gn +++ b/printing/BUILD.gn
@@ -222,6 +222,7 @@ ] } else if (is_android) { sources += [ + "printed_document_android.cc", "printing_context_android.cc", "printing_context_android.h", ]
diff --git a/printing/printed_document.cc b/printing/printed_document.cc index 78efcb9..f1f61fd 100644 --- a/printing/printed_document.cc +++ b/printing/printed_document.cc
@@ -304,12 +304,4 @@ PrintedDocument::Immutable::~Immutable() = default; -#if defined(OS_ANDROID) -// This function is not used on android. -bool PrintedDocument::RenderPrintedDocument(PrintingContext* context) { - NOTREACHED(); - return false; -} -#endif - } // namespace printing
diff --git a/printing/printed_document_android.cc b/printing/printed_document_android.cc new file mode 100644 index 0000000..bf502183 --- /dev/null +++ b/printing/printed_document_android.cc
@@ -0,0 +1,26 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "printing/printed_document.h" + +#include "base/logging.h" +#include "printing/printing_context_android.h" + +namespace printing { + +bool PrintedDocument::RenderPrintedDocument(PrintingContext* context) { + DCHECK(context); + + if (context->NewPage() != PrintingContext::OK) + return false; + { + base::AutoLock lock(lock_); + const MetafilePlayer* metafile = GetMetafile(); + DCHECK(metafile); + static_cast<PrintingContextAndroid*>(context)->PrintDocument(*metafile); + } + return context->PageDone() == PrintingContext::OK; +} + +} // namespace printing
diff --git a/printing/printing_context_android.cc b/printing/printing_context_android.cc index 81e59c069..816b47f 100644 --- a/printing/printing_context_android.cc +++ b/printing/printing_context_android.cc
@@ -11,6 +11,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" +#include "base/files/file.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" @@ -113,8 +114,10 @@ // We use device name variable to store the file descriptor. This is hacky // but necessary. Since device name is not necessary for the upstream // printing code for Android, this is harmless. - int fd = Java_PrintingContext_getFileDescriptor(env, j_printing_context_); - settings_.set_device_name(base::IntToString16(fd)); + // TODO(thestig): See if the call to set_device_name() can be removed. + fd_ = Java_PrintingContext_getFileDescriptor(env, j_printing_context_); + DCHECK(is_file_descriptor_valid()); + settings_.set_device_name(base::IntToString16(fd_)); ScopedJavaLocalRef<jintArray> intArr = Java_PrintingContext_getPages(env, j_printing_context_); @@ -142,6 +145,14 @@ std::move(callback_).Run(CANCEL); } +void PrintingContextAndroid::PrintDocument(const MetafilePlayer& metafile) { + DCHECK(is_file_descriptor_valid()); + + base::File file(fd_); + metafile.SaveTo(&file); + file.TakePlatformFile(); +} + PrintingContext::Result PrintingContextAndroid::UseDefaultSettings() { DCHECK(!in_print_job_);
diff --git a/printing/printing_context_android.h b/printing/printing_context_android.h index 44157a9c..f0c7bd4 100644 --- a/printing/printing_context_android.h +++ b/printing/printing_context_android.h
@@ -13,6 +13,8 @@ namespace printing { +class MetafilePlayer; + // Android subclass of PrintingContext. This class communicates with the // Java side through JNI. class PRINTING_EXPORT PrintingContextAndroid : public PrintingContext { @@ -36,6 +38,9 @@ void ShowSystemDialogDone(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); + // Prints the document contained in |metafile|. + void PrintDocument(const MetafilePlayer& metafile); + // PrintingContext implementation. void AskUserForSettings(int max_pages, bool has_selection, @@ -55,12 +60,17 @@ printing::NativeDrawingContext context() const override; private: + // TODO(thestig): Use |base::kInvalidFd| once available. + bool is_file_descriptor_valid() const { return fd_ > -1; } + base::android::ScopedJavaGlobalRef<jobject> j_printing_context_; // The callback from AskUserForSettings to be called when the settings are // ready on the Java side PrintSettingsCallback callback_; + int fd_ = -1; + DISALLOW_COPY_AND_ASSIGN(PrintingContextAndroid); };
diff --git a/remoting/android/java/AndroidManifest.xml.jinja2 b/remoting/android/java/AndroidManifest.xml.jinja2 index dd89e5a..da6abba 100644 --- a/remoting/android/java/AndroidManifest.xml.jinja2 +++ b/remoting/android/java/AndroidManifest.xml.jinja2
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="{{ APK_PACKAGE_NAME }}"> - <uses-sdk android:minSdkVersion="14" + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-feature android:glEsVersion="0x00020000" android:required="true" />
diff --git a/remoting/android/javatests/AndroidManifest.xml.jinja2 b/remoting/android/javatests/AndroidManifest.xml.jinja2 index e1d14ff..8f76f95 100644 --- a/remoting/android/javatests/AndroidManifest.xml.jinja2 +++ b/remoting/android/javatests/AndroidManifest.xml.jinja2
@@ -11,7 +11,7 @@ <!-- We add an application tag here just so that we can indicate that this package needs to link against the android.test library, which is needed when building test cases. --> - <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /> <application> <uses-library android:name="android.test.runner" />
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc index 9e93163..30ff69b 100644 --- a/remoting/client/chromoting_client.cc +++ b/remoting/client/chromoting_client.cc
@@ -184,11 +184,12 @@ user_interface_->SetDesktopSize(size_pixels, webrtc::DesktopVector(x_dpi, y_dpi)); - mouse_input_scaler_.set_input_size(size_pixels); + mouse_input_scaler_.set_input_size( + webrtc::DesktopRect::MakeSize(size_pixels)); mouse_input_scaler_.set_output_size( connection_->config().protocol() == protocol::SessionConfig::Protocol::ICE - ? size_pixels - : size_dips); + ? webrtc::DesktopRect::MakeSize(size_pixels) + : webrtc::DesktopRect::MakeSize(size_dips)); } void ChromotingClient::InjectClipboardEvent(
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index f454ab5..59a5390 100644 --- a/remoting/client/plugin/chromoting_instance.cc +++ b/remoting/client/plugin/chromoting_instance.cc
@@ -326,7 +326,7 @@ plugin_view_ = view; webrtc::DesktopSize size( webrtc::DesktopSize(view.GetRect().width(), view.GetRect().height())); - mouse_input_filter_.set_input_size(size); + mouse_input_filter_.set_input_size(webrtc::DesktopRect::MakeSize(size)); touch_input_scaler_.set_input_size(size); if (video_renderer_) @@ -503,7 +503,7 @@ const webrtc::DesktopVector& dpi) { DCHECK(!dpi.is_zero()); - mouse_input_filter_.set_output_size(size); + mouse_input_filter_.set_output_size(webrtc::DesktopRect::MakeSize(size)); touch_input_scaler_.set_output_size(size); std::unique_ptr<base::DictionaryValue> data(new base::DictionaryValue()); @@ -738,7 +738,7 @@ if (!plugin_view_.is_null()) { webrtc::DesktopSize size(plugin_view_.GetRect().width(), plugin_view_.GetRect().height()); - mouse_input_filter_.set_input_size(size); + mouse_input_filter_.set_input_size(webrtc::DesktopRect::MakeSize(size)); touch_input_scaler_.set_input_size(size); }
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc index 4e921d36..7c2912e 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc
@@ -246,8 +246,13 @@ // Default to fullscreen if unable to parse id. id = webrtc::kFullDesktopScreenId; } + // Invalid display index defaults to showing all displays. + if (!desktop_display_info_.GetDisplayInfo(id)) { + id = webrtc::kFullDesktopScreenId; + } } video_stream_->SelectSource(id); + show_display_id_ = id; } void ClientSession::OnConnectionAuthenticating() { @@ -264,6 +269,8 @@ is_authenticated_ = true; + desktop_display_info_.Reset(); + if (max_duration_ > base::TimeDelta()) { max_duration_timer_.Start( FROM_HERE, max_duration_, @@ -481,21 +488,31 @@ const webrtc::DesktopSize& size, const webrtc::DesktopVector& dpi) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - mouse_clamping_filter_.set_output_size(size); + webrtc::DesktopVector origin; + if (show_display_id_ != webrtc::kFullDesktopScreenId) { + const DisplayGeometry* display_info = + desktop_display_info_.GetDisplayInfo(show_display_id_); + if (display_info) { + origin.set(display_info->x, display_info->y); + } + } + mouse_clamping_filter_.set_output_size( + webrtc::DesktopRect::MakeOriginSize(origin, size)); switch (connection_->session()->config().protocol()) { case protocol::SessionConfig::Protocol::ICE: - mouse_clamping_filter_.set_input_size(size); + mouse_clamping_filter_.set_input_size( + webrtc::DesktopRect::MakeSize(size)); break; case protocol::SessionConfig::Protocol::WEBRTC: { // When using WebRTC protocol the client sends mouse coordinates in DIPs, // while InputInjector expects them in physical pixels. // TODO(sergeyu): Fix InputInjector implementations to use DIPs as well. - webrtc::DesktopSize size_dips(size.width() * kDefaultDpi / dpi.x(), - size.height() * kDefaultDpi / dpi.y()); - mouse_clamping_filter_.set_input_size(size_dips); + webrtc::DesktopSize size_dips = + DesktopDisplayInfo::CalcSizeDips(size, dpi.x(), dpi.y()); + mouse_clamping_filter_.set_input_size( + webrtc::DesktopRect::MakeSize(size_dips)); // Generate and send VideoLayout message. protocol::VideoLayout layout; @@ -547,10 +564,9 @@ // Calc desktop scaled geometry (in DIPs) // See comment in OnVideoSizeChanged() for details. - int scaled_width = (max_x - min_x) * kDefaultDpi / dpi_x; - int scaled_height = (max_y - min_y) * kDefaultDpi / dpi_y; - webrtc::DesktopSize size_dips(scaled_width, scaled_height); - mouse_clamping_filter_.set_input_size(size_dips); + const webrtc::DesktopSize size(max_x - min_x, max_y - min_y); + webrtc::DesktopSize size_dips = + DesktopDisplayInfo::CalcSizeDips(size, dpi_x, dpi_y); // Generate and send VideoLayout message. protocol::VideoLayout layout; @@ -563,8 +579,8 @@ video_track = layout.add_video_track(); video_track->set_position_x(0); video_track->set_position_y(0); - video_track->set_width(scaled_width); - video_track->set_height(scaled_height); + video_track->set_width(size_dips.width()); + video_track->set_height(size_dips.height()); video_track->set_x_dpi(dpi_x); video_track->set_y_dpi(dpi_y); @@ -578,10 +594,14 @@ video_track->set_y_dpi(dpi_y); // Add a VideoTrackLayout entry for each separate display. + desktop_display_info_.Reset(); for (int display_id = 0; display_id < displays->video_track_size(); display_id++) { + protocol::VideoTrackLayout display = displays->video_track(display_id); + desktop_display_info_.AddDisplayFrom(display); + protocol::VideoTrackLayout* video_track = layout.add_video_track(); - video_track->CopyFrom(displays->video_track(display_id)); + video_track->CopyFrom(display); } connection_->client_stub()->SetVideoLayout(layout);
diff --git a/remoting/host/client_session.h b/remoting/host/client_session.h index 283bb463..34f8aa2 100644 --- a/remoting/host/client_session.h +++ b/remoting/host/client_session.h
@@ -18,6 +18,7 @@ #include "base/timer/timer.h" #include "remoting/host/client_session_control.h" #include "remoting/host/client_session_details.h" +#include "remoting/host/desktop_display_info.h" #include "remoting/host/desktop_environment_options.h" #include "remoting/host/host_experiment_session_plugin.h" #include "remoting/host/host_extension_session_manager.h" @@ -35,6 +36,7 @@ #include "remoting/protocol/mouse_input_filter.h" #include "remoting/protocol/pairing_registry.h" #include "remoting/protocol/video_stream.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" namespace remoting { @@ -245,6 +247,13 @@ // Used to apply client-requested changes in screen resolution. std::unique_ptr<ScreenControls> screen_controls_; + // Contains the most recently gathered info about the desktop displays; + DesktopDisplayInfo desktop_display_info_; + + // The id of the desktop display to show to the user. + // Default is webrtc::kFullDesktopScreenId which shows all displays. + webrtc::ScreenId show_display_id_ = webrtc::kFullDesktopScreenId; + // The pairing registry for PIN-less authentication. scoped_refptr<protocol::PairingRegistry> pairing_registry_;
diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc index 4910da9..e8e6866 100644 --- a/remoting/host/client_session_unittest.cc +++ b/remoting/host/client_session_unittest.cc
@@ -107,6 +107,15 @@ void TearDown() override; protected: + // Fake multi-monitor setup. + static const int kDisplay1Width = + protocol::FakeDesktopCapturer::kWidth; // 800 + static const int kDisplay1Height = + protocol::FakeDesktopCapturer::kHeight; // 600 + static const int kDisplay2Width = 1024; + static const int kDisplay2Height = 768; + static const int kDisplay2YOffset = 35; + // Creates the client session from a FakeSession instance. void CreateClientSession(std::unique_ptr<protocol::FakeSession> session); @@ -119,7 +128,34 @@ void ConnectClientSession(); // Fakes video size notification from the VideoStream. - void NotifyVideoSize(); + void NotifyVideoSize(int width, int height, int dpi_x, int dpi_y); + + // Add a fake display to the layout list. Used in conjunction with + // NotifyDesktopDisplaySize. + void AddDisplayToLayout(protocol::VideoLayout* displays, + int x, + int y, + int width, + int height, + int dpi_x, + int dpi_y); + + // Fakes desktop display size notification from Webrtc. + void NotifyDesktopDisplaySize( + std::unique_ptr<protocol::VideoLayout> displays); + + // Fakes display select request from user. + void NotifySelectDesktopDisplay(std::string id); + + // Convenience methods to setup a single- or double-monitor setup. + void SetupSingleDisplay(); + void SetupMultiDisplay(); + + // When using a multi-mon setup, this fakes the user selecting which displays + // to show. + void MultiMon_SelectFirstDisplay(); + void MultiMon_SelectSecondDisplay(); + void MultiMon_SelectAllDisplays(); // Message loop that will process all ClientSession tasks. base::MessageLoop message_loop_; @@ -211,18 +247,142 @@ client_session_->OnConnectionChannelsConnected(); } -void ClientSessionTest::NotifyVideoSize() { +void ClientSessionTest::NotifyVideoSize(int width, + int height, + int dpi_x, + int dpi_y) { connection_->last_video_stream()->observer()->OnVideoSizeChanged( connection_->last_video_stream().get(), - webrtc::DesktopSize(protocol::FakeDesktopCapturer::kWidth, - protocol::FakeDesktopCapturer::kHeight), - webrtc::DesktopVector(kDefaultDpi, kDefaultDpi)); + webrtc::DesktopSize(width, height), webrtc::DesktopVector(dpi_x, dpi_y)); +} + +void ClientSessionTest::AddDisplayToLayout(protocol::VideoLayout* displays, + int x, + int y, + int width, + int height, + int dpi_x, + int dpi_y) { + protocol::VideoTrackLayout* video_track = displays->add_video_track(); + video_track->set_position_x(x); + video_track->set_position_y(y); + video_track->set_width(width); + video_track->set_height(height); + video_track->set_x_dpi(dpi_x); + video_track->set_y_dpi(dpi_y); +} + +void ClientSessionTest::NotifyDesktopDisplaySize( + std::unique_ptr<protocol::VideoLayout> displays) { + client_session_->OnDesktopDisplayChanged(std::move(displays)); +} + +void ClientSessionTest::NotifySelectDesktopDisplay(std::string id) { + protocol::SelectDesktopDisplayRequest req; + req.set_id(id); + client_session_->SelectDesktopDisplay(req); +} + +// Set up a single display (default size). +void ClientSessionTest::SetupSingleDisplay() { + NotifyVideoSize(kDisplay1Width, kDisplay1Height, kDefaultDpi, kDefaultDpi); + auto displays = std::make_unique<protocol::VideoLayout>(); + AddDisplayToLayout(displays.get(), 0, 0, kDisplay1Width, kDisplay1Height, + kDefaultDpi, kDefaultDpi); + NotifyDesktopDisplaySize(std::move(displays)); +} + +// Set up multiple displays: +// +-----------+ +// | 800x600 |---------------+ +// | 0 | 1024x768 | +// +-----------+ 1 | +// | | +// +---------------+ +void ClientSessionTest::SetupMultiDisplay() { + NotifyVideoSize(kDisplay1Width + kDisplay2Width, kDisplay2Height, kDefaultDpi, + kDefaultDpi); + auto displays = std::make_unique<protocol::VideoLayout>(); + AddDisplayToLayout(displays.get(), 0, 0, kDisplay1Width, kDisplay1Height, + kDefaultDpi, kDefaultDpi); + AddDisplayToLayout(displays.get(), kDisplay1Width, kDisplay2YOffset, + kDisplay2Width, kDisplay2Height, kDefaultDpi, kDefaultDpi); + NotifyDesktopDisplaySize(std::move(displays)); +} + +void ClientSessionTest::MultiMon_SelectFirstDisplay() { + NotifySelectDesktopDisplay("0"); + NotifyVideoSize(kDisplay1Width, kDisplay1Height, kDefaultDpi, kDefaultDpi); +} + +void ClientSessionTest::MultiMon_SelectSecondDisplay() { + NotifySelectDesktopDisplay("1"); + NotifyVideoSize(kDisplay2Width, kDisplay2Height, kDefaultDpi, kDefaultDpi); +} + +void ClientSessionTest::MultiMon_SelectAllDisplays() { + NotifySelectDesktopDisplay("all"); + NotifyVideoSize(kDisplay1Width + kDisplay2Width, kDisplay2Height, kDefaultDpi, + kDefaultDpi); +} + +TEST_F(ClientSessionTest, MultiMonMouseMove) { + CreateClientSession(); + ConnectClientSession(); + SetupMultiDisplay(); + + FakeInputInjector* input_injector = + desktop_environment_factory_->last_desktop_environment() + ->last_input_injector() + .get(); + std::vector<protocol::MouseEvent> mouse_events; + input_injector->set_mouse_events(&mouse_events); + + // These mouse events are in global (full desktop) coordinates. + connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(70, 50)); + connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(1000, 650)); + + // Select second display: origin: 800,35 ; size: 1024x768 + MultiMon_SelectSecondDisplay(); + // This mouse event is injected relative to the second display. + connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(1005, 625)); + // Events should clamp to the selected display. + connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(2000, 700)); + + // Select first display: origin: 0,0 ; size: 800x600 + MultiMon_SelectFirstDisplay(); + connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(80, 60)); + // Events should clamp to the selected display (800,600). + connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(1000, 640)); + + // Select entire desktop again: origin: 0,0 ; size: 1824x768 + MultiMon_SelectAllDisplays(); + // Events should clamp to the entire desktop (800+1024, 768). + connection_->input_stub()->InjectMouseEvent(MakeMouseMoveEvent(2000, 1000)); + + client_session_->DisconnectSession(protocol::OK); + client_session_.reset(); + + EXPECT_EQ(7U, mouse_events.size()); + EXPECT_THAT(mouse_events[0], EqualsMouseMoveEvent(70, 50)); + EXPECT_THAT(mouse_events[1], EqualsMouseMoveEvent(1000, 650)); + EXPECT_THAT(mouse_events[2], EqualsMouseMoveEvent(1005 + kDisplay1Width, + 625 + kDisplay2YOffset)); + EXPECT_THAT(mouse_events[3], + EqualsMouseMoveEvent(kDisplay1Width + kDisplay2Width - 1, + 700 + kDisplay2YOffset)); + EXPECT_THAT(mouse_events[4], EqualsMouseMoveEvent(80, 60)); + EXPECT_THAT(mouse_events[5], + EqualsMouseMoveEvent(kDisplay1Width - 1, kDisplay1Height - 1)); + EXPECT_THAT(mouse_events[6], + EqualsMouseMoveEvent(kDisplay1Width + kDisplay2Width - 1, + kDisplay2Height - 1)); } TEST_F(ClientSessionTest, DisableInputs) { CreateClientSession(); ConnectClientSession(); - NotifyVideoSize(); + SetupSingleDisplay(); FakeInputInjector* input_injector = desktop_environment_factory_->last_desktop_environment() @@ -278,8 +438,7 @@ TEST_F(ClientSessionTest, LocalInputTest) { CreateClientSession(); ConnectClientSession(); - NotifyVideoSize(); - + SetupSingleDisplay(); std::vector<protocol::MouseEvent> mouse_events; desktop_environment_factory_->last_desktop_environment() @@ -314,7 +473,7 @@ TEST_F(ClientSessionTest, RestoreEventState) { CreateClientSession(); ConnectClientSession(); - NotifyVideoSize(); + SetupSingleDisplay(); FakeInputInjector* input_injector = desktop_environment_factory_->last_desktop_environment() @@ -352,7 +511,7 @@ TEST_F(ClientSessionTest, ClampMouseEvents) { CreateClientSession(); ConnectClientSession(); - NotifyVideoSize(); + SetupSingleDisplay(); std::vector<protocol::MouseEvent> mouse_events; desktop_environment_factory_->last_desktop_environment()
diff --git a/remoting/host/desktop_display_info.cc b/remoting/host/desktop_display_info.cc index 6b184be7..2529cee 100644 --- a/remoting/host/desktop_display_info.cc +++ b/remoting/host/desktop_display_info.cc
@@ -5,6 +5,7 @@ #include "remoting/host/desktop_display_info.h" #include "build/build_config.h" +#include "remoting/base/constants.h" #if defined(OS_WIN) #include <windows.h> @@ -40,6 +41,45 @@ return !(*this == other); } +/* static */ +webrtc::DesktopSize DesktopDisplayInfo::CalcSizeDips(webrtc::DesktopSize size, + int dpi_x, + int dpi_y) { + webrtc::DesktopSize size_dips(size.width() * kDefaultDpi / dpi_x, + size.height() * kDefaultDpi / dpi_y); + return size_dips; +} + +void DesktopDisplayInfo::Reset() { + displays_.clear(); +} + +int DesktopDisplayInfo::NumDisplays() { + return displays_.size(); +} + +const DisplayGeometry* DesktopDisplayInfo::GetDisplayInfo(unsigned int id) { + if (id >= displays_.size()) + return nullptr; + return &displays_[id]; +} + +void DesktopDisplayInfo::AddDisplay(DisplayGeometry* display) { + displays_.push_back(*display); +} + +void DesktopDisplayInfo::AddDisplayFrom(protocol::VideoTrackLayout track) { + auto* display = new DisplayGeometry(); + display->x = track.position_x(); + display->y = track.position_y(); + display->width = track.width(); + display->height = track.height(); + display->dpi = track.x_dpi(); + display->bpp = kDefaultDpi; + display->is_default = false; + displays_.push_back(*display); +} + void DesktopDisplayInfo::LoadCurrentDisplayInfo() { displays_.clear();
diff --git a/remoting/host/desktop_display_info.h b/remoting/host/desktop_display_info.h index 766dbca..8f00da5 100644 --- a/remoting/host/desktop_display_info.h +++ b/remoting/host/desktop_display_info.h
@@ -9,6 +9,7 @@ #include "base/logging.h" #include "remoting/proto/control.pb.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" namespace remoting { @@ -25,6 +26,21 @@ DesktopDisplayInfo(); ~DesktopDisplayInfo(); + static webrtc::DesktopSize CalcSizeDips(webrtc::DesktopSize size, + int dpi_x, + int dpi_y); + + // Clear out the display info. + void Reset(); + int NumDisplays(); + const DisplayGeometry* GetDisplayInfo(unsigned int id); + + // Add a new display with the given info to the display list. + void AddDisplay(DisplayGeometry* display); + + void AddDisplayFrom(protocol::VideoTrackLayout track); + + // Query the OS for the set of currently active desktop displays. void LoadCurrentDisplayInfo(); bool operator==(const DesktopDisplayInfo& other);
diff --git a/remoting/host/installer/mac/BUILD.gn b/remoting/host/installer/mac/BUILD.gn index f4b1357..357b1f5 100644 --- a/remoting/host/installer/mac/BUILD.gn +++ b/remoting/host/installer/mac/BUILD.gn
@@ -141,6 +141,7 @@ "//base", "//remoting/host:remoting_infoplist_strings", "//remoting/host/mac:constants", + "//ui/base:base", ] foreach(locale, remoting_locales_with_underscores) { deps += [ ":remoting_uninstaller_strings_${locale}_bundle_data" ]
diff --git a/remoting/host/installer/mac/uninstaller/remoting_uninstaller_app.mm b/remoting/host/installer/mac/uninstaller/remoting_uninstaller_app.mm index cf22a9b0e..7724eb5c 100644 --- a/remoting/host/installer/mac/uninstaller/remoting_uninstaller_app.mm +++ b/remoting/host/installer/mac/uninstaller/remoting_uninstaller_app.mm
@@ -6,7 +6,10 @@ #import <Cocoa/Cocoa.h> +#include "base/mac/scoped_nsobject.h" +#include "remoting/base/string_resources.h" #include "remoting/host/installer/mac/uninstaller/remoting_uninstaller.h" +#include "ui/base/l10n/l10n_util_mac.h" @implementation RemotingUninstallerAppDelegate @@ -19,13 +22,12 @@ - (void)showSuccess:(bool)success withMessage:(NSString*) message { NSString* summary = success ? @"Uninstall succeeded" : @"Uninstall failed"; - NSAlert* alert = [NSAlert alertWithMessageText:summary - defaultButton:@"OK" - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"%@", message]; - [alert setAlertStyle: - (success ? NSInformationalAlertStyle : NSCriticalAlertStyle)]; + base::scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]); + [alert setMessageText:summary]; + [alert setInformativeText:message]; + [alert setAlertStyle:(success ? NSInformationalAlertStyle + : NSCriticalAlertStyle)]; + [alert addButtonWithTitle:l10n_util::GetNSString(IDS_OK)]; [alert runModal]; }
diff --git a/remoting/proto/control.proto b/remoting/proto/control.proto index 1829b30..c020e6a 100644 --- a/remoting/proto/control.proto +++ b/remoting/proto/control.proto
@@ -112,3 +112,25 @@ // The "all" string is used to select the entire desktop. optional string id = 1; } + +message DesktopDisplayInfo { + // Unique display identifier. + optional int32 id = 1; + + // Position of the top left corner of this display (in pixels). + optional int32 x = 2; + optional int32 y = 3; + + // Size of the display (in pixels). + optional int32 width = 4; + optional int32 height = 5; + + // DPI of the screen. + optional int32 dpi = 6; + + // Bits per pixel. + optional int32 bpp = 7; + + // True if this is the default display. + optional bool is_default = 8; +}
diff --git a/remoting/protocol/mouse_input_filter.cc b/remoting/protocol/mouse_input_filter.cc index 6080cc4b..b68a1f9 100644 --- a/remoting/protocol/mouse_input_filter.cc +++ b/remoting/protocol/mouse_input_filter.cc
@@ -4,6 +4,9 @@ #include "remoting/protocol/mouse_input_filter.h" +#include <algorithm> + +#include "base/logging.h" #include "remoting/proto/event.pb.h" namespace remoting { @@ -18,34 +21,40 @@ MouseInputFilter::~MouseInputFilter() = default; void MouseInputFilter::InjectMouseEvent(const MouseEvent& event) { - if (input_max_.is_empty() || output_max_.is_empty()) + if (input_rect_.is_empty() || output_rect_.is_empty()) return; // We scale based on the maximum input & output coordinates, rather than the // input and output sizes, so that it's possible to reach the edge of the // output when up-scaling. We also take care to round up or down correctly, // which is important when down-scaling. + // After scaling, we offset by the output rect origin. This is normally (0,0), + // but will be non-zero when we are showing a single display. MouseEvent out_event(event); if (out_event.has_x()) { - int x = out_event.x() * output_max_.width(); - x = (x + input_max_.width() / 2) / input_max_.width(); - out_event.set_x(std::max(0, std::min(output_max_.width(), x))); + int x = out_event.x() * output_rect_.width(); + x = (x + input_rect_.width() / 2) / input_rect_.width(); + out_event.set_x(output_rect_.left() + + std::max(0, std::min(output_rect_.width(), x))); } if (out_event.has_y()) { - int y = out_event.y() * output_max_.height(); - y = (y + input_max_.height() / 2) / input_max_.height(); - out_event.set_y(std::max(0, std::min(output_max_.height(), y))); + int y = out_event.y() * output_rect_.height(); + y = (y + input_rect_.height() / 2) / input_rect_.height(); + out_event.set_y(output_rect_.top() + + std::max(0, std::min(output_rect_.height(), y))); } InputFilter::InjectMouseEvent(out_event); } -void MouseInputFilter::set_input_size(const webrtc::DesktopSize& size) { - input_max_.set(size.width() - 1, size.height() - 1); +void MouseInputFilter::set_input_size(const webrtc::DesktopRect& rect) { + input_rect_ = webrtc::DesktopRect::MakeXYWH( + rect.left(), rect.top(), rect.width() - 1, rect.height() - 1); } -void MouseInputFilter::set_output_size(const webrtc::DesktopSize& size) { - output_max_.set(size.width() - 1, size.height() - 1); +void MouseInputFilter::set_output_size(const webrtc::DesktopRect& rect) { + output_rect_ = webrtc::DesktopRect::MakeXYWH( + rect.left(), rect.top(), rect.width() - 1, rect.height() - 1); } } // namespace protocol
diff --git a/remoting/protocol/mouse_input_filter.h b/remoting/protocol/mouse_input_filter.h index 1d4ffa13..21b943a 100644 --- a/remoting/protocol/mouse_input_filter.h +++ b/remoting/protocol/mouse_input_filter.h
@@ -23,17 +23,18 @@ ~MouseInputFilter() override; // Specify the input dimensions for mouse events. - void set_input_size(const webrtc::DesktopSize& size); + // This is specified in DIPs for WebRTC and pixels for ICE protocol. + void set_input_size(const webrtc::DesktopRect& r); - // Specify the output dimensions. - void set_output_size(const webrtc::DesktopSize& size); + // Specify the output dimensions (always in physical pixels). + void set_output_size(const webrtc::DesktopRect& r); // InputStub overrides. void InjectMouseEvent(const protocol::MouseEvent& event) override; private: - webrtc::DesktopSize input_max_; - webrtc::DesktopSize output_max_; + webrtc::DesktopRect input_rect_; + webrtc::DesktopRect output_rect_; DISALLOW_COPY_AND_ASSIGN(MouseInputFilter); };
diff --git a/remoting/protocol/mouse_input_filter_unittest.cc b/remoting/protocol/mouse_input_filter_unittest.cc index f27eba70..19b5a93e 100644 --- a/remoting/protocol/mouse_input_filter_unittest.cc +++ b/remoting/protocol/mouse_input_filter_unittest.cc
@@ -60,7 +60,7 @@ TEST(MouseInputFilterTest, InputDimensionsZero) { MockInputStub mock_stub; MouseInputFilter mouse_filter(&mock_stub); - mouse_filter.set_output_size(webrtc::DesktopSize(50, 50)); + mouse_filter.set_output_size(webrtc::DesktopRect::MakeWH(50, 50)); EXPECT_CALL(mock_stub, InjectMouseEvent(_)) .Times(0); @@ -72,7 +72,7 @@ TEST(MouseInputFilterTest, OutputDimensionsZero) { MockInputStub mock_stub; MouseInputFilter mouse_filter(&mock_stub); - mouse_filter.set_input_size(webrtc::DesktopSize(50, 50)); + mouse_filter.set_input_size(webrtc::DesktopRect::MakeWH(50, 50)); EXPECT_CALL(mock_stub, InjectMouseEvent(_)) .Times(0); @@ -84,8 +84,8 @@ TEST(MouseInputFilterTest, NoScalingOrClipping) { MockInputStub mock_stub; MouseInputFilter mouse_filter(&mock_stub); - mouse_filter.set_output_size(webrtc::DesktopSize(40,40)); - mouse_filter.set_input_size(webrtc::DesktopSize(40,40)); + mouse_filter.set_output_size(webrtc::DesktopRect::MakeWH(40, 40)); + mouse_filter.set_input_size(webrtc::DesktopRect::MakeWH(40, 40)); { InSequence s; @@ -112,8 +112,8 @@ TEST(MouseInputFilterTest, UpScalingAndClamping) { MockInputStub mock_stub; MouseInputFilter mouse_filter(&mock_stub); - mouse_filter.set_output_size(webrtc::DesktopSize(80, 80)); - mouse_filter.set_input_size(webrtc::DesktopSize(40, 40)); + mouse_filter.set_output_size(webrtc::DesktopRect::MakeWH(80, 80)); + mouse_filter.set_input_size(webrtc::DesktopRect::MakeWH(40, 40)); { InSequence s; @@ -140,8 +140,8 @@ TEST(MouseInputFilterTest, DownScalingAndClamping) { MockInputStub mock_stub; MouseInputFilter mouse_filter(&mock_stub); - mouse_filter.set_output_size(webrtc::DesktopSize(30, 30)); - mouse_filter.set_input_size(webrtc::DesktopSize(40, 40)); + mouse_filter.set_output_size(webrtc::DesktopRect::MakeWH(30, 30)); + mouse_filter.set_input_size(webrtc::DesktopRect::MakeWH(40, 40)); { InSequence s;
diff --git a/services/content/public/cpp/navigable_contents_view.cc b/services/content/public/cpp/navigable_contents_view.cc index 677e9448..4b5c5e3 100644 --- a/services/content/public/cpp/navigable_contents_view.cc +++ b/services/content/public/cpp/navigable_contents_view.cc
@@ -83,7 +83,7 @@ private: void ResizeChildren() { for (auto* child : owner_->children()) - SetChildBoundsDirect(child, owner_->bounds()); + SetChildBoundsDirect(child, gfx::Rect(owner_->bounds().size())); } aura::Window* const owner_;
diff --git a/services/device/bluetooth/bluetooth_system_unittest.cc b/services/device/bluetooth/bluetooth_system_unittest.cc index c7d6c7e..54cd300 100644 --- a/services/device/bluetooth/bluetooth_system_unittest.cc +++ b/services/device/bluetooth/bluetooth_system_unittest.cc
@@ -21,6 +21,7 @@ #include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "mojo/public/cpp/bindings/binding.h" #include "services/device/device_service_test_base.h" +#include "services/device/public/mojom/bluetooth_system.mojom-test-utils.h" #include "services/device/public/mojom/bluetooth_system.mojom.h" #include "services/device/public/mojom/constants.mojom.h" #include "third_party/cros_system_api/dbus/service_constants.h"
diff --git a/services/device/geolocation/wifi_data_provider_mac.mm b/services/device/geolocation/wifi_data_provider_mac.mm index ff25310d..278a5385 100644 --- a/services/device/geolocation/wifi_data_provider_mac.mm +++ b/services/device/geolocation/wifi_data_provider_mac.mm
@@ -7,6 +7,12 @@ #import <CoreWLAN/CoreWLAN.h> #import <Foundation/Foundation.h> +// This file uses the deprecated CWInterface API, but CWWiFiClient appears to be +// different in ways that are relevant to this code, so for now ignore the +// deprecation. See <https://crbug.com/841631>. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #include "base/mac/scoped_nsautorelease_pool.h" #include "base/mac/scoped_nsobject.h" #include "base/macros.h" @@ -135,3 +141,5 @@ } } // namespace device + +#pragma clang diagnostic pop
diff --git a/services/image_annotation/OWNERS b/services/image_annotation/OWNERS new file mode 100644 index 0000000..fb9a02e --- /dev/null +++ b/services/image_annotation/OWNERS
@@ -0,0 +1,3 @@ +amoylan@chromium.org +charleszhao@chromium.org +martis@chromium.org
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn index 2795da5b..6a852c7d 100644 --- a/services/network/BUILD.gn +++ b/services/network/BUILD.gn
@@ -38,6 +38,8 @@ "empty_url_loader_client.h", "host_resolver.cc", "host_resolver.h", + "host_resolver_mdns_listener.cc", + "host_resolver_mdns_listener.h", "http_auth_cache_copier.cc", "http_auth_cache_copier.h", "http_cache_data_counter.cc",
diff --git a/services/network/host_resolver.cc b/services/network/host_resolver.cc index cf52398..a9039450 100644 --- a/services/network/host_resolver.cc +++ b/services/network/host_resolver.cc
@@ -14,6 +14,7 @@ #include "net/dns/host_resolver.h" #include "net/dns/host_resolver_source.h" #include "net/log/net_log.h" +#include "services/network/host_resolver_mdns_listener.h" #include "services/network/resolve_host_request.h" namespace network { @@ -100,6 +101,28 @@ DCHECK(insertion_result); } +void HostResolver::MdnsListen(const net::HostPortPair& host, + net::DnsQueryType query_type, + mojom::MdnsListenClientPtr response_client, + MdnsListenCallback callback) { +#if !BUILDFLAG(ENABLE_MDNS) + NOTREACHED(); +#endif // !BUILDFLAG(ENABLE_MDNS) + + auto listener = std::make_unique<HostResolverMdnsListener>(internal_resolver_, + host, query_type); + int rv = + listener->Start(std::move(response_client), + base::BindOnce(&HostResolver::OnMdnsListenerCancelled, + base::Unretained(this), listener.get())); + if (rv == net::OK) { + bool insertion_result = listeners_.emplace(std::move(listener)).second; + DCHECK(insertion_result); + } + + std::move(callback).Run(rv); +} + size_t HostResolver::GetNumOutstandingRequestsForTesting() const { return requests_.size(); } @@ -118,6 +141,12 @@ requests_.erase(found_request); } +void HostResolver::OnMdnsListenerCancelled(HostResolverMdnsListener* listener) { + auto found_listener = listeners_.find(listener); + DCHECK(found_listener != listeners_.end()); + listeners_.erase(found_listener); +} + void HostResolver::OnConnectionError() { DCHECK(connection_shutdown_callback_);
diff --git a/services/network/host_resolver.h b/services/network/host_resolver.h index fb4c00e7..b4629c6 100644 --- a/services/network/host_resolver.h +++ b/services/network/host_resolver.h
@@ -7,12 +7,14 @@ #include <memory> #include <set> +#include <string> #include "base/callback.h" #include "base/component_export.h" #include "base/containers/unique_ptr_adapters.h" #include "base/macros.h" #include "mojo/public/cpp/bindings/binding.h" +#include "net/dns/public/dns_query_type.h" #include "services/network/public/mojom/host_resolver.mojom.h" namespace net { @@ -22,6 +24,7 @@ } // namespace net namespace network { +class HostResolverMdnsListener; class ResolveHostRequest; class COMPONENT_EXPORT(NETWORK_SERVICE) HostResolver @@ -47,6 +50,10 @@ void ResolveHost(const net::HostPortPair& host, mojom::ResolveHostParametersPtr optional_parameters, mojom::ResolveHostClientPtr response_client) override; + void MdnsListen(const net::HostPortPair& host, + net::DnsQueryType query_type, + mojom::MdnsListenClientPtr response_client, + MdnsListenCallback callback) override; size_t GetNumOutstandingRequestsForTesting() const; @@ -57,12 +64,15 @@ private: void OnResolveHostComplete(ResolveHostRequest* request, int error); + void OnMdnsListenerCancelled(HostResolverMdnsListener* listener); void OnConnectionError(); mojo::Binding<mojom::HostResolver> binding_; ConnectionShutdownCallback connection_shutdown_callback_; std::set<std::unique_ptr<ResolveHostRequest>, base::UniquePtrComparator> requests_; + std::set<std::unique_ptr<HostResolverMdnsListener>, base::UniquePtrComparator> + listeners_; net::HostResolver* const internal_resolver_; net::NetLog* const net_log_;
diff --git a/services/network/host_resolver_mdns_listener.cc b/services/network/host_resolver_mdns_listener.cc new file mode 100644 index 0000000..55732e3 --- /dev/null +++ b/services/network/host_resolver_mdns_listener.cc
@@ -0,0 +1,88 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/host_resolver_mdns_listener.h" + +#include <utility> + +#include "base/callback.h" +#include "net/base/host_port_pair.h" + +namespace network { + +HostResolverMdnsListener::HostResolverMdnsListener( + net::HostResolver* resolver, + const net::HostPortPair& host, + net::DnsQueryType query_type) { + DCHECK(resolver); + + internal_listener_ = resolver->CreateMdnsListener(host, query_type); +} + +HostResolverMdnsListener::~HostResolverMdnsListener() { + internal_listener_ = nullptr; + response_client_ = nullptr; +} + +int HostResolverMdnsListener::Start(mojom::MdnsListenClientPtr response_client, + base::OnceClosure cancellation_callback) { + DCHECK(internal_listener_); + DCHECK(!response_client_.is_bound()); + + int rv = internal_listener_->Start(this); + if (rv != net::OK) + return rv; + + response_client_ = std::move(response_client); + // Unretained |this| reference is safe because connection error cannot occur + // if |response_client_| goes out of scope. + response_client_.set_connection_error_handler(base::BindOnce( + &HostResolverMdnsListener::OnConnectionError, base::Unretained(this))); + + cancellation_callback_ = std::move(cancellation_callback); + + return net::OK; +} + +void HostResolverMdnsListener::OnAddressResult( + net::HostResolver::MdnsListener::Delegate::UpdateType update_type, + net::DnsQueryType query_type, + net::IPEndPoint address) { + DCHECK(response_client_.is_bound()); + response_client_->OnAddressResult(update_type, query_type, address); +} + +void HostResolverMdnsListener::OnTextResult( + net::HostResolver::MdnsListener::Delegate::UpdateType update_type, + net::DnsQueryType query_type, + std::vector<std::string> text_records) { + DCHECK(response_client_.is_bound()); + response_client_->OnTextResult(update_type, query_type, text_records); +} + +void HostResolverMdnsListener::OnHostnameResult( + net::HostResolver::MdnsListener::Delegate::UpdateType update_type, + net::DnsQueryType query_type, + net::HostPortPair host) { + DCHECK(response_client_.is_bound()); + response_client_->OnHostnameResult(update_type, query_type, host); +} + +void HostResolverMdnsListener::OnUnhandledResult( + net::HostResolver::MdnsListener::Delegate::UpdateType update_type, + net::DnsQueryType query_type) { + DCHECK(response_client_.is_bound()); + response_client_->OnUnhandledResult(update_type, query_type); +} + +void HostResolverMdnsListener::OnConnectionError() { + DCHECK(cancellation_callback_); + + internal_listener_ = nullptr; + + // Invoke cancellation callback last as it may delete |this|. + std::move(cancellation_callback_).Run(); +} + +} // namespace network
diff --git a/services/network/host_resolver_mdns_listener.h b/services/network/host_resolver_mdns_listener.h new file mode 100644 index 0000000..7f14e25 --- /dev/null +++ b/services/network/host_resolver_mdns_listener.h
@@ -0,0 +1,66 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_NETWORK_HOST_RESOLVER_MDNS_LISTENER_H_ +#define SERVICES_NETWORK_HOST_RESOLVER_MDNS_LISTENER_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/callback_forward.h" +#include "base/macros.h" +#include "net/base/ip_endpoint.h" +#include "net/dns/host_resolver.h" +#include "net/dns/public/dns_query_type.h" +#include "services/network/public/mojom/host_resolver.mojom.h" + +namespace net { +class HostPortPair; +} // namespace net + +namespace network { + +class HostResolverMdnsListener + : public net::HostResolver::MdnsListener::Delegate { + public: + HostResolverMdnsListener(net::HostResolver* resolver, + const net::HostPortPair& host, + net::DnsQueryType query_type); + ~HostResolverMdnsListener() override; + + int Start(mojom::MdnsListenClientPtr response_client, + base::OnceClosure cancellation_callback); + + // net::HostResolver::MdnsListenerDelegate implementation + void OnAddressResult( + net::HostResolver::MdnsListener::Delegate::UpdateType update_type, + net::DnsQueryType query_type, + net::IPEndPoint address) override; + void OnTextResult( + net::HostResolver::MdnsListener::Delegate::UpdateType update_type, + net::DnsQueryType query_type, + std::vector<std::string> text_records) override; + void OnHostnameResult( + net::HostResolver::MdnsListener::Delegate::UpdateType update_type, + net::DnsQueryType query_type, + net::HostPortPair host) override; + void OnUnhandledResult( + net::HostResolver::MdnsListener::Delegate::UpdateType update_type, + net::DnsQueryType query_type) override; + + private: + void OnConnectionError(); + + std::unique_ptr<net::HostResolver::MdnsListener> internal_listener_; + mojom::MdnsListenClientPtr response_client_; + + base::OnceClosure cancellation_callback_; + + DISALLOW_COPY_AND_ASSIGN(HostResolverMdnsListener); +}; + +} // namespace network + +#endif // SERVICES_NETWORK_HOST_RESOLVER_MDNS_LISTENER_H_
diff --git a/services/network/host_resolver_unittest.cc b/services/network/host_resolver_unittest.cc index 57cbc807..3980779d 100644 --- a/services/network/host_resolver_unittest.cc +++ b/services/network/host_resolver_unittest.cc
@@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <memory> -#include <string> +#include "services/network/host_resolver.h" + +#include <map> #include <utility> #include <vector> @@ -13,7 +14,6 @@ #include "base/test/bind_test_util.h" #include "base/test/scoped_task_environment.h" #include "base/test/simple_test_tick_clock.h" -#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "net/base/address_list.h" #include "net/base/host_port_pair.h" @@ -22,13 +22,11 @@ #include "net/base/net_errors.h" #include "net/dns/dns_config.h" #include "net/dns/dns_test_util.h" +#include "net/dns/host_resolver.h" #include "net/dns/host_resolver_impl.h" #include "net/dns/mock_host_resolver.h" #include "net/dns/public/dns_protocol.h" -#include "net/dns/public/dns_query_type.h" #include "net/log/net_log.h" -#include "services/network/host_resolver.h" -#include "services/network/public/mojom/host_resolver.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -118,6 +116,72 @@ base::RunLoop* const run_loop_; }; +class TestMdnsListenClient : public mojom::MdnsListenClient { + public: + using UpdateType = net::HostResolver::MdnsListener::Delegate::UpdateType; + using UpdateKey = std::pair<UpdateType, net::DnsQueryType>; + + explicit TestMdnsListenClient(mojom::MdnsListenClientPtr* interface_ptr) + : binding_(this, mojo::MakeRequest(interface_ptr)) {} + + void OnAddressResult(UpdateType update_type, + net::DnsQueryType result_type, + const net::IPEndPoint& address) override { + address_results_.insert({{update_type, result_type}, address}); + } + + void OnTextResult(UpdateType update_type, + net::DnsQueryType result_type, + const std::vector<std::string>& text_records) override { + for (auto& text_record : text_records) { + text_results_.insert({{update_type, result_type}, text_record}); + } + } + + void OnHostnameResult(UpdateType update_type, + net::DnsQueryType result_type, + const net::HostPortPair& host) override { + hostname_results_.insert({{update_type, result_type}, host}); + } + + void OnUnhandledResult(UpdateType update_type, + net::DnsQueryType result_type) override { + unhandled_results_.insert({update_type, result_type}); + } + + const std::multimap<UpdateKey, net::IPEndPoint>& address_results() { + return address_results_; + } + + const std::multimap<UpdateKey, std::string>& text_results() { + return text_results_; + } + + const std::multimap<UpdateKey, net::HostPortPair>& hostname_results() { + return hostname_results_; + } + + const std::multiset<UpdateKey>& unhandled_results() { + return unhandled_results_; + } + + template <typename T> + static std::pair<UpdateKey, T> CreateExpectedResult( + UpdateType update_type, + net::DnsQueryType query_type, + T result) { + return std::make_pair(std::make_pair(update_type, query_type), result); + } + + private: + mojo::Binding<mojom::MdnsListenClient> binding_; + + std::multimap<UpdateKey, net::IPEndPoint> address_results_; + std::multimap<UpdateKey, std::string> text_results_; + std::multimap<UpdateKey, net::HostPortPair> hostname_results_; + std::multiset<UpdateKey> unhandled_results_; +}; + TEST_F(HostResolverTest, Sync) { auto inner_resolver = std::make_unique<net::MockHostResolver>(); inner_resolver->set_synchronous_mode(true); @@ -1148,5 +1212,161 @@ EXPECT_EQ(0u, resolver.GetNumOutstandingRequestsForTesting()); } +#if BUILDFLAG(ENABLE_MDNS) +TEST_F(HostResolverTest, MdnsListener_AddressResult) { + net::NetLog net_log; + auto inner_resolver = std::make_unique<net::MockHostResolver>(); + HostResolver resolver(inner_resolver.get(), &net_log); + + mojom::MdnsListenClientPtr response_client_ptr; + TestMdnsListenClient response_client(&response_client_ptr); + + int error = net::ERR_FAILED; + base::RunLoop run_loop; + net::HostPortPair host("host.local", 41); + resolver.MdnsListen(host, net::DnsQueryType::A, + std::move(response_client_ptr), + base::BindLambdaForTesting([&](int error_val) { + error = error_val; + run_loop.Quit(); + })); + + run_loop.Run(); + ASSERT_EQ(net::OK, error); + + net::IPAddress result_address(1, 2, 3, 4); + net::IPEndPoint result(result_address, 41); + inner_resolver->TriggerMdnsListeners( + host, net::DnsQueryType::A, + net::HostResolver::MdnsListener::Delegate::UpdateType::ADDED, result); + base::RunLoop().RunUntilIdle(); + + EXPECT_THAT(response_client.address_results(), + testing::ElementsAre(TestMdnsListenClient::CreateExpectedResult( + net::HostResolver::MdnsListener::Delegate::UpdateType::ADDED, + net::DnsQueryType::A, result))); + + EXPECT_THAT(response_client.text_results(), testing::IsEmpty()); + EXPECT_THAT(response_client.hostname_results(), testing::IsEmpty()); + EXPECT_THAT(response_client.unhandled_results(), testing::IsEmpty()); +} + +TEST_F(HostResolverTest, MdnsListener_TextResult) { + net::NetLog net_log; + auto inner_resolver = std::make_unique<net::MockHostResolver>(); + HostResolver resolver(inner_resolver.get(), &net_log); + + mojom::MdnsListenClientPtr response_client_ptr; + TestMdnsListenClient response_client(&response_client_ptr); + + int error = net::ERR_FAILED; + base::RunLoop run_loop; + net::HostPortPair host("host.local", 42); + resolver.MdnsListen(host, net::DnsQueryType::TXT, + std::move(response_client_ptr), + base::BindLambdaForTesting([&](int error_val) { + error = error_val; + run_loop.Quit(); + })); + + run_loop.Run(); + ASSERT_EQ(net::OK, error); + + inner_resolver->TriggerMdnsListeners( + host, net::DnsQueryType::TXT, + net::HostResolver::MdnsListener::Delegate::UpdateType::CHANGED, + {"foo", "bar"}); + base::RunLoop().RunUntilIdle(); + + EXPECT_THAT( + response_client.text_results(), + testing::UnorderedElementsAre( + TestMdnsListenClient::CreateExpectedResult( + net::HostResolver::MdnsListener::Delegate::UpdateType::CHANGED, + net::DnsQueryType::TXT, "foo"), + TestMdnsListenClient::CreateExpectedResult( + net::HostResolver::MdnsListener::Delegate::UpdateType::CHANGED, + net::DnsQueryType::TXT, "bar"))); + + EXPECT_THAT(response_client.address_results(), testing::IsEmpty()); + EXPECT_THAT(response_client.hostname_results(), testing::IsEmpty()); + EXPECT_THAT(response_client.unhandled_results(), testing::IsEmpty()); +} + +TEST_F(HostResolverTest, MdnsListener_HostnameResult) { + net::NetLog net_log; + auto inner_resolver = std::make_unique<net::MockHostResolver>(); + HostResolver resolver(inner_resolver.get(), &net_log); + + mojom::MdnsListenClientPtr response_client_ptr; + TestMdnsListenClient response_client(&response_client_ptr); + + int error = net::ERR_FAILED; + base::RunLoop run_loop; + net::HostPortPair host("host.local", 43); + resolver.MdnsListen(host, net::DnsQueryType::PTR, + std::move(response_client_ptr), + base::BindLambdaForTesting([&](int error_val) { + error = error_val; + run_loop.Quit(); + })); + + run_loop.Run(); + ASSERT_EQ(net::OK, error); + + net::HostPortPair result("example.com", 43); + inner_resolver->TriggerMdnsListeners( + host, net::DnsQueryType::PTR, + net::HostResolver::MdnsListener::Delegate::UpdateType::REMOVED, result); + base::RunLoop().RunUntilIdle(); + + EXPECT_THAT( + response_client.hostname_results(), + testing::ElementsAre(TestMdnsListenClient::CreateExpectedResult( + net::HostResolver::MdnsListener::Delegate::UpdateType::REMOVED, + net::DnsQueryType::PTR, result))); + + EXPECT_THAT(response_client.address_results(), testing::IsEmpty()); + EXPECT_THAT(response_client.text_results(), testing::IsEmpty()); + EXPECT_THAT(response_client.unhandled_results(), testing::IsEmpty()); +} + +TEST_F(HostResolverTest, MdnsListener_UnhandledResult) { + net::NetLog net_log; + auto inner_resolver = std::make_unique<net::MockHostResolver>(); + HostResolver resolver(inner_resolver.get(), &net_log); + + mojom::MdnsListenClientPtr response_client_ptr; + TestMdnsListenClient response_client(&response_client_ptr); + + int error = net::ERR_FAILED; + base::RunLoop run_loop; + net::HostPortPair host("host.local", 44); + resolver.MdnsListen(host, net::DnsQueryType::PTR, + std::move(response_client_ptr), + base::BindLambdaForTesting([&](int error_val) { + error = error_val; + run_loop.Quit(); + })); + + run_loop.Run(); + ASSERT_EQ(net::OK, error); + + inner_resolver->TriggerMdnsListeners( + host, net::DnsQueryType::PTR, + net::HostResolver::MdnsListener::Delegate::UpdateType::ADDED); + base::RunLoop().RunUntilIdle(); + + EXPECT_THAT(response_client.unhandled_results(), + testing::ElementsAre(std::make_pair( + net::HostResolver::MdnsListener::Delegate::UpdateType::ADDED, + net::DnsQueryType::PTR))); + + EXPECT_THAT(response_client.address_results(), testing::IsEmpty()); + EXPECT_THAT(response_client.text_results(), testing::IsEmpty()); + EXPECT_THAT(response_client.hostname_results(), testing::IsEmpty()); +} +#endif // BUILDFLAG(ENABLE_MDNS) + } // namespace } // namespace network
diff --git a/services/network/network_service.cc b/services/network/network_service.cc index 83febccd..fbe344a 100644 --- a/services/network/network_service.cc +++ b/services/network/network_service.cc
@@ -65,6 +65,7 @@ #if defined(OS_ANDROID) #include "base/android/application_status_listener.h" +#include "net/android/http_auth_negotiate_android.h" #endif namespace network { @@ -137,6 +138,70 @@ return a.load_state > b.load_state; } +#if defined(OS_ANDROID) && BUILDFLAG(USE_KERBEROS) +// Used for Negotiate authentication on Android, which needs to generate tokens +// in the browser process. +class NetworkServiceAuthNegotiateAndroid : public net::HttpNegotiateAuthSystem { + public: + NetworkServiceAuthNegotiateAndroid(NetworkService* network_service, + const net::HttpAuthPreferences* prefs) + : network_service_(network_service), auth_negotiate_(prefs) {} + ~NetworkServiceAuthNegotiateAndroid() override = default; + + // HttpNegotiateAuthSystem implementation: + bool Init() override { return auth_negotiate_.Init(); } + + bool NeedsIdentity() const override { + return auth_negotiate_.NeedsIdentity(); + } + + bool AllowsExplicitCredentials() const override { + return auth_negotiate_.AllowsExplicitCredentials(); + } + + net::HttpAuth::AuthorizationResult ParseChallenge( + net::HttpAuthChallengeTokenizer* tok) override { + return auth_negotiate_.ParseChallenge(tok); + } + + int GenerateAuthToken(const net::AuthCredentials* credentials, + const std::string& spn, + const std::string& channel_bindings, + std::string* auth_token, + net::CompletionOnceCallback callback) override { + network_service_->client()->OnGenerateHttpNegotiateAuthToken( + auth_negotiate_.server_auth_token(), auth_negotiate_.can_delegate(), + auth_negotiate_.GetAuthAndroidNegotiateAccountType(), spn, + base::BindOnce(&NetworkServiceAuthNegotiateAndroid::Finish, + weak_factory_.GetWeakPtr(), auth_token, + std::move(callback))); + return net::ERR_IO_PENDING; + } + + void Delegate() override { auth_negotiate_.Delegate(); } + + private: + void Finish(std::string* auth_token_out, + net::CompletionOnceCallback callback, + int result, + const std::string& auth_token) { + *auth_token_out = auth_token; + std::move(callback).Run(result); + } + + NetworkService* network_service_ = nullptr; + net::android::HttpAuthNegotiateAndroid auth_negotiate_; + base::WeakPtrFactory<NetworkServiceAuthNegotiateAndroid> weak_factory_{this}; +}; + +std::unique_ptr<net::HttpNegotiateAuthSystem> CreateAuthSystem( + NetworkService* network_service, + const net::HttpAuthPreferences* prefs) { + return std::make_unique<NetworkServiceAuthNegotiateAndroid>(network_service, + prefs); +} +#endif + } // namespace NetworkService::NetworkService( @@ -413,7 +478,11 @@ , http_auth_static_params->gssapi_library_name #endif - ); +#if defined(OS_ANDROID) && BUILDFLAG(USE_KERBEROS) + , + base::BindRepeating(&CreateAuthSystem, this) +#endif + ); } void NetworkService::ConfigureHttpAuthPrefs( @@ -558,7 +627,12 @@ net::HttpAuthHandlerFactory* NetworkService::GetHttpAuthHandlerFactory() { if (!http_auth_handler_factory_) { http_auth_handler_factory_ = net::HttpAuthHandlerFactory::CreateDefault( - host_resolver_.get(), &http_auth_preferences_); + host_resolver_.get(), &http_auth_preferences_ +#if defined(OS_ANDROID) && BUILDFLAG(USE_KERBEROS) + , + base::BindRepeating(&CreateAuthSystem, this) +#endif + ); } return http_auth_handler_factory_.get(); }
diff --git a/services/network/public/cpp/host_resolver.typemap b/services/network/public/cpp/host_resolver.typemap index 8921967..20cb2428 100644 --- a/services/network/public/cpp/host_resolver.typemap +++ b/services/network/public/cpp/host_resolver.typemap
@@ -5,6 +5,7 @@ mojom = "//services/network/public/mojom/host_resolver.mojom" public_headers = [ "//net/dns/dns_config_overrides.h", + "//net/dns/host_resolver.h", "//net/dns/host_resolver_source.h", "//net/dns/public/dns_query_type.h", ] @@ -18,6 +19,7 @@ ] type_mappings = [ "network.mojom.DnsConfigOverrides=net::DnsConfigOverrides", - "network.mojom.ResolveHostParameters.DnsQueryType=net::DnsQueryType", + "network.mojom.DnsQueryType=net::DnsQueryType", "network.mojom.ResolveHostParameters.Source=net::HostResolverSource", + "network.mojom.MdnsListenClient.UpdateType=net::HostResolver::MdnsListener::Delegate::UpdateType", ]
diff --git a/services/network/public/cpp/host_resolver_mojom_traits.cc b/services/network/public/cpp/host_resolver_mojom_traits.cc index 78a22a7..424cba4 100644 --- a/services/network/public/cpp/host_resolver_mojom_traits.cc +++ b/services/network/public/cpp/host_resolver_mojom_traits.cc
@@ -18,6 +18,8 @@ using network::mojom::DnsOverHttpsServer; using network::mojom::DnsOverHttpsServerDataView; using network::mojom::DnsOverHttpsServerPtr; +using network::mojom::DnsQueryType; +using network::mojom::MdnsListenClient; using network::mojom::ResolveHostParameters; namespace { @@ -215,46 +217,45 @@ } // static -ResolveHostParameters::DnsQueryType -EnumTraits<ResolveHostParameters::DnsQueryType, net::DnsQueryType>::ToMojom( +DnsQueryType EnumTraits<DnsQueryType, net::DnsQueryType>::ToMojom( net::DnsQueryType input) { switch (input) { case net::DnsQueryType::UNSPECIFIED: - return ResolveHostParameters::DnsQueryType::UNSPECIFIED; + return DnsQueryType::UNSPECIFIED; case net::DnsQueryType::A: - return ResolveHostParameters::DnsQueryType::A; + return DnsQueryType::A; case net::DnsQueryType::AAAA: - return ResolveHostParameters::DnsQueryType::AAAA; + return DnsQueryType::AAAA; case net::DnsQueryType::TXT: - return ResolveHostParameters::DnsQueryType::TXT; + return DnsQueryType::TXT; case net::DnsQueryType::PTR: - return ResolveHostParameters::DnsQueryType::PTR; + return DnsQueryType::PTR; case net::DnsQueryType::SRV: - return ResolveHostParameters::DnsQueryType::SRV; + return DnsQueryType::SRV; } } // static -bool EnumTraits<ResolveHostParameters::DnsQueryType, net::DnsQueryType>:: - FromMojom(ResolveHostParameters::DnsQueryType input, - net::DnsQueryType* output) { +bool EnumTraits<DnsQueryType, net::DnsQueryType>::FromMojom( + DnsQueryType input, + net::DnsQueryType* output) { switch (input) { - case ResolveHostParameters::DnsQueryType::UNSPECIFIED: + case DnsQueryType::UNSPECIFIED: *output = net::DnsQueryType::UNSPECIFIED; return true; - case ResolveHostParameters::DnsQueryType::A: + case DnsQueryType::A: *output = net::DnsQueryType::A; return true; - case ResolveHostParameters::DnsQueryType::AAAA: + case DnsQueryType::AAAA: *output = net::DnsQueryType::AAAA; return true; - case ResolveHostParameters::DnsQueryType::TXT: + case DnsQueryType::TXT: *output = net::DnsQueryType::TXT; return true; - case ResolveHostParameters::DnsQueryType::PTR: + case DnsQueryType::PTR: *output = net::DnsQueryType::PTR; return true; - case ResolveHostParameters::DnsQueryType::SRV: + case DnsQueryType::SRV: *output = net::DnsQueryType::SRV; return true; } @@ -296,4 +297,37 @@ } } +// static +MdnsListenClient::UpdateType +EnumTraits<MdnsListenClient::UpdateType, + net::HostResolver::MdnsListener::Delegate::UpdateType>:: + ToMojom(net::HostResolver::MdnsListener::Delegate::UpdateType input) { + switch (input) { + case net::HostResolver::MdnsListener::Delegate::UpdateType::ADDED: + return MdnsListenClient::UpdateType::ADDED; + case net::HostResolver::MdnsListener::Delegate::UpdateType::CHANGED: + return MdnsListenClient::UpdateType::CHANGED; + case net::HostResolver::MdnsListener::Delegate::UpdateType::REMOVED: + return MdnsListenClient::UpdateType::REMOVED; + } +} + +// static +bool EnumTraits<MdnsListenClient::UpdateType, + net::HostResolver::MdnsListener::Delegate::UpdateType>:: + FromMojom(MdnsListenClient::UpdateType input, + net::HostResolver::MdnsListener::Delegate::UpdateType* output) { + switch (input) { + case MdnsListenClient::UpdateType::ADDED: + *output = net::HostResolver::MdnsListener::Delegate::UpdateType::ADDED; + return true; + case MdnsListenClient::UpdateType::CHANGED: + *output = net::HostResolver::MdnsListener::Delegate::UpdateType::CHANGED; + return true; + case MdnsListenClient::UpdateType::REMOVED: + *output = net::HostResolver::MdnsListener::Delegate::UpdateType::REMOVED; + return true; + } +} + } // namespace mojo
diff --git a/services/network/public/cpp/host_resolver_mojom_traits.h b/services/network/public/cpp/host_resolver_mojom_traits.h index 3d18769a..3a5fd42 100644 --- a/services/network/public/cpp/host_resolver_mojom_traits.h +++ b/services/network/public/cpp/host_resolver_mojom_traits.h
@@ -72,13 +72,10 @@ }; template <> -struct EnumTraits<network::mojom::ResolveHostParameters::DnsQueryType, - net::DnsQueryType> { - static network::mojom::ResolveHostParameters::DnsQueryType ToMojom( - net::DnsQueryType input); - static bool FromMojom( - network::mojom::ResolveHostParameters::DnsQueryType input, - net::DnsQueryType* output); +struct EnumTraits<network::mojom::DnsQueryType, net::DnsQueryType> { + static network::mojom::DnsQueryType ToMojom(net::DnsQueryType input); + static bool FromMojom(network::mojom::DnsQueryType input, + net::DnsQueryType* output); }; template <> @@ -90,6 +87,16 @@ net::HostResolverSource* output); }; +template <> +struct EnumTraits<network::mojom::MdnsListenClient::UpdateType, + net::HostResolver::MdnsListener::Delegate::UpdateType> { + static network::mojom::MdnsListenClient::UpdateType ToMojom( + net::HostResolver::MdnsListener::Delegate::UpdateType input); + static bool FromMojom( + network::mojom::MdnsListenClient::UpdateType input, + net::HostResolver::MdnsListener::Delegate::UpdateType* output); +}; + } // namespace mojo #endif // SERVICES_NETWORK_PUBLIC_CPP_HOST_RESOLVER_MOJOM_TRAITS_H_
diff --git a/services/network/public/mojom/host_resolver.mojom b/services/network/public/mojom/host_resolver.mojom index b3e723f1..3fe9011e 100644 --- a/services/network/public/mojom/host_resolver.mojom +++ b/services/network/public/mojom/host_resolver.mojom
@@ -118,22 +118,22 @@ OnHostnameResults(array<HostPortPair> hosts); }; +// DNS query type for a ResolveHostRequest. +// See: +// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4 +enum DnsQueryType { + UNSPECIFIED, + A, + AAAA, + TXT, + PTR, + SRV, +}; + // Parameter-grouping struct for additional optional parameters for // HostResolver::ResolveHost() calls. All fields are optional and have a // reasonable default. struct ResolveHostParameters { - // DNS query type for a ResolveHostRequest. - // See: - // https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4 - enum DnsQueryType { - UNSPECIFIED, - A, - AAAA, - TXT, - PTR, - SRV, - }; - // Requested DNS query type. If UNSPECIFIED, resolver will pick A or AAAA (or // both) based on IPv4/IPv6 settings. DnsQueryType dns_query_type = DnsQueryType.UNSPECIFIED; @@ -189,9 +189,36 @@ bool is_speculative = false; }; +// Response interface used to receive notifications from +// HostResolver::MdnsListen requests. All methods have a |query_type| field to +// allow a single BindingSet and implementation to be used to listen for updates +// for multiple types for the same host. +interface MdnsListenClient { + enum UpdateType { + ADDED, + CHANGED, + REMOVED + }; + + OnAddressResult(UpdateType update_type, + DnsQueryType query_type, + IPEndPoint endpoint); + OnTextResult(UpdateType update_type, + DnsQueryType query_type, + array<string> text_records); + OnHostnameResult(UpdateType update_type, + DnsQueryType query_type, + HostPortPair host); + + // For results which may be valid MDNS but are not handled/parsed by network + // service, e.g. pointers to the root domain. + OnUnhandledResult(UpdateType update_type, DnsQueryType query_type); +}; + // Interface that can be passed to code/processes without direct access to // NetworkContext to make ResolveHost requests. If destroyed, all outstanding -// ResolveHost requests from the destroyed interface will be cancelled. +// ResolveHost and MdnsListen requests from the destroyed interface will be +// cancelled. interface HostResolver { // Resolves the given hostname (or IP address literal). Results are a network // error code, and on success (network error code OK), an AddressList. All @@ -214,6 +241,17 @@ ResolveHost(HostPortPair host, ResolveHostParameters? optional_parameters, ResolveHostClient response_client); + + // Starts a listener to watch for updates to a multicast DNS result. Result is + // a network error code indicating the success of starting the listener. On + // success (result OK), |response_client| will begin receiving update + // notifications. + // + // All outstanding listeners are cancelled and will receive no further + // notifications if the HostResolver or parent NetworkContext are destroyed. + MdnsListen(HostPortPair host, + DnsQueryType query_type, + MdnsListenClient response_client) => (int32 result); }; // A client interface that subscribes to DNS config change events from
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom index 2f8568d0..e991c54 100644 --- a/services/network/public/mojom/network_service.mojom +++ b/services/network/public/mojom/network_service.mojom
@@ -168,6 +168,13 @@ // identifies the annotation of the request. OnDataUseUpdate(int32 network_traffic_annotation_id_hash, int64 recv_bytes, int64 sent_bytes); + + // Called to generate an auth token for SPNEGO authentication on Android. + [EnableIf=is_android] + OnGenerateHttpNegotiateAuthToken(string server_auth_token, bool can_delegate, + string auth_negotiate_android_account_type, + string spn) => + (int32 result, string auth_token); }; // Values for configuring HTTP authentication that can only be set once.
diff --git a/services/network/test/test_network_service_client.cc b/services/network/test/test_network_service_client.cc index e9324731..b1678e7c 100644 --- a/services/network/test/test_network_service_client.cc +++ b/services/network/test/test_network_service_client.cc
@@ -133,4 +133,15 @@ int64_t recv_bytes, int64_t sent_bytes) {} +#if defined(OS_ANDROID) +void TestNetworkServiceClient::OnGenerateHttpNegotiateAuthToken( + const std::string& server_auth_token, + bool can_delegate, + const std::string& auth_negotiate_android_account_type, + const std::string& spn, + OnGenerateHttpNegotiateAuthTokenCallback callback) { + NOTREACHED(); +} +#endif + } // namespace network
diff --git a/services/network/test/test_network_service_client.h b/services/network/test/test_network_service_client.h index 5977999..e79f32e9 100644 --- a/services/network/test/test_network_service_client.h +++ b/services/network/test/test_network_service_client.h
@@ -5,6 +5,7 @@ #ifndef SERVICES_NETWORK_TEST_TEST_NETWORK_SERVICE_CLIENT_H_ #define SERVICES_NETWORK_TEST_TEST_NETWORK_SERVICE_CLIENT_H_ +#include "build/build_config.h" #include "mojo/public/cpp/bindings/binding.h" #include "services/network/public/mojom/network_service.mojom.h" @@ -80,6 +81,14 @@ void OnDataUseUpdate(int32_t network_traffic_annotation_id_hash, int64_t recv_bytes, int64_t sent_bytes) override; +#if defined(OS_ANDROID) + void OnGenerateHttpNegotiateAuthToken( + const std::string& server_auth_token, + bool can_delegate, + const std::string& auth_negotiate_android_account_type, + const std::string& spn, + OnGenerateHttpNegotiateAuthTokenCallback callback) override; +#endif private: bool enable_uploads_;
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc index 0e5c319..e218d8ac 100644 --- a/services/network/url_loader_unittest.cc +++ b/services/network/url_loader_unittest.cc
@@ -2308,6 +2308,17 @@ int64_t recv_bytes, int64_t sent_bytes) override {} +#if defined(OS_ANDROID) + void OnGenerateHttpNegotiateAuthToken( + const std::string& server_auth_token, + bool can_delegate, + const std::string& auth_negotiate_android_account_type, + const std::string& spn, + OnGenerateHttpNegotiateAuthTokenCallback callback) override { + NOTREACHED(); + } +#endif + void set_credentials_response(CredentialsResponse credentials_response) { credentials_response_ = credentials_response; }
diff --git a/services/service_manager/public/cpp/manifest.cc b/services/service_manager/public/cpp/manifest.cc index 464ad43..9d38fc98 100644 --- a/services/service_manager/public/cpp/manifest.cc +++ b/services/service_manager/public/cpp/manifest.cc
@@ -59,177 +59,6 @@ Manifest::ExposedInterfaceFilterCapability::operator=( ExposedInterfaceFilterCapability&&) = default; -// static -Manifest Manifest::FromValueDeprecated(std::unique_ptr<base::Value> value_ptr) { - DCHECK(value_ptr); - base::Value value(std::move(*value_ptr)); - - Manifest manifest; - if (!value.is_dict()) - return manifest; - - const base::Value* name_value = value.FindKey("name"); - if (name_value && name_value->is_string()) - manifest.service_name = name_value->GetString(); - - const base::Value* display_name_value = value.FindKey("display_name"); - if (display_name_value && display_name_value->is_string()) - manifest.display_name.raw_string = display_name_value->GetString(); - - const base::Value* sandbox_type_value = value.FindKey("sandbox_type"); - if (sandbox_type_value && sandbox_type_value->is_string()) { - manifest.options.sandbox_type = sandbox_type_value->GetString(); - } else { - // This is kind of weird, but the default when processing packaged service - // manifests (which is all we care about now, in practice) is "utility". So - // assume that if no "sandbox_type" key is present. - manifest.options.sandbox_type = "utility"; - } - - const base::Value* options_value = value.FindKey("options"); - if (options_value && options_value->is_dict()) { - const base::Value* can_connect_to_services_as_any_user_value = - options_value->FindKey("can_connect_to_other_services_as_any_user"); - manifest.options.can_connect_to_instances_in_any_group = - can_connect_to_services_as_any_user_value && - can_connect_to_services_as_any_user_value->is_bool() && - can_connect_to_services_as_any_user_value->GetBool(); - - const base::Value* - can_connect_to_other_services_with_any_instance_name_value = - options_value->FindKey( - "can_connect_to_other_services_with_any_instance_name"); - manifest.options.can_connect_to_instances_with_any_id = - can_connect_to_other_services_with_any_instance_name_value && - can_connect_to_other_services_with_any_instance_name_value->is_bool() && - can_connect_to_other_services_with_any_instance_name_value->GetBool(); - - const base::Value* can_create_other_service_instances_value = - options_value->FindKey("can_create_other_service_instances"); - manifest.options.can_register_other_service_instances = - can_create_other_service_instances_value && - can_create_other_service_instances_value->is_bool() && - can_create_other_service_instances_value->GetBool(); - - const base::Value* instance_sharing_value = - options_value->FindKey("instance_sharing"); - if (instance_sharing_value && instance_sharing_value->is_string()) { - if (instance_sharing_value->GetString() == "singleton") { - manifest.options.instance_sharing_policy = - InstanceSharingPolicy::kSingleton; - } else if (instance_sharing_value->GetString() == - "shared_instance_across_users" || - instance_sharing_value->GetString() == - "shared_across_instance_groups") { - manifest.options.instance_sharing_policy = - InstanceSharingPolicy::kSharedAcrossGroups; - } - } - } - - const base::Value* interface_provider_specs_value = - value.FindKey("interface_provider_specs"); - if (interface_provider_specs_value && - interface_provider_specs_value->is_dict()) { - for (const auto& spec : interface_provider_specs_value->DictItems()) { - if (!spec.second.is_dict()) - continue; - const std::string& spec_name = spec.first; - const bool is_main_spec = (spec_name == "service_manager:connector"); - const base::Value* provides_value = spec.second.FindKey("provides"); - if (provides_value && provides_value->is_dict()) { - for (const auto& capability : provides_value->DictItems()) { - if (!capability.second.is_list()) - continue; - const std::string& capability_name = capability.first; - std::set<std::string> interface_names; - for (const auto& interface_name : capability.second.GetList()) - interface_names.insert(interface_name.GetString()); - if (is_main_spec) { - ExposedCapability capability; - capability.capability_name = capability_name; - capability.interface_names = std::move(interface_names); - manifest.exposed_capabilities.emplace_back(std::move(capability)); - } else { - ExposedInterfaceFilterCapability capability; - capability.filter_name = spec_name; - capability.capability_name = capability_name; - capability.interface_names = std::move(interface_names); - manifest.exposed_interface_filter_capabilities.emplace_back( - std::move(capability)); - } - } - } - - const base::Value* requires_value = spec.second.FindKey("requires"); - if (requires_value && requires_value->is_dict()) { - for (const auto& entry : requires_value->DictItems()) { - if (!entry.second.is_list()) - continue; - const std::string& from_service_name = entry.first; - if (is_main_spec) { - if (entry.second.GetList().empty()) { - manifest.required_capabilities.push_back({from_service_name, ""}); - } else { - for (const auto& capability_name : entry.second.GetList()) { - manifest.required_capabilities.push_back( - {from_service_name, capability_name.GetString()}); - } - } - } else { - for (const auto& capability_name : entry.second.GetList()) { - manifest.required_interface_filter_capabilities.push_back( - {from_service_name, spec_name, capability_name.GetString()}); - } - } - } - } - } - } - - const base::Value* required_values_value = value.FindKey("required_files"); - if (required_values_value && required_values_value->is_dict()) { -#if defined(OS_LINUX) - constexpr const char kRequiredPlatform[] = "linux"; -#elif defined(OS_ANDROID) - constexpr const char kRequiredPlatform[] = "android"; -#else - constexpr const char kRequiredPlatform[] = "none"; -#endif - for (const auto& item : required_values_value->DictItems()) { - const std::string& key = item.first; - if (!item.second.is_list()) - continue; - - for (const auto& entry : item.second.GetList()) { - if (!entry.is_dict()) - continue; - const base::Value* path_value = entry.FindKey("path"); - const base::Value* platform_value = entry.FindKey("platform"); - if (platform_value && platform_value->is_string() && path_value && - path_value->is_string() && - platform_value->GetString() == kRequiredPlatform) { - PreloadedFileInfo info; - info.key = key; - info.path = base::FilePath().AppendASCII(path_value->GetString()); - manifest.preloaded_files.emplace_back(std::move(info)); - } - } - } - } - - constexpr const char kServicesKey[] = "services"; - base::Value* services_value = value.FindKey(kServicesKey); - if (services_value && services_value->is_list()) { - for (auto& manifest_value : services_value->GetList()) { - manifest.packaged_services.emplace_back(FromValueDeprecated( - std::make_unique<base::Value>(std::move(manifest_value)))); - } - } - - return manifest; -} - Manifest& Manifest::Amend(Manifest other) { for (auto& other_capability : other.exposed_capabilities) { auto it = std::find_if(
diff --git a/services/service_manager/public/cpp/manifest.h b/services/service_manager/public/cpp/manifest.h index 85fe136..33e6e0a 100644 --- a/services/service_manager/public/cpp/manifest.h +++ b/services/service_manager/public/cpp/manifest.h
@@ -11,7 +11,6 @@ #include "base/component_export.h" #include "base/files/file_path.h" -#include "base/values.h" namespace service_manager { @@ -259,11 +258,6 @@ Manifest& operator=(const Manifest&); Manifest& operator=(Manifest&&); - // Creates a new Manifest object from a |base::Value| representation of the - // deprecated JSON manifest format. This is a temporary function and should - // only be used to transition services away from JSON manifests. - static Manifest FromValueDeprecated(std::unique_ptr<base::Value> value_ptr); - // Amends this Manifest with a subset of |other|. Namely, exposed and required // capabilities, exposed and required interface filter capabilities, packaged // services, and preloaded files are all added from |other| if present.
diff --git a/services/service_manager/public/cpp/manifest_unittest.cc b/services/service_manager/public/cpp/manifest_unittest.cc index 729e3c1..d8c315c 100644 --- a/services/service_manager/public/cpp/manifest_unittest.cc +++ b/services/service_manager/public/cpp/manifest_unittest.cc
@@ -8,10 +8,8 @@ #include <string> #include "base/files/file_path.h" -#include "base/json/json_reader.h" #include "base/no_destructor.h" #include "base/stl_util.h" -#include "base/values.h" #include "services/service_manager/public/cpp/manifest_builder.h" #include "services/service_manager/public/mojom/connector.mojom.h" #include "testing/gmock/include/gmock/gmock.h" @@ -97,102 +95,6 @@ EXPECT_EQ(3u, manifest.preloaded_files.size()); } -TEST(ManifestTest, FromValueDeprecated) { - constexpr const char kTestManifestJson[] = R"( - { - "name": "foo", - "display_name": "bar", - "sandbox_type": "utility", - "services": [ - { "name": "packaged1" }, - { "name": "packaged2" } - ], - "options": { - "can_connect_to_other_services_as_any_user": true, - "can_connect_to_other_services_with_any_instance_name": true, - "can_create_other_service_instances": true, - "instance_sharing": "singleton" - }, - "interface_provider_specs": { - "service_manager:connector": { - "provides": { - "cap1": ["interface1", "interface2"], - "cap2": ["interface3"], - "cap3": [] - }, - "requires": { - "a_service": ["cap3"], - "another_service": ["cap4", "cap5"], - "one_more_service": [] - } - }, - "navigation:frame": { - "provides": { - "cap6": ["interface4"] - }, - "requires": { - "yet_another_service": ["cap7", "cap8"] - } - } - } - } - )"; - const Manifest manifest{ - Manifest::FromValueDeprecated(base::JSONReader::Read(kTestManifestJson))}; - - EXPECT_EQ("foo", manifest.service_name); - EXPECT_EQ("bar", manifest.display_name.raw_string); - - EXPECT_EQ("utility", manifest.options.sandbox_type); - EXPECT_EQ(Manifest::InstanceSharingPolicy::kSingleton, - manifest.options.instance_sharing_policy); - EXPECT_EQ(true, manifest.options.can_connect_to_instances_in_any_group); - EXPECT_EQ(true, manifest.options.can_connect_to_instances_with_any_id); - EXPECT_EQ(true, manifest.options.can_register_other_service_instances); - - const auto& exposed_capabilities = manifest.exposed_capabilities; - ASSERT_EQ(3u, exposed_capabilities.size()); - EXPECT_EQ("cap1", exposed_capabilities[0].capability_name); - EXPECT_THAT(exposed_capabilities[0].interface_names, - ElementsAre("interface1", "interface2")); - EXPECT_EQ("cap2", exposed_capabilities[1].capability_name); - EXPECT_THAT(exposed_capabilities[1].interface_names, - ElementsAre("interface3")); - EXPECT_EQ("cap3", exposed_capabilities[2].capability_name); - EXPECT_TRUE(exposed_capabilities[2].interface_names.empty()); - - const auto& required_capabilities = manifest.required_capabilities; - ASSERT_EQ(4u, required_capabilities.size()); - EXPECT_EQ("a_service", required_capabilities[0].service_name); - EXPECT_EQ("cap3", required_capabilities[0].capability_name); - EXPECT_EQ("another_service", required_capabilities[1].service_name); - EXPECT_EQ("cap4", required_capabilities[1].capability_name); - EXPECT_EQ("another_service", required_capabilities[2].service_name); - EXPECT_EQ("cap5", required_capabilities[2].capability_name); - EXPECT_EQ("one_more_service", required_capabilities[3].service_name); - EXPECT_EQ("", required_capabilities[3].capability_name); - - const auto& exposed_filters = manifest.exposed_interface_filter_capabilities; - ASSERT_EQ(1u, exposed_filters.size()); - EXPECT_EQ("navigation:frame", exposed_filters[0].filter_name); - EXPECT_EQ("cap6", exposed_filters[0].capability_name); - EXPECT_THAT(exposed_filters[0].interface_names, ElementsAre("interface4")); - - const auto& required_filters = - manifest.required_interface_filter_capabilities; - ASSERT_EQ(2u, required_filters.size()); - EXPECT_EQ("navigation:frame", required_filters[0].filter_name); - EXPECT_EQ("yet_another_service", required_filters[0].service_name); - EXPECT_EQ("cap7", required_filters[0].capability_name); - EXPECT_EQ("navigation:frame", required_filters[1].filter_name); - EXPECT_EQ("yet_another_service", required_filters[1].service_name); - EXPECT_EQ("cap8", required_filters[1].capability_name); - - ASSERT_EQ(2u, manifest.packaged_services.size()); - EXPECT_EQ("packaged1", manifest.packaged_services[0].service_name); - EXPECT_EQ("packaged2", manifest.packaged_services[1].service_name); -} - TEST(ManifestTest, Amend) { // Verify that everything is properly merged when amending potentially // overlapping capability metadata.
diff --git a/services/tracing/perfetto/json_trace_exporter.cc b/services/tracing/perfetto/json_trace_exporter.cc index b209234..7463985 100644 --- a/services/tracing/perfetto/json_trace_exporter.cc +++ b/services/tracing/perfetto/json_trace_exporter.cc
@@ -472,8 +472,14 @@ void JSONTraceExporter::OnDetach(bool) { NOTREACHED(); } + void JSONTraceExporter::OnAttach(bool, const perfetto::TraceConfig&) { NOTREACHED(); } +void JSONTraceExporter::OnTraceStats(bool, const perfetto::TraceStats&) { + // We don't currently use GetTraceStats(). + NOTREACHED(); +} + } // namespace tracing
diff --git a/services/tracing/perfetto/json_trace_exporter.h b/services/tracing/perfetto/json_trace_exporter.h index d7a626a69..2ea2ccd 100644 --- a/services/tracing/perfetto/json_trace_exporter.h +++ b/services/tracing/perfetto/json_trace_exporter.h
@@ -57,6 +57,7 @@ bool has_more) override; void OnDetach(bool success) override; void OnAttach(bool success, const perfetto::TraceConfig&) override; + void OnTraceStats(bool success, const perfetto::TraceStats&) override; private: OnTraceEventJSONCallback json_callback_;
diff --git a/services/tracing/perfetto/json_trace_exporter_unittest.cc b/services/tracing/perfetto/json_trace_exporter_unittest.cc index 00953c4b..169551f 100644 --- a/services/tracing/perfetto/json_trace_exporter_unittest.cc +++ b/services/tracing/perfetto/json_trace_exporter_unittest.cc
@@ -88,6 +88,7 @@ // Unused in chrome. void Detach(const std::string& /*key*/) override {} void Attach(const std::string& /*key*/) override {} + void GetTraceStats() override {} private: MockService* mock_service_;
diff --git a/services/tracing/perfetto/test_utils.cc b/services/tracing/perfetto/test_utils.cc index a0e22f4..d7b9087 100644 --- a/services/tracing/perfetto/test_utils.cc +++ b/services/tracing/perfetto/test_utils.cc
@@ -177,6 +177,8 @@ void MockConsumer::OnDetach(bool /*success*/) {} void MockConsumer::OnAttach(bool /*success*/, const perfetto::TraceConfig&) {} +void MockConsumer::OnTraceStats(bool /*success*/, const perfetto::TraceStats&) { +} MockProducerHost::MockProducerHost( const std::string& data_source_name,
diff --git a/services/tracing/perfetto/test_utils.h b/services/tracing/perfetto/test_utils.h index f76a89e..7246c122 100644 --- a/services/tracing/perfetto/test_utils.h +++ b/services/tracing/perfetto/test_utils.h
@@ -104,6 +104,7 @@ bool has_more) override; void OnDetach(bool success) override; void OnAttach(bool success, const perfetto::TraceConfig&) override; + void OnTraceStats(bool success, const perfetto::TraceStats&) override; private: std::unique_ptr<perfetto::TracingService::ConsumerEndpoint>
diff --git a/services/ws/ime/test_ime_driver/test_ime_driver.cc b/services/ws/ime/test_ime_driver/test_ime_driver.cc index 3c86c2f0..7a03d3b9 100644 --- a/services/ws/ime/test_ime_driver/test_ime_driver.cc +++ b/services/ws/ime/test_ime_driver/test_ime_driver.cc
@@ -22,10 +22,10 @@ // mojom::InputMethod: void OnTextInputStateChanged( ws::mojom::TextInputStatePtr text_input_state) override { - NOTIMPLEMENTED(); + NOTIMPLEMENTED_LOG_ONCE(); } void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) override { - NOTIMPLEMENTED(); + NOTIMPLEMENTED_LOG_ONCE(); } void ProcessKeyEvent(std::unique_ptr<ui::Event> key_event, ProcessKeyEventCallback callback) override { @@ -40,8 +40,8 @@ base::Unretained(this), std::move(cloned_event), std::move(callback))); } - void CancelComposition() override { NOTIMPLEMENTED(); } - void ShowVirtualKeyboardIfEnabled() override { NOTIMPLEMENTED(); } + void CancelComposition() override { NOTIMPLEMENTED_LOG_ONCE(); } + void ShowVirtualKeyboardIfEnabled() override { NOTIMPLEMENTED_LOG_ONCE(); } void PostProcssKeyEvent(std::unique_ptr<ui::Event> key_event, ProcessKeyEventCallback callback,
diff --git a/services/ws/public/cpp/property_type_converters.cc b/services/ws/public/cpp/property_type_converters.cc index aa61e57..f720009 100644 --- a/services/ws/public/cpp/property_type_converters.cc +++ b/services/ws/public/cpp/property_type_converters.cc
@@ -15,6 +15,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/size_f.h" namespace mojo { @@ -69,6 +70,45 @@ return vec; } +namespace { + +union float2bytes { + float f; + uint32_t i; +}; + +} // namespace + +// static +gfx::SizeF TypeConverter<gfx::SizeF, std::vector<uint8_t>>::Convert( + const std::vector<uint8_t>& input) { + if (input.size() != 8) + return gfx::SizeF(); + + float2bytes width, height; + width.i = input[0] << 24 | input[1] << 16 | input[2] << 8 | input[3]; + height.i = input[4] << 24 | input[5] << 16 | input[6] << 8 | input[7]; + return gfx::SizeF(width.f, height.f); +} + +// static +std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, gfx::SizeF>::Convert( + const gfx::SizeF& input) { + std::vector<uint8_t> vec(8); + float2bytes width, height; + width.f = input.width(); + height.f = input.height(); + vec[0] = (width.i >> 24) & 0xFF; + vec[1] = (width.i >> 16) & 0xFF; + vec[2] = (width.i >> 8) & 0xFF; + vec[3] = width.i & 0xFF; + vec[4] = (height.i >> 24) & 0xFF; + vec[5] = (height.i >> 16) & 0xFF; + vec[6] = (height.i >> 8) & 0xFF; + vec[7] = height.i & 0xFF; + return vec; +} + // static gfx::Size TypeConverter<gfx::Size, std::vector<uint8_t>>::Convert( const std::vector<uint8_t>& input) {
diff --git a/services/ws/public/cpp/property_type_converters.h b/services/ws/public/cpp/property_type_converters.h index ad9f923..6c39ca70 100644 --- a/services/ws/public/cpp/property_type_converters.h +++ b/services/ws/public/cpp/property_type_converters.h
@@ -21,6 +21,7 @@ namespace gfx { class Rect; class Size; +class SizeF; } // namespace gfx namespace mojo { @@ -48,6 +49,15 @@ }; template <> +struct TypeConverter<std::vector<uint8_t>, gfx::SizeF> { + static std::vector<uint8_t> Convert(const gfx::SizeF& input); +}; +template <> +struct TypeConverter<gfx::SizeF, std::vector<uint8_t>> { + static gfx::SizeF Convert(const std::vector<uint8_t>& input); +}; + +template <> struct TypeConverter<std::vector<uint8_t>, int32_t> { static std::vector<uint8_t> Convert(const int32_t& input); };
diff --git a/services/ws/public/mojom/window_manager.mojom b/services/ws/public/mojom/window_manager.mojom index d3420714..a49223c3 100644 --- a/services/ws/public/mojom/window_manager.mojom +++ b/services/ws/public/mojom/window_manager.mojom
@@ -70,6 +70,9 @@ // "com.google.Photos". Type: mojom::String. const string kArcPackageName_Property = "prop:arc-package-name"; + // The aspect ratio to be kept. Type: gfx::SizeF. + const string kAspectRatio_Property = "prop:aspect-ratio"; + // The accessibility ui::AXTreeID for a views::Widget. // TODO(dmazzoni): Convert to base::UnguessableToken. https://crbug.com/881986 // Type: mojom::String @@ -99,6 +102,10 @@ const string kFrameActiveColor_Property = "prop:frame-active-color"; const string kFrameInactiveColor_Property = "prop:frame-inactive-color"; + // The window's maximum size as defined by its content. Maps to + // aura::client::kMaximumSize_Property. Type: gfx::Size. + const string kMaximumSize_Property = "prop:maximum-size"; + // The window's minimum size as defined by its content. Maps to // aura::client::kMinimumSize_Property. Type: gfx::Size. const string kMinimumSize_Property = "prop:minimum-size";
diff --git a/services/ws/window_server_test_impl.cc b/services/ws/window_server_test_impl.cc index 70ac330..d57ddfe 100644 --- a/services/ws/window_server_test_impl.cc +++ b/services/ws/window_server_test_impl.cc
@@ -65,7 +65,8 @@ EnsureClientHasDrawnWindowCallback cb, const std::string& actual_client_name) { if (desired_client_name == actual_client_name) { - RequestWindowContents(desired_client_name, std::move(cb)); + RequestWindowContents(desired_client_name, /*retry_count=*/0, + std::move(cb)); } else { // No tree with the given name, or it hasn't painted yet. Install a callback // for the next time a client creates a CompositorFramesink. @@ -83,21 +84,23 @@ void WindowServerTestImpl::RequestWindowContents( const std::string& client_name, + int retry_count, EnsureClientHasDrawnWindowCallback cb) { ClientRoot* client_root = GetWindowTreeWithClientName(client_name) ->GetFirstRootWithCompositorFrameSink(); if (!client_root || client_root->window()->bounds().IsEmpty()) { base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(&WindowServerTestImpl::RequestWindowContents, - base::Unretained(this), client_name, std::move(cb))); + FROM_HERE, base::BindOnce(&WindowServerTestImpl::RequestWindowContents, + base::Unretained(this), client_name, + retry_count, std::move(cb))); return; } auto copy_output_request = std::make_unique<viz::CopyOutputRequest>( viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, base::BindOnce(&WindowServerTestImpl::OnWindowContentsCaptured, - base::Unretained(this), client_name, std::move(cb))); + base::Unretained(this), client_name, retry_count, + std::move(cb))); aura::Window* window = client_root->window(); copy_output_request->set_area(gfx::Rect(window->bounds().size())); window->layer()->RequestCopyOfOutput(std::move(copy_output_request)); @@ -105,14 +108,30 @@ void WindowServerTestImpl::OnWindowContentsCaptured( const std::string& client_name, + int retry_count, EnsureClientHasDrawnWindowCallback cb, std::unique_ptr<viz::CopyOutputResult> result) { - if (result->IsEmpty()) { - RequestWindowContents(client_name, std::move(cb)); + if (!result->IsEmpty() && SanityCheckOutputSkBitmap(result->AsSkBitmap())) { + std::move(cb).Run(/*success=*/true); return; } - std::move(cb).Run(SanityCheckOutputSkBitmap(result->AsSkBitmap())); + // Arbitrary retry params. + constexpr int kMaxRetry = 3; + constexpr base::TimeDelta kRetryDelay = base::TimeDelta::FromSeconds(1); + + ++retry_count; + if (retry_count == kMaxRetry) { + std::move(cb).Run(/*success=*/false); + return; + } + + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&WindowServerTestImpl::RequestWindowContents, + base::Unretained(this), client_name, retry_count, + std::move(cb)), + kRetryDelay); } void WindowServerTestImpl::EnsureClientHasDrawnWindow( @@ -120,7 +139,7 @@ EnsureClientHasDrawnWindowCallback callback) { WindowTree* tree = GetWindowTreeWithClientName(client_name); if (tree && tree->GetFirstRootWithCompositorFrameSink()) { - RequestWindowContents(client_name, std::move(callback)); + RequestWindowContents(client_name, /*retry_count=*/0, std::move(callback)); return; } InstallCallback(client_name, std::move(callback));
diff --git a/services/ws/window_server_test_impl.h b/services/ws/window_server_test_impl.h index 53a0958e..e7cdaa2 100644 --- a/services/ws/window_server_test_impl.h +++ b/services/ws/window_server_test_impl.h
@@ -43,8 +43,10 @@ // Request to capture the window contents of the client and invoke the // callback with sanity check result of the captured pixels. void RequestWindowContents(const std::string& client_name, + int retry_count, EnsureClientHasDrawnWindowCallback cb); void OnWindowContentsCaptured(const std::string& client_name, + int retry_count, EnsureClientHasDrawnWindowCallback cb, std::unique_ptr<viz::CopyOutputResult> result);
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn index 8e0b5ac..e280660 100644 --- a/storage/browser/BUILD.gn +++ b/storage/browser/BUILD.gn
@@ -179,6 +179,8 @@ "quota/quota_client.h", "quota/quota_database.cc", "quota/quota_database.h", + "quota/quota_features.cc", + "quota/quota_features.h", "quota/quota_macros.h", "quota/quota_manager.cc", "quota/quota_manager.h",
diff --git a/storage/browser/quota/quota_features.cc b/storage/browser/quota/quota_features.cc new file mode 100644 index 0000000..fb269e1 --- /dev/null +++ b/storage/browser/quota/quota_features.cc
@@ -0,0 +1,31 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "storage/browser/quota/quota_features.h" + +namespace storage { + +namespace features { + +#if defined(OS_CHROMEOS) +// Chrome OS is given a larger fraction, as web content is the considered +// the primary use of the platform. Chrome OS itself maintains free space by +// starting to evict data (old profiles) when less than 1GB remains, +// stopping eviction once 2GB is free. +// Prior to M66 this was 1/3, same as other platforms. +const constexpr double kTemporaryPoolSizeRatioThirds = 2.0 / 3.0; // 66% +#else +const constexpr double kTemporaryPoolSizeRatioThirds = 1.0 / 3.0; // 33% +#endif + +const base::Feature kQuotaExpandPoolSize{"QuotaExpandPoolSize", + base::FEATURE_DISABLED_BY_DEFAULT}; + +constexpr base::FeatureParam<double> kExperimentalPoolSizeRatio{ + &kQuotaExpandPoolSize, "PoolSizeRatio", kTemporaryPoolSizeRatioThirds}; + +constexpr base::FeatureParam<double> kPerHostRatio{&kQuotaExpandPoolSize, + "PerHostRatio", 0.2}; +} // namespace features +} // namespace storage
diff --git a/storage/browser/quota/quota_features.h b/storage/browser/quota/quota_features.h new file mode 100644 index 0000000..ba0292f4 --- /dev/null +++ b/storage/browser/quota/quota_features.h
@@ -0,0 +1,25 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_QUOTA_QUOTA_FEATURES_H_ +#define STORAGE_BROWSER_QUOTA_QUOTA_FEATURES_H_ + +#include "base/component_export.h" +#include "base/feature_list.h" +#include "base/metrics/field_trial_params.h" + +namespace storage { + +namespace features { + +COMPONENT_EXPORT(STORAGE_BROWSER) +extern const base::Feature kQuotaExpandPoolSize; +extern const base::FeatureParam<double> kExperimentalPoolSizeRatio; +extern const base::FeatureParam<double> kPerHostRatio; + +} // namespace features + +} // namespace storage + +#endif // STORAGE_QUOTA_QUOTA_FEATURES_H_
diff --git a/storage/browser/quota/quota_settings.cc b/storage/browser/quota/quota_settings.cc index 8765569..3d755fc 100644 --- a/storage/browser/quota/quota_settings.cc +++ b/storage/browser/quota/quota_settings.cc
@@ -11,6 +11,7 @@ #include "base/task/post_task.h" #include "base/threading/scoped_blocking_call.h" #include "build/build_config.h" +#include "storage/browser/quota/quota_features.h" #include "storage/browser/quota/quota_macros.h" namespace storage { @@ -47,18 +48,13 @@ return settings; } -// The fraction of the device's storage the browser is willing to -// use for temporary storage. -#if defined(OS_CHROMEOS) - // Chrome OS is given a larger fraction, as web content is the considered - // the primary use of the platform. Chrome OS itself maintains free space by - // starting to evict data (old profiles) when less than 1GB remains, - // stopping eviction once 2GB is free. - // Prior to M66 this was 1/3, same as other platforms. - const double kTemporaryPoolSizeRatio = 2.0 / 3.0; // 66% -#else - const double kTemporaryPoolSizeRatio = 1.0 / 3.0; // 33% -#endif + // The fraction of the device's storage the browser is willing to + // use for temporary storage. + // Check Finch for an experimental value to use as temporary pool size ratio + // if experiment is enabled, otherwise fallback to ~66% for chromeOS and + // ~33% otherwise. + const double kTemporaryPoolSizeRatio = + features::kExperimentalPoolSizeRatio.Get(); // The amount of the device's storage the browser attempts to // keep free. If there is less than this amount of storage free @@ -93,7 +89,7 @@ // Determines the portion of the temp pool that can be // utilized by a single host (ie. 5 for 20%). - const int kPerHostTemporaryPortion = 5; + const double kPerHostTemporaryRatio = features::kPerHostRatio.Get(); // SessionOnly (or ephemeral) origins are allotted a fraction of what // normal origins are provided, and the amount is capped to a hard limit. @@ -117,7 +113,7 @@ settings.must_remain_available = std::min(kMustRemainAvailableFixed, static_cast<int64_t>(total * kMustRemainAvailableRatio)); - settings.per_host_quota = pool_size / kPerHostTemporaryPortion; + settings.per_host_quota = pool_size * kPerHostTemporaryRatio; settings.session_only_per_host_quota = std::min( RandomizeByPercent(kMaxSessionOnlyHostQuota, kRandomizedPercentage), static_cast<int64_t>(settings.per_host_quota *
diff --git a/testing/android/driver/java/AndroidManifest.xml b/testing/android/driver/java/AndroidManifest.xml index 97f2d658..cae6f08d 100644 --- a/testing/android/driver/java/AndroidManifest.xml +++ b/testing/android/driver/java/AndroidManifest.xml
@@ -10,7 +10,7 @@ android:versionCode="1" android:versionName="1.0"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:label="OnDeviceInstrumentationDriver" />
diff --git a/testing/android/native_test/java/AndroidManifest.xml.jinja2 b/testing/android/native_test/java/AndroidManifest.xml.jinja2 index ff97921..6d6c029 100644 --- a/testing/android/native_test/java/AndroidManifest.xml.jinja2 +++ b/testing/android/native_test/java/AndroidManifest.xml.jinja2
@@ -10,7 +10,7 @@ android:versionCode="1" android:versionName="1.0"> - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
diff --git a/testing/buildbot/OWNERS b/testing/buildbot/OWNERS index e9c77851..fcadf545 100644 --- a/testing/buildbot/OWNERS +++ b/testing/buildbot/OWNERS
@@ -18,12 +18,9 @@ per-file chromium.fyi.json=creis@chromium.org per-file chromium.clang.json=hans@chromium.org -per-file *chromium.perf*.json=dtu@chromium.org +per-file *chromium.perf*.json=crouleau@chromium.org per-file *chromium.perf*.json=eyaich@chromium.org per-file *chromium.perf*.json=martiniss@chromium.org -per-file *chromium.perf*.json=nednguyen@google.com -per-file chromium.perf.json=eakuefner@chromium.org -per-file chromium.perf.json=fmeawad@chromium.org per-file chromium.perf.json=simonhatch@chromium.org per-file chromium.perf.json=sullivan@chromium.org per-file chromium.webrtc.json=phoglund@chromium.org
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index ab7b204..d0e96c0 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -17211,6 +17211,7 @@ "dimension_sets": [ { "device_os": "OPR3.170623.008", + "device_playstore_version": "12.8.23-all", "device_type": "marlin", "os": "Android" } @@ -23693,7 +23694,13 @@ ], "isolated_scripts": [ { + "args": [ + "--smoke-test-mode" + ], "isolate_name": "components_perftests", + "merge": { + "script": "//tools/perf/process_perf_results.py" + }, "name": "components_perftests", "swarming": { "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 37b2a2b..4684f524 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -1,6 +1,11 @@ { "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, "AAAAA2 See generate_buildbot_json.py to make changes": {}, + "chromeos-amd64-generic-cfi-thin-lto-rel": { + "additional_compile_targets": [ + "chromiumos_preflight" + ] + }, "chromeos-amd64-generic-rel": { "additional_compile_targets": [ "chromiumos_preflight"
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json index c72040d..a8eb72a 100644 --- a/testing/buildbot/chromium.clang.json +++ b/testing/buildbot/chromium.clang.json
@@ -13696,7 +13696,13 @@ } }, { + "args": [ + "--smoke-test-mode" + ], "isolate_name": "components_perftests", + "merge": { + "script": "//tools/perf/process_perf_results.py" + }, "name": "components_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -13749,6 +13755,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 5e4f452..7fab689e 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -891,7 +891,13 @@ } }, { + "args": [ + "--smoke-test-mode" + ], "isolate_name": "components_perftests", + "merge": { + "script": "//tools/perf/process_perf_results.py" + }, "name": "components_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -944,6 +950,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -3926,19 +3938,19 @@ "swarming": { "can_use_on_swarming_builders": true }, - "test": "castrunner_browsertests" + "test": "cast_runner_browsertests" }, { "swarming": { "can_use_on_swarming_builders": true }, - "test": "castrunner_integration_tests" + "test": "cast_runner_integration_tests" }, { "swarming": { "can_use_on_swarming_builders": true }, - "test": "castrunner_unittests" + "test": "cast_runner_unittests" }, { "args": [ @@ -4043,13 +4055,13 @@ "swarming": { "can_use_on_swarming_builders": true }, - "test": "webrunner_browsertests" + "test": "web_runner_integration_tests" }, { "swarming": { "can_use_on_swarming_builders": true }, - "test": "webrunner_smoketests" + "test": "webrunner_browsertests" }, { "swarming": { @@ -4084,7 +4096,7 @@ } ] }, - "test": "castrunner_browsertests" + "test": "cast_runner_browsertests" }, { "swarming": { @@ -4095,7 +4107,7 @@ } ] }, - "test": "castrunner_integration_tests" + "test": "cast_runner_integration_tests" }, { "swarming": { @@ -4106,7 +4118,7 @@ } ] }, - "test": "castrunner_unittests" + "test": "cast_runner_unittests" }, { "args": [ @@ -4291,7 +4303,7 @@ } ] }, - "test": "webrunner_browsertests" + "test": "web_runner_integration_tests" }, { "swarming": { @@ -4302,7 +4314,7 @@ } ] }, - "test": "webrunner_smoketests" + "test": "webrunner_browsertests" }, { "swarming": { @@ -4342,7 +4354,7 @@ } ] }, - "test": "castrunner_browsertests" + "test": "cast_runner_browsertests" }, { "swarming": { @@ -4353,7 +4365,7 @@ } ] }, - "test": "castrunner_integration_tests" + "test": "cast_runner_integration_tests" }, { "swarming": { @@ -4364,7 +4376,7 @@ } ] }, - "test": "castrunner_unittests" + "test": "cast_runner_unittests" }, { "args": [ @@ -4563,7 +4575,7 @@ } ] }, - "test": "webrunner_browsertests" + "test": "web_runner_integration_tests" }, { "swarming": { @@ -4574,7 +4586,7 @@ } ] }, - "test": "webrunner_smoketests" + "test": "webrunner_browsertests" }, { "swarming": { @@ -6576,6 +6588,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -10721,6 +10739,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -12129,7 +12153,13 @@ } }, { + "args": [ + "--smoke-test-mode" + ], "isolate_name": "components_perftests", + "merge": { + "script": "//tools/perf/process_perf_results.py" + }, "name": "components_perftests", "swarming": { "can_use_on_swarming_builders": true, @@ -12224,6 +12254,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index e397e3ef..7347cb3 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -4655,13 +4655,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 4 }, "test": "dawn_end2end_tests" @@ -4809,13 +4802,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 4 }, "test": "angle_end2end_tests" @@ -4835,14 +4821,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "angle_unittests" }, @@ -4859,14 +4838,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "angle_white_box_tests" }, @@ -4884,13 +4856,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 4 }, "test": "dawn_end2end_tests" @@ -4908,14 +4873,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gl_tests" }, @@ -4932,14 +4890,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gl_unittests" }, @@ -4955,14 +4906,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gles2_conform_test" }, @@ -4975,14 +4919,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "swiftshader_unittests" } @@ -5009,14 +4946,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -5040,14 +4970,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -5071,14 +4994,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -5102,14 +5018,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -5137,14 +5046,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -5175,14 +5077,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -5221,14 +5116,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -5253,14 +5141,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -5284,14 +5165,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -5316,13 +5190,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 2 } }, @@ -5348,13 +5215,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 2 } } @@ -5905,13 +5765,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 4 }, "test": "angle_end2end_tests" @@ -5931,14 +5784,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "angle_unittests" }, @@ -5955,14 +5801,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "angle_white_box_tests" }, @@ -5980,13 +5819,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 4 }, "test": "dawn_end2end_tests" @@ -6004,14 +5836,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gl_tests" }, @@ -6028,14 +5853,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gl_unittests" }, @@ -6051,14 +5869,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gles2_conform_test" }, @@ -6071,14 +5882,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "swiftshader_unittests" } @@ -6099,14 +5903,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] } } ] @@ -7127,13 +6924,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 4 }, "test": "angle_end2end_tests" @@ -7153,14 +6943,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "angle_unittests" }, @@ -7177,14 +6960,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "angle_white_box_tests" }, @@ -7205,14 +6981,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "browser_tests" }, @@ -7230,13 +6999,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 4 }, "test": "dawn_end2end_tests" @@ -7254,14 +7016,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gl_tests" }, @@ -7278,14 +7033,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gl_unittests" }, @@ -7301,14 +7049,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gles2_conform_test" }, @@ -7321,14 +7062,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "swiftshader_unittests" } @@ -7349,14 +7083,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] } }, { @@ -7380,14 +7107,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -7411,14 +7131,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -7442,14 +7155,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -7473,14 +7179,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -7508,14 +7207,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -7546,14 +7238,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -7592,14 +7277,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -7624,14 +7302,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -7655,14 +7326,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -7689,13 +7353,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 20 } }, @@ -7723,13 +7380,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 20 } }, @@ -7755,13 +7405,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 2 } }, @@ -7787,13 +7430,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 2 } } @@ -7841,13 +7477,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 4 }, "test": "angle_deqp_egl_tests" @@ -7868,13 +7497,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 4 }, "test": "angle_deqp_gles2_tests" @@ -7895,13 +7517,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 6 }, "test": "angle_deqp_gles31_tests" @@ -7922,13 +7537,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 12 }, "test": "angle_deqp_gles3_tests" @@ -14889,13 +14497,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 4 }, "test": "angle_end2end_tests" @@ -14913,14 +14514,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "angle_white_box_tests" }, @@ -14938,13 +14532,6 @@ "pool": "Chrome-GPU" } ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 4 }, "test": "dawn_end2end_tests" @@ -14961,14 +14548,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gles2_conform_test" }, @@ -14981,14 +14561,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "swiftshader_unittests" } @@ -15009,14 +14582,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] } }, { @@ -15044,14 +14610,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -15078,13 +14637,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 20 } }, @@ -15110,13 +14662,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 2 } }
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json index b8204b1..cab33d5e 100644 --- a/testing/buildbot/chromium.gpu.json +++ b/testing/buildbot/chromium.gpu.json
@@ -297,14 +297,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "angle_unittests" }, @@ -321,14 +314,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gl_tests" }, @@ -345,14 +331,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gl_unittests" } @@ -379,14 +358,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -410,14 +382,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -441,14 +406,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -472,14 +430,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -507,14 +458,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -545,14 +489,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -591,14 +528,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -623,14 +553,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -654,14 +577,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -686,13 +602,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 2 } } @@ -715,14 +624,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "angle_unittests" }, @@ -743,14 +645,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "browser_tests" }, @@ -767,14 +662,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gl_tests" }, @@ -791,14 +679,7 @@ "os": "Ubuntu", "pool": "Chrome-GPU" } - ], - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + ] }, "test": "gl_unittests" } @@ -825,14 +706,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -856,14 +730,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -887,14 +754,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -918,14 +778,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -953,14 +806,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -991,14 +837,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -1037,14 +876,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -1069,14 +901,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -1100,14 +925,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -1132,13 +950,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 2 } }
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index 0b67a8d..366884b 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -677,7 +677,7 @@ } ] }, - "test": "castrunner_unittests" + "test": "cast_runner_unittests" }, { "args": [ @@ -1676,6 +1676,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -2386,6 +2392,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -3052,6 +3064,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -4302,6 +4320,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json index 34e76355..bfbe0aa0 100644 --- a/testing/buildbot/chromium.mac.json +++ b/testing/buildbot/chromium.mac.json
@@ -995,7 +995,13 @@ } }, { + "args": [ + "--smoke-test-mode" + ], "isolate_name": "components_perftests", + "merge": { + "script": "//tools/perf/process_perf_results.py" + }, "name": "components_perftests", "swarming": { "can_use_on_swarming_builders": true, @@ -1087,6 +1093,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true, @@ -2121,7 +2133,13 @@ } }, { + "args": [ + "--smoke-test-mode" + ], "isolate_name": "components_perftests", + "merge": { + "script": "//tools/perf/process_perf_results.py" + }, "name": "components_perftests", "swarming": { "can_use_on_swarming_builders": true, @@ -2213,6 +2231,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true, @@ -3330,7 +3354,13 @@ } }, { + "args": [ + "--smoke-test-mode" + ], "isolate_name": "components_perftests", + "merge": { + "script": "//tools/perf/process_perf_results.py" + }, "name": "components_perftests", "swarming": { "can_use_on_swarming_builders": true, @@ -3422,6 +3452,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true, @@ -4456,7 +4492,13 @@ } }, { + "args": [ + "--smoke-test-mode" + ], "isolate_name": "components_perftests", + "merge": { + "script": "//tools/perf/process_perf_results.py" + }, "name": "components_perftests", "swarming": { "can_use_on_swarming_builders": true, @@ -4529,6 +4571,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true, @@ -5632,6 +5680,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json index bcfe07b7..b85041d 100644 --- a/testing/buildbot/chromium.win.json +++ b/testing/buildbot/chromium.win.json
@@ -716,7 +716,13 @@ } }, { + "args": [ + "--smoke-test-mode" + ], "isolate_name": "components_perftests", + "merge": { + "script": "//tools/perf/process_perf_results.py" + }, "name": "components_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -781,6 +787,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -3371,6 +3383,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true, @@ -4098,7 +4116,13 @@ } }, { + "args": [ + "--smoke-test-mode" + ], "isolate_name": "components_perftests", + "merge": { + "script": "//tools/perf/process_perf_results.py" + }, "name": "components_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -4163,6 +4187,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true @@ -4943,6 +4973,12 @@ }, { "isolate_name": "views_perftests", + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, "name": "views_perftests", "swarming": { "can_use_on_swarming_builders": true
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json index 11c7a7e..d9d699d 100644 --- a/testing/buildbot/client.v8.fyi.json +++ b/testing/buildbot/client.v8.fyi.json
@@ -295,14 +295,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -326,14 +319,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -357,14 +343,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -388,14 +367,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -426,14 +398,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -472,14 +437,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -504,14 +462,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -535,14 +486,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -569,13 +513,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 20 } }, @@ -601,13 +538,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 2 } } @@ -636,14 +566,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -667,14 +590,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -698,14 +614,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -729,14 +638,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -767,14 +669,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -813,14 +708,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -845,14 +733,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -876,14 +757,7 @@ "pool": "Chrome-GPU" } ], - "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - } + "idempotent": false } }, { @@ -910,13 +784,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 20 } }, @@ -942,13 +809,6 @@ } ], "idempotent": false, - "optional_dimensions": { - "600": [ - { - "gpu": "10de:1cb3-410.78" - } - ] - }, "shards": 2 } }
diff --git a/testing/buildbot/filters/fuchsia.content_unittests.filter b/testing/buildbot/filters/fuchsia.content_unittests.filter index 0add8d92..d67a923 100644 --- a/testing/buildbot/filters/fuchsia.content_unittests.filter +++ b/testing/buildbot/filters/fuchsia.content_unittests.filter
@@ -4,16 +4,6 @@ -BluetoothBlocklistTest.InvalidUUID -WebBluetoothDeviceIdTest.DefaultConstructor -# These rely on chmod() for MakeFileUnread/writable(), https://crbug.com/759853. --BaseFileTest.ReadonlyBaseFile --BaseFileTest.RenameWithError --BaseFileTest.RenameWithErrorInProgress --BlobTransportControllerTest.Disk --DownloadFile/DownloadFileTestWithRename.RenameError/0 --DownloadFile/DownloadFileTestWithRename.RenameError/1 --DownloadFile/DownloadFileTestWithRename.RenameWithErrorRetry/0 --DownloadFile/DownloadFileTestWithRename.RenameWithErrorRetry/1 - # https://crbug.com/761214 -RendererAudioOutputStreamFactoryIntegrationTest.StreamIntegrationTest -WebContentsAudioInputStreamTest.MirroringNothingWithTargetChange/0
diff --git a/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter b/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter index 60b2ae90..0268573 100644 --- a/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter +++ b/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter
@@ -22,9 +22,6 @@ -org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testLoadDataShouldTriggerShouldInterceptRequest -org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testLoadDataUrlShouldTriggerShouldInterceptRequest -org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testLoadDataWithBaseUrlTriggersShouldInterceptRequest --org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testNotCalledForExistingAsset --org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testNotCalledForExistingContentUrl --org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testNotCalledForExistingResource -org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testNotCalledForHttpRedirect # https://crbug.com/893568
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index 2058182..ed949e3 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -411,16 +411,16 @@ "label": "//media/capture:capture_unittests", "type": "windowed_test_launcher", }, - "castrunner_browsertests": { - "label": "//fuchsia:castrunner_browsertests", + "cast_runner_browsertests": { + "label": "//fuchsia/runners:cast_runner_browsertests", "type": "console_test_launcher", }, - "castrunner_integration_tests": { - "label": "//fuchsia:castrunner_integration_tests", + "cast_runner_integration_tests": { + "label": "//fuchsia/runners:cast_runner_integration_tests", "type": "console_test_launcher", }, - "castrunner_unittests": { - "label": "//fuchsia:castrunner_unittests", + "cast_runner_unittests": { + "label": "//fuchsia/runners:cast_runner_unittests", "type": "console_test_launcher", }, "cast_audio_backend_unittests": { @@ -649,6 +649,9 @@ "components_perftests": { "args": [ "--xvfb", + "--benchmark=components_perftests", + "--non-telemetry=true", + "--migrated-test=true", "components_perftests", ], "label": "//components:components_perftests", @@ -2575,6 +2578,9 @@ "views_perftests": { "args": [ "--xvfb", + "--benchmark=views_perftests", + "--non-telemetry=true", + "--migrated-test=true", "views_perftests", ], "label": "//ui/views:views_perftests", @@ -2657,6 +2663,10 @@ "label": "//third_party/blink/renderer/platform:web_icon_sizes_fuzzer", "type": "fuzzer", }, + "web_runner_integration_tests": { + "label": "//fuchsia/runners:web_runner_integration_tests", + "type": "console_test_launcher", + }, "webapk_client_junit_tests": { "label": "//chrome/android/webapk/libs/client:webapk_client_junit_tests", "type": "junit_test", @@ -2738,10 +2748,6 @@ "label": "//fuchsia:webrunner_browsertests", "type": "console_test_launcher", }, - "webrunner_smoketests": { - "label": "//fuchsia:webrunner_smoketests", - "type": "console_test_launcher", - }, "webrunner_unittests": { "label": "//fuchsia:webrunner_unittests", "type": "console_test_launcher",
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index ac0ea191..9598a2d 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl
@@ -273,21 +273,6 @@ }, }, }, - # TODO(jmadill): Remove this after upgrade. http://crbug.com/887241 - 'linux_nvidia_quadro_p400_upgrade': { - 'swarming': { - 'optional_dimensions': { - # Wait 10 minutes for this new driver version and then fall back to the - # current "stable" driver version. The format for optional dimensions - # is: expiration: [{key, value}, ..]. - 600: [ - { - 'gpu': '10de:1cb3-410.78', - } - ], - }, - } - }, 'lollipop': { 'swarming': { 'dimensions': {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 0c8abf3..09be9f0 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -233,6 +233,20 @@ }, }, }, + 'cast_runner_browsertests': { + # TODO(crbug.com/910799): Enable this once we're confident that it + # passes. + 'remove_from': [ + # chromium.linux + 'Fuchsia x64', + ], + }, + 'cast_runner_integration_tests': { + 'remove_from': [ + # chromium.linux + 'Fuchsia x64', # TODO(https://crbug.com/918586): Flaky install failures. + ], + }, 'cast_shell_browsertests': { 'modifications': { 'Cast Audio Linux': { @@ -259,20 +273,6 @@ }, }, }, - 'castrunner_browsertests': { - # TODO(crbug.com/910799): Enable this once we're confident that it - # passes. - 'remove_from': [ - # chromium.linux - 'Fuchsia x64', - ], - }, - 'castrunner_integration_tests': { - 'remove_from': [ - # chromium.linux - 'Fuchsia x64', # TODO(https://crbug.com/918586): Flaky install failures. - ], - }, 'checkbins': { 'remove_from': [ 'linux-dbg', @@ -663,6 +663,25 @@ }, }, }, + 'monochrome_public_test_ar_apk': { + 'modifications': { + # chromium.android + # We need to match the Playstore version as well because AR tests fail on + # old versions of the Playstore. + 'Oreo Phone Tester': { + 'swarming': { + 'dimension_sets': [ + { + 'device_os': 'OPR3.170623.008', + 'device_playstore_version': '12.8.23-all', + 'device_type': 'marlin', + 'os': 'Android', + }, + ], + }, + }, + }, + }, 'nacl_helper_nonsfi_unittests': { 'remove_from': [ # chromium.memory @@ -1317,6 +1336,12 @@ 'linux-chromeos-dbg', # https://crbug.com/859307 ], }, + 'web_runner_integration_tests': { + 'remove_from': [ + # chromium.linux + 'Fuchsia x64', # TODO(https://crbug.com/918586): Flaky install failures. + ], + }, 'webgl2_conformance_tests': { 'remove_from': [ # The Mac NVIDIA Retina bots don't have the capacity to run @@ -1677,12 +1702,6 @@ 'Fuchsia x64', # TODO(https://crbug.com/918586): Flaky install failures. ], }, - 'webrunner_smoketests': { - 'remove_from': [ - # chromium.linux - 'Fuchsia x64', # TODO(https://crbug.com/918586): Flaky install failures. - ], - }, 'webui_polymer2_browser_tests': { 'remove_from': [ # chromium.win
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 409cd30..e4480194 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -2650,7 +2650,14 @@ }, 'components_perftests_isolated_scripts' : { - 'components_perftests': {}, + 'components_perftests': { + 'merge': { + 'script': '//tools/perf/process_perf_results.py', + }, + 'args': [ + '--smoke-test-mode', + ], + }, }, 'cronet_gtests': { @@ -2693,7 +2700,14 @@ 'shards': 4, }, }, - 'views_perftests': {}, + 'views_perftests': { + 'merge': { + 'script': '//tools/perf/process_perf_results.py', + 'args': [ + '--smoke-test-mode', + ], + }, + }, 'webkit_layout_tests': { # layout test failures are retried 3 times when '--test-list' is not # passed, but 0 times when '--test-list' is passed. We want to always @@ -2718,9 +2732,9 @@ 'fuchsia_gtests': { 'base_unittests': {}, - 'castrunner_browsertests': {}, - 'castrunner_integration_tests': {}, - 'castrunner_unittests': {}, + 'cast_runner_browsertests': {}, + 'cast_runner_integration_tests': {}, + 'cast_runner_unittests': {}, 'content_unittests': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.content_unittests.filter', @@ -2753,8 +2767,8 @@ '--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.ui_base_unittests.filter', ], }, + 'web_runner_integration_tests': {}, 'webrunner_browsertests': {}, - 'webrunner_smoketests': {}, 'webrunner_unittests': {}, },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index f1a2bfb..185bbdd8 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -665,6 +665,11 @@ { 'name': 'chromium.chromiumos', 'machines': { + 'chromeos-amd64-generic-cfi-thin-lto-rel': { + 'additional_compile_targets': [ + 'chromiumos_preflight', + ], + }, 'chromeos-amd64-generic-rel': { 'additional_compile_targets': [ 'chromiumos_preflight', @@ -1793,7 +1798,6 @@ 'os_type': 'linux', 'mixins': [ 'linux_nvidia_quadro_p400', - 'linux_nvidia_quadro_p400_upgrade', ], 'test_suites': { 'gtest_tests': 'gpu_desktop_gtests', @@ -1805,7 +1809,6 @@ 'os_type': 'linux', 'mixins': [ 'linux_nvidia_quadro_p400', - 'linux_nvidia_quadro_p400_upgrade', ], 'test_suites': { 'gtest_tests': 'gpu_desktop_gtests', @@ -2179,7 +2182,6 @@ 'browser_config': 'release', 'mixins': [ 'linux_nvidia_quadro_p400', - 'linux_nvidia_quadro_p400_upgrade', ], 'test_suites': { 'gtest_tests': 'gpu_dawn_end2end_tests', @@ -2254,7 +2256,6 @@ 'os_type': 'linux', 'mixins': [ 'linux_nvidia_quadro_p400', - 'linux_nvidia_quadro_p400_upgrade', ], 'test_suites': { 'gtest_tests': 'gpu_fyi_linux_debug_gtests', @@ -2279,7 +2280,6 @@ 'os_type': 'linux', 'mixins': [ 'linux_nvidia_quadro_p400', - 'linux_nvidia_quadro_p400_upgrade', ], 'test_suites': { # This bot doesn't run any browser-based tests @@ -2330,7 +2330,6 @@ 'browser_config': 'release', 'mixins': [ 'linux_nvidia_quadro_p400', - 'linux_nvidia_quadro_p400_upgrade', ], 'test_suites': { 'gtest_tests': 'gpu_fyi_linux_release_gtests', @@ -2353,7 +2352,6 @@ 'browser_config': 'release', 'mixins': [ 'linux_nvidia_quadro_p400', - 'linux_nvidia_quadro_p400_upgrade', ], 'test_suites': { 'gtest_tests': 'gpu_angle_deqp_linux_nvidia_gtests', @@ -2589,7 +2587,6 @@ 'browser_config': 'release', 'mixins': [ 'linux_nvidia_quadro_p400', - 'linux_nvidia_quadro_p400_upgrade', ], 'test_suites': { 'gtest_tests': 'gpu_fyi_linux_optional_gtests', @@ -3686,7 +3683,6 @@ 'browser_config': 'release', 'mixins': [ 'linux_nvidia_quadro_p400', - 'linux_nvidia_quadro_p400_upgrade', ], 'test_suites': { 'gpu_telemetry_tests': 'gpu_v8_desktop_telemetry_tests', @@ -3697,7 +3693,6 @@ 'browser_config': 'release', 'mixins': [ 'linux_nvidia_quadro_p400', - 'linux_nvidia_quadro_p400_upgrade', ], 'test_suites': { 'gpu_telemetry_tests': 'gpu_v8_desktop_telemetry_tests',
diff --git a/testing/iossim/iossim.mm b/testing/iossim/iossim.mm index eea905e..a6ac57b 100644 --- a/testing/iossim/iossim.mm +++ b/testing/iossim/iossim.mm
@@ -306,11 +306,11 @@ forKey:@"TestingEnvironmentVariables"]; [xctestrun setObject:testTargetName forKey:@"TestTargetName"]; - NSString* error; NSData* data = [NSPropertyListSerialization - dataFromPropertyList:xctestrun + dataWithPropertyList:xctestrun format:NSPropertyListXMLFormat_v1_0 - errorDescription:&error]; + options:0 + error:nil]; [data writeToFile:tempFilePath atomically:YES]; XCRunTask* task = [[[XCRunTask alloc] initWithArguments:@[ @"xcodebuild", @"-xctestrun", tempFilePath, @"-destination",
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index c7bfbac..6fab0b27 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -646,6 +646,26 @@ ] } ], + "AutofillEnableCompanyName": [ + { + "platforms": [ + "android", + "chromeos", + "ios", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Disabled", + "disable_features": [ + "AutofillEnableCompanyName" + ] + } + ] + } + ], "AutofillFieldMetadata": [ { "platforms": [ @@ -2763,8 +2783,7 @@ "target_engagement_score_scale": "100" }, "enable_features": [ - "RecordAnchorMetricsClicked", - "RecordAnchorMetricsVisible" + "NavigationPredictor" ] } ] @@ -3729,6 +3748,109 @@ ] } ], + "QuotaExpandPoolSize": [ + { + "platforms": [ + "android", + "ios", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled_Pool_TwoThirds_Origin_OneFifth", + "params": { + "PerHostPortion": "0.2", + "PoolSizeRatio": "0.6666666666666666" + }, + "enable_features": [ + "QuotaExpandPoolSize" + ] + }, + { + "name": "Enabled_Pool_ThreeQuarters_Origin_OneFifth", + "params": { + "PerHostPortion": "0.2", + "PoolSizeRatio": "0.75" + }, + "enable_features": [ + "QuotaExpandPoolSize" + ] + }, + { + "name": "Enabled_Pool_Full_Origin_OneFifth", + "params": { + "PerHostPortion": "0.2", + "PoolSizeRatio": "1.0" + }, + "enable_features": [ + "QuotaExpandPoolSize" + ] + }, + { + "name": "Enabled_Pool_TwoThirds_Origin_OneHalf", + "params": { + "PerHostPortion": "0.5", + "PoolSizeRatio": "0.6666666666666666" + }, + "enable_features": [ + "QuotaExpandPoolSize" + ] + }, + { + "name": "Enabled_Pool_ThreeQuarters_Origin_OneHalf", + "params": { + "PerHostPortion": "0.5", + "PoolSizeRatio": "0.75" + }, + "enable_features": [ + "QuotaExpandPoolSize" + ] + }, + { + "name": "Enabled_Pool_Full_Origin_OneHalf", + "params": { + "PerHostPortion": "0.5", + "PoolSizeRatio": "1.0" + }, + "enable_features": [ + "QuotaExpandPoolSize" + ] + }, + { + "name": "Enabled_Pool_TwoThirds_Origin_TwoThirds", + "params": { + "PerHostPortion": "0.6666666666666666", + "PoolSizeRatio": "0.6666666666666666" + }, + "enable_features": [ + "QuotaExpandPoolSize" + ] + }, + { + "name": "Enabled_Pool_ThreeQuarters_Origin_TwoThirds", + "params": { + "PerHostPortion": "0.6666666666666666", + "PoolSizeRatio": "0.75" + }, + "enable_features": [ + "QuotaExpandPoolSize" + ] + }, + { + "name": "Enabled_Pool_Full_Origin_TwoThirds", + "params": { + "PerHostPortion": "0.6666666666666666", + "PoolSizeRatio": "1.0" + }, + "enable_features": [ + "QuotaExpandPoolSize" + ] + } + ] + } + ], "ReaderModeUI": [ { "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 5cffbd72..33fe8134 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -60,6 +60,15 @@ const base::Feature kMojoBlobURLs{"MojoBlobURLs", base::FEATURE_DISABLED_BY_DEFAULT}; +// Used to control the collection of anchor element metrics (crbug.com/856683). +// If kNavigationPredictor is enabled, then metrics of anchor elements +// in the first viewport after the page load and the metrics of the clicked +// anchor element will be extracted and recorded. Additionally, navigation +// predictor may preconnect/prefetch to resources/origins to make the +// future navigations faster. +const base::Feature kNavigationPredictor{"NavigationPredictor", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Onion souping for all DOMStorage. https://crbug.com/781870 const base::Feature kOnionSoupDOMStorage{"OnionSoupDOMStorage", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -95,16 +104,6 @@ const base::Feature kRTCOfferExtmapAllowMixed{ "RTCOfferExtmapAllowMixed", base::FEATURE_DISABLED_BY_DEFAULT}; -// Used to control the collection of anchor element metrics (crbug.com/856683). -// If kRecordAnchorMetricsClicked is enabled, then metrics of anchor elements -// clicked by the user will be extracted and recorded. -// If kRecordAnchorMetricsVisible is enabled, then metrics of anchor elements -// in the first viewport after the page load will be extracted and recorded. -const base::Feature kRecordAnchorMetricsClicked{ - "RecordAnchorMetricsClicked", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kRecordAnchorMetricsVisible{ - "RecordAnchorMetricsVisible", base::FEATURE_DISABLED_BY_DEFAULT}; - // Enables to load the response body through Mojo data pipe passed by // WebURLLoaderClient::DidStartLoadingResponseBody() instead of // WebURLLoaderClient::DidReceiveData().
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn index 115b7ff6..e8fd60e 100644 --- a/third_party/blink/public/BUILD.gn +++ b/third_party/blink/public/BUILD.gn
@@ -812,10 +812,13 @@ # The web_feature_mojo_bindings is separated from the rest of the mojom files # because the chromium typemap for blink mojo_bindings has private content # dependencies. -mojom("web_feature_mojo_bindings") { +mojom_component("web_feature_mojo_bindings") { sources = [ "platform/web_feature.mojom", ] + + macro_prefix = "WEB_FEATURE_MOJO_BINDINGS_MOJOM" + output_prefix = "web_feature_mojo_bindings_mojom" } # The web_feature_mojo_bindings is separated from the rest of the mojom files
diff --git a/third_party/blink/public/OWNERS b/third_party/blink/public/OWNERS index afff5d3..499cd80 100644 --- a/third_party/blink/public/OWNERS +++ b/third_party/blink/public/OWNERS
@@ -1,7 +1,6 @@ chrishtr@chromium.org dcheng@chromium.org dgozman@chromium.org -dstockwell@chromium.org foolip@chromium.org haraken@chromium.org japhet@chromium.org
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 56cbc9b..ce0bbdc 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -26,14 +26,13 @@ BLINK_COMMON_EXPORT extern const base::Feature kLayoutNG; BLINK_COMMON_EXPORT extern const base::Feature kMixedContentAutoupgrade; BLINK_COMMON_EXPORT extern const base::Feature kMojoBlobURLs; +BLINK_COMMON_EXPORT extern const base::Feature kNavigationPredictor; BLINK_COMMON_EXPORT extern const base::Feature kOnionSoupDOMStorage; BLINK_COMMON_EXPORT extern const base::Feature kPlzDedicatedWorker; BLINK_COMMON_EXPORT extern const base::Feature kPortals; BLINK_COMMON_EXPORT extern const base::Feature kRTCGetDisplayMedia; BLINK_COMMON_EXPORT extern const base::Feature kRTCUnifiedPlanByDefault; BLINK_COMMON_EXPORT extern const base::Feature kRTCOfferExtmapAllowMixed; -BLINK_COMMON_EXPORT extern const base::Feature kRecordAnchorMetricsClicked; -BLINK_COMMON_EXPORT extern const base::Feature kRecordAnchorMetricsVisible; BLINK_COMMON_EXPORT extern const base::Feature kResourceLoadViaDataPipe; BLINK_COMMON_EXPORT extern const base::Feature kServiceWorkerImportedScriptUpdateCheck;
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn index ed48b04..731da16b 100644 --- a/third_party/blink/public/mojom/BUILD.gn +++ b/third_party/blink/public/mojom/BUILD.gn
@@ -153,10 +153,13 @@ # Kept separate from "mojom_platform" because the Java bindings are needed by # Android's implementation of speech recognition. -mojom("speech_recognition_error_code") { +mojom_component("speech_recognition_error_code") { sources = [ "speech/speech_recognition_error_code.mojom", ] + + macro_prefix = "SPEECH_RECOGNITION_ERROR_CODE_MOJOM" + output_prefix = "speech_recognition_error_code_mojom" } # This target can include mojom interfaces which do use types that are
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom index f58f9ed..53a844c36 100644 --- a/third_party/blink/public/platform/web_feature.mojom +++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1521,11 +1521,6 @@ kReportUriMultipleEndpoints = 2052, kReportUriSingleEndpoint = 2053, kV8ConstructorNonUndefinedPrimitiveReturn = 2054, - kEncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe = 2055, - kGeolocationDisallowedByFeaturePolicyInCrossOriginIframe = 2056, - kGetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe = 2057, - kGetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe = 2058, - kRequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe = 2059, kMediaSourceKeyframeTimeGreaterThanDependant = 2060, kMediaSourceMuxedSequenceMode = 2061, kPrepareModuleScript = 2062,
diff --git a/third_party/blink/public/web/web_ax_object.h b/third_party/blink/public/web/web_ax_object.h index 58d439e..7dee9992 100644 --- a/third_party/blink/public/web/web_ax_object.h +++ b/third_party/blink/public/web/web_ax_object.h
@@ -159,6 +159,7 @@ BLINK_EXPORT WebString FontFamily() const; BLINK_EXPORT float FontSize() const; BLINK_EXPORT bool CanvasHasFallbackContent() const; + BLINK_EXPORT WebAXObject ErrorMessage() const; // If this is an image, returns the image (scaled to maxSize) as a data url. BLINK_EXPORT WebString ImageDataUrl(const WebSize& max_size) const; BLINK_EXPORT WebAXRestriction Restriction() const;
diff --git a/third_party/blink/public/web/web_remote_frame_client.h b/third_party/blink/public/web/web_remote_frame_client.h index 793b2c2e..f9a76268 100644 --- a/third_party/blink/public/web/web_remote_frame_client.h +++ b/third_party/blink/public/web/web_remote_frame_client.h
@@ -40,6 +40,7 @@ virtual void Navigate(const WebURLRequest& request, bool should_replace_current_entry, bool is_opener_navigation, + bool prevent_sandboxed_download, mojo::ScopedMessagePipeHandle blob_url_token) {} virtual void FrameRectsChanged(const WebRect& local_frame_rect,
diff --git a/third_party/blink/public/web/web_settings.h b/third_party/blink/public/web/web_settings.h index b476d40e..777a62f3 100644 --- a/third_party/blink/public/web/web_settings.h +++ b/third_party/blink/public/web/web_settings.h
@@ -152,6 +152,7 @@ virtual void SetDownloadableBinaryFontsEnabled(bool) = 0; virtual void SetEditingBehavior(EditingBehavior) = 0; virtual void SetEnableScrollAnimator(bool) = 0; + virtual void SetPrefersReducedMotion(bool) = 0; virtual void SetEnableTouchAdjustment(bool) = 0; virtual void SetSmoothScrollForFindEnabled(bool) = 0; virtual void SetWebGL1Enabled(bool) = 0;
diff --git a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md index b28129c7..63ac8fa 100644 --- a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md +++ b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
@@ -222,7 +222,7 @@ Whether you should allow an interface to have constructor depends on the spec of the interface. *** note -Currently `[Constructor(...)]` does not yet support optional arguments w/o defaults. It just supports optional `[Default=Undefined]`. +Currently `[Constructor(...)]` does not yet support optional arguments w/o defaults. It just supports optional `[DefaultValue=Undefined]`. *** ### [EnforceRange] _(t)_ @@ -948,29 +948,6 @@ [HighEntropy, Measure] const INTERESTING_CONSTANT = 1; ``` -### [Default] _(p)_ - -Summary: `[Default]` allows one to specify the default values for optional arguments. This removes the need to have C++ overloads in the Blink implementation. - -Standard: In Web IDL, [default values for optional arguments](https://heycam.github.io/webidl/#dfn-optional-argument-default-value) are written as `optional type identifier = value`. Blink supports this but not all implementations have been updated to handle overloaded functions - see [bug 258153](https://crbug.com/258153). `[Default=Undefined]` was added to all optional parameters to preserve compatibility until the C++ implementations are updated. - -Usage: `[Default=Undefined]` can be specified on any optional parameter: - -```webidl -interface HTMLFoo { - void func1(long a, long b, optional long c, optional long d); - void func2(long a, long b, [Default=Undefined] optional long c); -}; -``` - -The parameters marked with the standard Web IDL `optional` qualifier are optional, and JavaScript can omit the parameters. Obviously, if parameter X is marked with `optional` then all subsequent parameters of X should be marked with `optional`. - -The difference between `optional` and `[Default=Undefined]` optional is whether the Blink implementation requires overloaded methods or not: without a default value, the Blink implementation must have overloaded C++ functions, while with a default value, the Blink implementation only needs a single C++ function. - -In case of func1(...), if JavaScript calls func1(100, 200), then `HTMLFoo::func1(int a, int b)` is called in Blink. If JavaScript calls `func1(100, 200, 300)`, then `HTMLFoo::func1(int a, int b, int c)` is called in Blink. If JavaScript calls `func1(100, 200, 300, 400)`, then `HTMLFoo::func1(int a, int b, int c, int d)` is called in Blink. In other words, if the Blink implementation has overloaded methods, you can use `optional`. - -In case of func2(...) which adds `[Default=Undefined]`, if JavaScript calls `func2(100, 200)`, then it behaves as if JavaScript called `func2(100, 200, undefined)`. Consequently, `HTMLFoo::func2(int a, int b, int c)` is called in Blink. 100 is passed to `a`, 200 is passed to `b`, and 0 is passed to `c`. (A JavaScript `undefined` is converted to 0, following the value conversion rule in the Web IDL spec; if it were a DOMString parameter, it would end up as the string `"undefined"`.) In this way, Blink needs to just implement `func2(int a, int b, int c)` and needs not to implement both `func2(int a, int b)` and `func2(int a, int b, int c)`. - ### [DeprecateAs] _(m, a, c)_ Summary: Measures usage of a deprecated feature via UseCounter, and notifies developers about deprecation via a console warning. @@ -1576,6 +1553,30 @@ ``` +### [DefaultValue] _(p)_ + +Summary: `[DefaultValue]` allows one to specify the default values for optional arguments. This removes the need to have C++ overloads in the Blink implementation. + +Standard: In Web IDL, [default values for optional arguments](https://heycam.github.io/webidl/#dfn-optional-argument-default-value) are written as `optional type identifier = value`. Blink supports this but not all implementations have been updated to handle overloaded functions - see [bug 258153](https://crbug.com/258153). `[DefaultValue=Undefined]` was added to all optional parameters to preserve compatibility until the C++ implementations are updated. + +Usage: `[DefaultValue=Undefined]` can be specified on any optional parameter: + +```webidl +interface HTMLFoo { + void func1(long a, long b, optional long c, optional long d); + void func2(long a, long b, [DefaultValue=Undefined] optional long c); +}; +``` + +The parameters marked with the standard Web IDL `optional` qualifier are optional, and JavaScript can omit the parameters. Obviously, if parameter X is marked with `optional` then all subsequent parameters of X should be marked with `optional`. + +The difference between `optional` and `[DefaultValue=Undefined]` optional is whether the Blink implementation requires overloaded methods or not: without a default value, the Blink implementation must have overloaded C++ functions, while with a default value, the Blink implementation only needs a single C++ function. + +In case of `func1(...)`, if JavaScript calls `func1(100, 200)`, then `HTMLFoo::func1(int a, int b)` is called in Blink. If JavaScript calls `func1(100, 200, 300)`, then `HTMLFoo::func1(int a, int b, int c)` is called in Blink. If JavaScript calls `func1(100, 200, 300, 400)`, then `HTMLFoo::func1(int a, int b, int c, int d)` is called in Blink. In other words, if the Blink implementation has overloaded methods, you can use `optional` without `[DefaultValue=Undefined]`. + +In case of `func2(...)` which adds `[DefaultValue=Undefined]`, if JavaScript calls `func2(100, 200)`, then it behaves as if JavaScript called `func2(100, 200, undefined)`. Consequently, `HTMLFoo::func2(int a, int b, int c)` is called in Blink. 100 is passed to `a`, 200 is passed to `b`, and 0 is passed to `c`. (A JavaScript `undefined` is converted to 0, following the value conversion rule in the Web IDL spec; if it were a DOMString parameter, it would end up as the string `"undefined"`.) In this way, Blink needs to just implement `func2(int a, int b, int c)` and needs not to implement both `func2(int a, int b)` and `func2(int a, int b, int c)`. + + ## Discouraged Blink-specific IDL Extended Attributes These extended attributes are _discouraged_ - they are not deprecated, but they should be avoided and removed if possible.
diff --git a/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt b/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt index 3dffa32..4d7403c 100644 --- a/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt +++ b/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
@@ -37,7 +37,7 @@ CEReactions CachedAccessor CachedAttribute=* -CallWith=CurrentWindow|EnteredWindow|ExecutionContext|Isolate|ScriptArguments|ScriptState|ThisValue +CallWith=CurrentWindow|EnteredWindow|ExecutionContext|Isolate|ScriptState|ThisValue CheckSecurity=Receiver|ReturnValue Clamp Constructor @@ -49,7 +49,7 @@ Custom=|Getter|Setter|LegacyCallAsFunction|PropertyGetter|PropertyEnumerator|PropertyQuery|CallPrologue|CallEpilogue CustomConstructor CustomElementCallbacks -Default=Undefined +DefaultValue=Undefined DeprecateAs=* DoNotCheckConstants DoNotTestNewObject @@ -89,16 +89,16 @@ ReflectOnly=* Replaceable # Valid values for [RuntimeEnabled] are the Runtime Enabled Features, listed in -# Source/platform/runtime_enabled_features.json5 +# third_party/blink/renderer/platform/runtime_enabled_features.json5 RuntimeEnabled=* # Valid values for [RuntimeCallStatsCounter] are counters defined in -# Source/platform/bindings/RuntimeCallStats.h +# third_party/blink/renderer/platform/bindings/runtime_call_stats.h RuntimeCallStatsCounter=* SameObject SaveSameObject SecureContext=|* Serializable -SetterCallWith=ExecutionContext|ScriptState|ScriptArguments|CurrentWindow|EnteredWindow +SetterCallWith=CurrentWindow|EnteredWindow|ExecutionContext|Isolate|ScriptState Transferable TreatNonObjectAsNull TreatNullAs=EmptyString
diff --git a/third_party/blink/renderer/bindings/scripts/v8_interface.py b/third_party/blink/renderer/bindings/scripts/v8_interface.py index e3c8373..5dcbc51f 100644 --- a/third_party/blink/renderer/bindings/scripts/v8_interface.py +++ b/third_party/blink/renderer/bindings/scripts/v8_interface.py
@@ -685,13 +685,13 @@ generated_iterator_method('keys'), entries_or_values_method, - # void forEach(Function callback, [Default=Undefined] optional any thisArg) + # void forEach(Function callback, [DefaultValue=Undefined] optional any thisArg) generated_method(IdlType('void'), 'forEach', # TODO(yukishiino): |callback| should be type of Function. arguments=[generated_argument(IdlType('CallbackFunctionTreatedAsScriptValue'), 'callback'), generated_argument(IdlType('any'), 'thisArg', is_optional=True, - extended_attributes={'Default': 'Undefined'})], + extended_attributes={'DefaultValue': 'Undefined'})], extended_attributes=forEach_extended_attributes), ])
diff --git a/third_party/blink/renderer/bindings/scripts/v8_methods.py b/third_party/blink/renderer/bindings/scripts/v8_methods.py index cbd6848c..f63b86a 100644 --- a/third_party/blink/renderer/bindings/scripts/v8_methods.py +++ b/third_party/blink/renderer/bindings/scripts/v8_methods.py
@@ -139,10 +139,6 @@ this_cpp_value = cpp_value(interface, method, len(arguments)) - is_call_with_script_arguments = has_extended_attribute_value(method, 'CallWith', 'ScriptArguments') - if is_call_with_script_arguments: - includes.update(['bindings/core/v8/script_call_stack.h', - 'core/inspector/script_arguments.h']) is_call_with_script_state = has_extended_attribute_value(method, 'CallWith', 'ScriptState') is_call_with_this_value = has_extended_attribute_value(method, 'CallWith', 'ThisValue') if is_call_with_script_state or is_call_with_this_value: @@ -210,7 +206,6 @@ if argument_context['is_optional_without_default_value']), 'idl_type': idl_type.base_type, 'is_call_with_execution_context': has_extended_attribute_value(method, 'CallWith', 'ExecutionContext'), - 'is_call_with_script_arguments': is_call_with_script_arguments, 'is_call_with_script_state': is_call_with_script_state, 'is_call_with_this_value': is_call_with_this_value, 'is_ce_reactions': is_ce_reactions, @@ -288,8 +283,9 @@ 'enum_type': idl_type.enum_type, 'enum_values': idl_type.enum_values, 'handle': '%s_handle' % snake_case_name, - # FIXME: remove once [Default] removed and just use argument.default_value - 'has_default': 'Default' in extended_attributes or set_default_value, + # TODO(peria): remove once [DefaultValue] removed and just use + # argument.default_value. https://crbug.com/924419 + 'has_default': 'DefaultValue' in extended_attributes or set_default_value, 'has_type_checking_interface': has_type_checking_interface, # Dictionary is special-cased, but arrays and sequences shouldn't be 'idl_type': idl_type.base_type,
diff --git a/third_party/blink/renderer/bindings/scripts/v8_utilities.py b/third_party/blink/renderer/bindings/scripts/v8_utilities.py index 0bad0fe..34808495 100644 --- a/third_party/blink/renderer/bindings/scripts/v8_utilities.py +++ b/third_party/blink/renderer/bindings/scripts/v8_utilities.py
@@ -209,7 +209,6 @@ 'Isolate': 'info.GetIsolate()', 'ScriptState': 'script_state', 'ExecutionContext': 'execution_context', - 'ScriptArguments': 'script_arguments', 'CurrentWindow': 'CurrentDOMWindow(info.GetIsolate())', 'EnteredWindow': 'EnteredDOMWindow(info.GetIsolate())', 'Document': 'document', @@ -220,7 +219,6 @@ 'Isolate', 'ScriptState', 'ExecutionContext', - 'ScriptArguments', 'CurrentWindow', 'EnteredWindow', 'Document',
diff --git a/third_party/blink/renderer/bindings/templates/methods.cc.tmpl b/third_party/blink/renderer/bindings/templates/methods.cc.tmpl index cf9d117..f2250dc 100644 --- a/third_party/blink/renderer/bindings/templates/methods.cc.tmpl +++ b/third_party/blink/renderer/bindings/templates/methods.cc.tmpl
@@ -264,10 +264,6 @@ ExecutionContext* execution_context = ExecutionContext::ForRelevantRealm(info); {% endif %} {% endif %} -{% if method.is_call_with_script_arguments %} -{# [CallWith=ScriptArguments] #} -ScriptArguments* scriptArguments(ScriptArguments::Create(script_state, info, {{method.number_of_arguments}})); -{% endif %} {% if method.is_call_with_document %} {# [ConstructorCallWith=Document] #} Document& document = *To<Document>(ToExecutionContext(
diff --git a/third_party/blink/renderer/bindings/tests/idls/core/test_interface_constructor.idl b/third_party/blink/renderer/bindings/tests/idls/core/test_interface_constructor.idl index c82b6eb0..ff6a42b 100644 --- a/third_party/blink/renderer/bindings/tests/idls/core/test_interface_constructor.idl +++ b/third_party/blink/renderer/bindings/tests/idls/core/test_interface_constructor.idl
@@ -41,7 +41,7 @@ sequence<(long or TestDictionary)> sequenceLongOrTestDictionaryArg, optional USVString? optionalUSVStringArg, optional Dictionary optionalDictionaryArg, - [Default=Undefined] optional TestInterfaceEmpty optionalTestInterfaceEmptyArg), + [DefaultValue=Undefined] optional TestInterfaceEmpty optionalTestInterfaceEmptyArg), Constructor(DOMString arg, optional DOMString optArg), Constructor(DOMString arg, DOMString arg2, DOMString arg3), NamedConstructor=Audio(DOMString arg, optional DOMString optArg),
diff --git a/third_party/blink/renderer/bindings/tests/idls/core/test_interface_constructor_2.idl b/third_party/blink/renderer/bindings/tests/idls/core/test_interface_constructor_2.idl index 097b27c9..92ff6ff 100644 --- a/third_party/blink/renderer/bindings/tests/idls/core/test_interface_constructor_2.idl +++ b/third_party/blink/renderer/bindings/tests/idls/core/test_interface_constructor_2.idl
@@ -33,7 +33,7 @@ // and for overloaded vs. non-overloaded, if length > 0. // length == 0, non-overloaded just omits a block and is not worth another test. // -// Also includes some [Default] arguments (instead of in +// Also includes some [DefaultValue] arguments (instead of in // TestInterfaceConstructor.idl), otherwise overload resolution check string is // extremely long and triggers a lint warning (line length). [ @@ -44,9 +44,9 @@ Constructor( TestInterfaceEmpty testInterfaceEmptyArg, long longArg, - [Default=Undefined] optional DOMString defaultUndefinedOptionalStringArg, + [DefaultValue=Undefined] optional DOMString defaultUndefinedOptionalStringArg, optional DOMString defaultNullStringOptionalStringArg = null, - [Default=Undefined] optional Dictionary defaultUndefinedOptionalDictionaryArg, + [DefaultValue=Undefined] optional Dictionary defaultUndefinedOptionalDictionaryArg, optional DOMString optionalStringArg) ] interface TestInterfaceConstructor2 { };
diff --git a/third_party/blink/renderer/bindings/tests/idls/core/test_interface_named_constructor.idl b/third_party/blink/renderer/bindings/tests/idls/core/test_interface_named_constructor.idl index 8f64cf61..7ec7bdc 100644 --- a/third_party/blink/renderer/bindings/tests/idls/core/test_interface_named_constructor.idl +++ b/third_party/blink/renderer/bindings/tests/idls/core/test_interface_named_constructor.idl
@@ -30,9 +30,9 @@ ActiveScriptWrappable, NamedConstructor=Audio( DOMString stringArg, - [Default=Undefined] optional boolean defaultUndefinedOptionalBooleanArg, - [Default=Undefined] optional long defaultUndefinedOptionalLongArg, - [Default=Undefined] optional DOMString defaultUndefinedOptionalStringArg, + [DefaultValue=Undefined] optional boolean defaultUndefinedOptionalBooleanArg, + [DefaultValue=Undefined] optional long defaultUndefinedOptionalLongArg, + [DefaultValue=Undefined] optional DOMString defaultUndefinedOptionalStringArg, optional DOMString defaultNullStringOptionalstringArg = null, optional DOMString optionalStringArg), ConstructorCallWith=Document,
diff --git a/third_party/blink/renderer/bindings/tests/idls/core/test_object.idl b/third_party/blink/renderer/bindings/tests/idls/core/test_object.idl index 2dab559..b329c9b 100644 --- a/third_party/blink/renderer/bindings/tests/idls/core/test_object.idl +++ b/third_party/blink/renderer/bindings/tests/idls/core/test_object.idl
@@ -443,27 +443,26 @@ [RaisesException, CallWith=ScriptState] deleter boolean(unsigned long index); [CallWith=ScriptState] deleter boolean(DOMString name); - // Extended attributes for arguments + // Annotated types in arguments // [Clamp] - void voidMethodClampUnsignedShortArg([Clamp] unsigned short clampUnsignedShortArg); void voidMethodClampUnsignedLongArg([Clamp] unsigned long clampUnsignedLongArg); - // [Default] - void voidMethodDefaultUndefinedTestInterfaceEmptyArg([Default=Undefined] optional TestInterfaceEmpty defaultUndefinedTestInterfaceEmptyArg); - void voidMethodDefaultUndefinedLongArg([Default=Undefined] optional long defaultUndefinedLongArg); - void voidMethodDefaultUndefinedStringArg([Default=Undefined] optional DOMString defaultUndefinedStringArg); // [EnforceRange] void voidMethodEnforceRangeLongArg([EnforceRange] long enforceRangeLongArg); // [TreatNullAs] void voidMethodTreatNullAsEmptyStringStringArg([TreatNullAs=EmptyString] DOMString treatNullAsEmptyStringStringArg); + // Extended attributes for arguments + // [DefaultValue] + void voidMethodDefaultUndefinedTestInterfaceEmptyArg([DefaultValue=Undefined] optional TestInterfaceEmpty defaultUndefinedTestInterfaceEmptyArg); + void voidMethodDefaultUndefinedLongArg([DefaultValue=Undefined] optional long defaultUndefinedLongArg); + void voidMethodDefaultUndefinedStringArg([DefaultValue=Undefined] optional DOMString defaultUndefinedStringArg); + // Extended attributes for methods [LogActivity, LogAllWorlds] void activityLoggingAccessForAllWorldsMethod(); [CallWith=ExecutionContext] void callWithExecutionContextVoidMethod(); [CallWith=ScriptState] void callWithScriptStateVoidMethod(); [CallWith=ScriptState] long callWithScriptStateLongMethod(); [CallWith=(ScriptState,ExecutionContext,Isolate)] void callWithScriptStateExecutionContextIsolateVoidMethod(); - [CallWith=(ScriptState,ScriptArguments)] void callWithScriptStateScriptArgumentsVoidMethod(); - [CallWith=(ScriptState,ScriptArguments)] void callWithScriptStateScriptArgumentsVoidMethodOptionalBooleanArg(optional boolean optionalBooleanArg); [CallWith=CurrentWindow] void callWithCurrentWindow(); [CallWith=(CurrentWindow,EnteredWindow)] void callWithCurrentWindowScriptWindow(); [CallWith=ThisValue] void callWithThisValue(); @@ -544,7 +543,7 @@ // Avoid redundant type checking void useToImpl4ArgumentsCheckingIfPossibleWithOptionalArg(Node node1, optional Node node2); void useToImpl4ArgumentsCheckingIfPossibleWithNullableArg(Node node1, Node? node2); - void useToImpl4ArgumentsCheckingIfPossibleWithUndefinedArg(Node node1, [Default=Undefined] optional Node node2); + void useToImpl4ArgumentsCheckingIfPossibleWithUndefinedArg(Node node1, [DefaultValue=Undefined] optional Node node2); [Unforgeable] void unforgeableVoidMethod(); [NewObject] TestInterface newObjectTestInterfaceMethod(); [NewObject] Promise<TestInterface> newObjectTestInterfacePromiseMethod();
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc index 1a1f226f..98bfd78 100644 --- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc +++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc
@@ -16,7 +16,6 @@ #include "third_party/blink/renderer/bindings/core/v8/idl_types.h" #include "third_party/blink/renderer/bindings/core/v8/js_event_handler.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" -#include "third_party/blink/renderer/bindings/core/v8/script_call_stack.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h" @@ -61,7 +60,6 @@ #include "third_party/blink/renderer/core/html/html_table_rows_collection.h" #include "third_party/blink/renderer/core/html_names.h" #include "third_party/blink/renderer/core/inspector/console_message.h" -#include "third_party/blink/renderer/core/inspector/script_arguments.h" #include "third_party/blink/renderer/core/origin_trials/origin_trials.h" #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h" #include "third_party/blink/renderer/core/typed_arrays/flexible_array_buffer_view.h" @@ -7835,24 +7833,6 @@ V8SetReturnValueString(info, result, info.GetIsolate()); } -static void VoidMethodClampUnsignedShortArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { - ExceptionState exception_state(info.GetIsolate(), ExceptionState::kExecutionContext, "TestObject", "voidMethodClampUnsignedShortArg"); - - TestObject* impl = V8TestObject::ToImpl(info.Holder()); - - if (UNLIKELY(info.Length() < 1)) { - exception_state.ThrowTypeError(ExceptionMessages::NotEnoughArguments(1, info.Length())); - return; - } - - uint16_t clamp_unsigned_short_arg; - clamp_unsigned_short_arg = NativeValueTraits<IDLUnsignedShortClamp>::NativeValue(info.GetIsolate(), info[0], exception_state); - if (exception_state.HadException()) - return; - - impl->voidMethodClampUnsignedShortArg(clamp_unsigned_short_arg); -} - static void VoidMethodClampUnsignedLongArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { ExceptionState exception_state(info.GetIsolate(), ExceptionState::kExecutionContext, "TestObject", "voidMethodClampUnsignedLongArg"); @@ -7871,6 +7851,40 @@ impl->voidMethodClampUnsignedLongArg(clamp_unsigned_long_arg); } +static void VoidMethodEnforceRangeLongArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { + ExceptionState exception_state(info.GetIsolate(), ExceptionState::kExecutionContext, "TestObject", "voidMethodEnforceRangeLongArg"); + + TestObject* impl = V8TestObject::ToImpl(info.Holder()); + + if (UNLIKELY(info.Length() < 1)) { + exception_state.ThrowTypeError(ExceptionMessages::NotEnoughArguments(1, info.Length())); + return; + } + + int32_t enforce_range_long_arg; + enforce_range_long_arg = NativeValueTraits<IDLLongEnforceRange>::NativeValue(info.GetIsolate(), info[0], exception_state); + if (exception_state.HadException()) + return; + + impl->voidMethodEnforceRangeLongArg(enforce_range_long_arg); +} + +static void VoidMethodTreatNullAsEmptyStringStringArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { + TestObject* impl = V8TestObject::ToImpl(info.Holder()); + + if (UNLIKELY(info.Length() < 1)) { + V8ThrowException::ThrowTypeError(info.GetIsolate(), ExceptionMessages::FailedToExecute("voidMethodTreatNullAsEmptyStringStringArg", "TestObject", ExceptionMessages::NotEnoughArguments(1, info.Length()))); + return; + } + + V8StringResource<kTreatNullAsEmptyString> treat_null_as_empty_string_string_arg; + treat_null_as_empty_string_string_arg = info[0]; + if (!treat_null_as_empty_string_string_arg.Prepare()) + return; + + impl->voidMethodTreatNullAsEmptyStringStringArg(treat_null_as_empty_string_string_arg); +} + static void VoidMethodDefaultUndefinedTestInterfaceEmptyArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { TestObject* impl = V8TestObject::ToImpl(info.Holder()); @@ -7908,40 +7922,6 @@ impl->voidMethodDefaultUndefinedStringArg(default_undefined_string_arg); } -static void VoidMethodEnforceRangeLongArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { - ExceptionState exception_state(info.GetIsolate(), ExceptionState::kExecutionContext, "TestObject", "voidMethodEnforceRangeLongArg"); - - TestObject* impl = V8TestObject::ToImpl(info.Holder()); - - if (UNLIKELY(info.Length() < 1)) { - exception_state.ThrowTypeError(ExceptionMessages::NotEnoughArguments(1, info.Length())); - return; - } - - int32_t enforce_range_long_arg; - enforce_range_long_arg = NativeValueTraits<IDLLongEnforceRange>::NativeValue(info.GetIsolate(), info[0], exception_state); - if (exception_state.HadException()) - return; - - impl->voidMethodEnforceRangeLongArg(enforce_range_long_arg); -} - -static void VoidMethodTreatNullAsEmptyStringStringArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { - TestObject* impl = V8TestObject::ToImpl(info.Holder()); - - if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::ThrowTypeError(info.GetIsolate(), ExceptionMessages::FailedToExecute("voidMethodTreatNullAsEmptyStringStringArg", "TestObject", ExceptionMessages::NotEnoughArguments(1, info.Length()))); - return; - } - - V8StringResource<kTreatNullAsEmptyString> treat_null_as_empty_string_string_arg; - treat_null_as_empty_string_string_arg = info[0]; - if (!treat_null_as_empty_string_string_arg.Prepare()) - return; - - impl->voidMethodTreatNullAsEmptyStringStringArg(treat_null_as_empty_string_string_arg); -} - static void ActivityLoggingAccessForAllWorldsMethodMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { TestObject* impl = V8TestObject::ToImpl(info.Holder()); @@ -7981,42 +7961,6 @@ impl->callWithScriptStateExecutionContextIsolateVoidMethod(info.GetIsolate(), script_state, execution_context); } -static void CallWithScriptStateScriptArgumentsVoidMethodMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { - TestObject* impl = V8TestObject::ToImpl(info.Holder()); - - ScriptState* script_state = ScriptState::ForRelevantRealm(info); - - ScriptArguments* scriptArguments(ScriptArguments::Create(script_state, info, 0)); - impl->callWithScriptStateScriptArgumentsVoidMethod(script_state, script_arguments); -} - -static void CallWithScriptStateScriptArgumentsVoidMethodOptionalBooleanArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { - ExceptionState exception_state(info.GetIsolate(), ExceptionState::kExecutionContext, "TestObject", "callWithScriptStateScriptArgumentsVoidMethodOptionalBooleanArg"); - - TestObject* impl = V8TestObject::ToImpl(info.Holder()); - - ScriptState* script_state = ScriptState::ForRelevantRealm(info); - - bool optional_boolean_arg; - int num_args_passed = info.Length(); - while (num_args_passed > 0) { - if (!info[num_args_passed - 1]->IsUndefined()) - break; - --num_args_passed; - } - if (UNLIKELY(num_args_passed <= 0)) { - ScriptArguments* scriptArguments(ScriptArguments::Create(script_state, info, 1)); - impl->callWithScriptStateScriptArgumentsVoidMethodOptionalBooleanArg(script_state, script_arguments); - return; - } - optional_boolean_arg = NativeValueTraits<IDLBoolean>::NativeValue(info.GetIsolate(), info[0], exception_state); - if (exception_state.HadException()) - return; - - ScriptArguments* scriptArguments(ScriptArguments::Create(script_state, info, 1)); - impl->callWithScriptStateScriptArgumentsVoidMethodOptionalBooleanArg(script_state, script_arguments, optional_boolean_arg); -} - static void CallWithCurrentWindowMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { TestObject* impl = V8TestObject::ToImpl(info.Holder()); @@ -12771,18 +12715,24 @@ test_object_v8_internal::SetItemMethod(info); } -void V8TestObject::VoidMethodClampUnsignedShortArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { - RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestObject_voidMethodClampUnsignedShortArg"); - - test_object_v8_internal::VoidMethodClampUnsignedShortArgMethod(info); -} - void V8TestObject::VoidMethodClampUnsignedLongArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestObject_voidMethodClampUnsignedLongArg"); test_object_v8_internal::VoidMethodClampUnsignedLongArgMethod(info); } +void V8TestObject::VoidMethodEnforceRangeLongArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { + RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestObject_voidMethodEnforceRangeLongArg"); + + test_object_v8_internal::VoidMethodEnforceRangeLongArgMethod(info); +} + +void V8TestObject::VoidMethodTreatNullAsEmptyStringStringArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { + RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestObject_voidMethodTreatNullAsEmptyStringStringArg"); + + test_object_v8_internal::VoidMethodTreatNullAsEmptyStringStringArgMethod(info); +} + void V8TestObject::VoidMethodDefaultUndefinedTestInterfaceEmptyArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestObject_voidMethodDefaultUndefinedTestInterfaceEmptyArg"); @@ -12801,18 +12751,6 @@ test_object_v8_internal::VoidMethodDefaultUndefinedStringArgMethod(info); } -void V8TestObject::VoidMethodEnforceRangeLongArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { - RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestObject_voidMethodEnforceRangeLongArg"); - - test_object_v8_internal::VoidMethodEnforceRangeLongArgMethod(info); -} - -void V8TestObject::VoidMethodTreatNullAsEmptyStringStringArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { - RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestObject_voidMethodTreatNullAsEmptyStringStringArg"); - - test_object_v8_internal::VoidMethodTreatNullAsEmptyStringStringArgMethod(info); -} - void V8TestObject::ActivityLoggingAccessForAllWorldsMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestObject_activityLoggingAccessForAllWorldsMethod"); @@ -12848,18 +12786,6 @@ test_object_v8_internal::CallWithScriptStateExecutionContextIsolateVoidMethodMethod(info); } -void V8TestObject::CallWithScriptStateScriptArgumentsVoidMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { - RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestObject_callWithScriptStateScriptArgumentsVoidMethod"); - - test_object_v8_internal::CallWithScriptStateScriptArgumentsVoidMethodMethod(info); -} - -void V8TestObject::CallWithScriptStateScriptArgumentsVoidMethodOptionalBooleanArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { - RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestObject_callWithScriptStateScriptArgumentsVoidMethodOptionalBooleanArg"); - - test_object_v8_internal::CallWithScriptStateScriptArgumentsVoidMethodOptionalBooleanArgMethod(info); -} - void V8TestObject::CallWithCurrentWindowMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestObject_callWithCurrentWindow"); @@ -13713,20 +13639,17 @@ {"overloadedStaticMethod", V8TestObject::OverloadedStaticMethodMethodCallback, 1, v8::None, V8DOMConfiguration::kOnInterface, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"item", V8TestObject::ItemMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"setItem", V8TestObject::SetItemMethodCallback, 2, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, - {"voidMethodClampUnsignedShortArg", V8TestObject::VoidMethodClampUnsignedShortArgMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"voidMethodClampUnsignedLongArg", V8TestObject::VoidMethodClampUnsignedLongArgMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, + {"voidMethodEnforceRangeLongArg", V8TestObject::VoidMethodEnforceRangeLongArgMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, + {"voidMethodTreatNullAsEmptyStringStringArg", V8TestObject::VoidMethodTreatNullAsEmptyStringStringArgMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"voidMethodDefaultUndefinedTestInterfaceEmptyArg", V8TestObject::VoidMethodDefaultUndefinedTestInterfaceEmptyArgMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"voidMethodDefaultUndefinedLongArg", V8TestObject::VoidMethodDefaultUndefinedLongArgMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"voidMethodDefaultUndefinedStringArg", V8TestObject::VoidMethodDefaultUndefinedStringArgMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, - {"voidMethodEnforceRangeLongArg", V8TestObject::VoidMethodEnforceRangeLongArgMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, - {"voidMethodTreatNullAsEmptyStringStringArg", V8TestObject::VoidMethodTreatNullAsEmptyStringStringArgMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"activityLoggingAccessForAllWorldsMethod", V8TestObject::ActivityLoggingAccessForAllWorldsMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"callWithExecutionContextVoidMethod", V8TestObject::CallWithExecutionContextVoidMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"callWithScriptStateVoidMethod", V8TestObject::CallWithScriptStateVoidMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"callWithScriptStateLongMethod", V8TestObject::CallWithScriptStateLongMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"callWithScriptStateExecutionContextIsolateVoidMethod", V8TestObject::CallWithScriptStateExecutionContextIsolateVoidMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, - {"callWithScriptStateScriptArgumentsVoidMethod", V8TestObject::CallWithScriptStateScriptArgumentsVoidMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, - {"callWithScriptStateScriptArgumentsVoidMethodOptionalBooleanArg", V8TestObject::CallWithScriptStateScriptArgumentsVoidMethodOptionalBooleanArgMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"callWithCurrentWindow", V8TestObject::CallWithCurrentWindowMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"callWithCurrentWindowScriptWindow", V8TestObject::CallWithCurrentWindowScriptWindowMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}, {"callWithThisValue", V8TestObject::CallWithThisValueMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds},
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.h b/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.h index 88ea6f5..c44ae2f 100644 --- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.h +++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.h
@@ -541,20 +541,17 @@ CORE_EXPORT static void OverloadedStaticMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void ItemMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void SetItemMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); - CORE_EXPORT static void VoidMethodClampUnsignedShortArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void VoidMethodClampUnsignedLongArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); + CORE_EXPORT static void VoidMethodEnforceRangeLongArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); + CORE_EXPORT static void VoidMethodTreatNullAsEmptyStringStringArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void VoidMethodDefaultUndefinedTestInterfaceEmptyArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void VoidMethodDefaultUndefinedLongArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void VoidMethodDefaultUndefinedStringArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); - CORE_EXPORT static void VoidMethodEnforceRangeLongArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); - CORE_EXPORT static void VoidMethodTreatNullAsEmptyStringStringArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void ActivityLoggingAccessForAllWorldsMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void CallWithExecutionContextVoidMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void CallWithScriptStateVoidMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void CallWithScriptStateLongMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void CallWithScriptStateExecutionContextIsolateVoidMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); - CORE_EXPORT static void CallWithScriptStateScriptArgumentsVoidMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); - CORE_EXPORT static void CallWithScriptStateScriptArgumentsVoidMethodOptionalBooleanArgMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void CallWithCurrentWindowMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void CallWithCurrentWindowScriptWindowMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&); CORE_EXPORT static void CallWithThisValueMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
diff --git a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl index 5697ad5..75971286 100644 --- a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl +++ b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl
@@ -11,20 +11,20 @@ namespace blink { -struct SameSizeAsComputedStyleBase { +struct SameSizeVerifierForComputedStyleBase { {% if computed_style.subgroups is defined %} - void* dataRefs[{{computed_style.subgroups|length}}]; + void* data_refs[{{computed_style.subgroups|length}}]; {% endif %} {% for field in computed_style.fields|rejectattr("is_bit_field") %} {{field.type_name}} {{field.name}}; {% endfor %} - unsigned m_bit_fields[{{computed_style.num_32_bit_words_for_bit_fields}}]; + unsigned bit_fields[{{computed_style.num_32_bit_words_for_bit_fields}}]; }; // If this fails, the packing algorithm in make_computed_style_base.py has // failed to produce the optimal packed size. To fix, update the algorithm to // ensure that the buckets are placed so that each takes up at most 1 word. -ASSERT_SIZE(ComputedStyleBase, SameSizeAsComputedStyleBase); +ASSERT_SIZE(ComputedStyleBase, SameSizeVerifierForComputedStyleBase); // Constructor and destructor are protected so that only the parent class ComputedStyle // can instantiate this class.
diff --git a/third_party/blink/renderer/build/scripts/make_element_type_helpers.py b/third_party/blink/renderer/build/scripts/make_element_type_helpers.py index 210e5c26..057a1be1 100755 --- a/third_party/blink/renderer/build/scripts/make_element_type_helpers.py +++ b/third_party/blink/renderer/build/scripts/make_element_type_helpers.py
@@ -10,6 +10,7 @@ import json5_generator import template_expander +from blinkbuild.name_style_converter import NameStyleConverter def _symbol(tag): return 'k' + tag['name'].to_upper_camel_case() @@ -55,8 +56,8 @@ (basename + '.cc'): self.generate_helper_implementation, } - base_element_header = 'third_party/blink/renderer/core/' \ - '{0}/{0}_element.h'.format(self.namespace.lower()) + base_element_header = 'third_party/blink/renderer/core/{}/{}_element.h'.format( + self.namespace.lower(), NameStyleConverter(self.namespace).to_snake_case()) self._template_context = { 'base_element_header': base_element_header, 'cpp_namespace': self.namespace.lower() + '_names',
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index 3d96807..14b4353 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1926,6 +1926,7 @@ "html/forms/email_input_type_test.cc", "html/forms/external_popup_menu_test.cc", "html/forms/file_input_type_test.cc", + "html/forms/form_controller_test.cc", "html/forms/form_data_test.cc", "html/forms/html_form_control_element_test.cc", "html/forms/html_form_element_test.cc", @@ -2116,6 +2117,7 @@ "page/focus_controller_test.cc", "page/page_popup_client_test.cc", "page/print_context_test.cc", + "page/scrolling/fragment_anchor_test.cc", "page/scrolling/main_thread_scrolling_reasons_test.cc", "page/scrolling/root_scroller_test.cc", "page/scrolling/scroll_into_view_test.cc",
diff --git a/third_party/blink/renderer/core/accessibility/ax_object_cache.h b/third_party/blink/renderer/core/accessibility/ax_object_cache.h index 5913d693..e9dfdd7 100644 --- a/third_party/blink/renderer/core/accessibility/ax_object_cache.h +++ b/third_party/blink/renderer/core/accessibility/ax_object_cache.h
@@ -103,6 +103,8 @@ virtual void HandleLayoutComplete(Document*) = 0; virtual void HandleClicked(Node*) = 0; virtual void HandleAutofillStateChanged(Element*, bool) = 0; + virtual void HandleValidationMessageVisibilityChanged( + const Element* form_control) = 0; // Handle any notifications which arrived while layout was dirty. virtual void ProcessUpdatesAfterLayout(Document&) = 0;
diff --git a/third_party/blink/renderer/core/css/css_selector.cc b/third_party/blink/renderer/core/css/css_selector.cc index ea99b13..e07bcc4 100644 --- a/third_party/blink/renderer/core/css/css_selector.cc +++ b/third_party/blink/renderer/core/css/css_selector.cc
@@ -1044,6 +1044,25 @@ GetPseudoType() == kPseudoPlaceholder); } +bool CSSSelector::IsAllowedAfterPart() const { + if (Match() != CSSSelector::kPseudoElement) { + return false; + } + // Everything that makes sense should work following ::part. This whitelist + // restricts it to what has been tested. + switch (GetPseudoType()) { + case kPseudoBefore: + case kPseudoAfter: + case kPseudoPlaceholder: + case kPseudoFirstLine: + case kPseudoFirstLetter: + case kPseudoSelection: + return true; + default: + return false; + } +} + template <typename Functor> static bool ForAnyInTagHistory(const Functor& functor, const CSSSelector& selector) {
diff --git a/third_party/blink/renderer/core/css/css_selector.h b/third_party/blink/renderer/core/css/css_selector.h index 8396c2d..619f661 100644 --- a/third_party/blink/renderer/core/css/css_selector.h +++ b/third_party/blink/renderer/core/css/css_selector.h
@@ -381,6 +381,7 @@ bool MatchesPseudoElement() const; bool IsTreeAbidingPseudoElement() const; + bool IsAllowedAfterPart() const; bool HasContentPseudo() const; bool HasSlottedPseudo() const;
diff --git a/third_party/blink/renderer/core/css/css_style_sheet.idl b/third_party/blink/renderer/core/css/css_style_sheet.idl index e4c0b0a..3ee4e19 100644 --- a/third_party/blink/renderer/core/css/css_style_sheet.idl +++ b/third_party/blink/renderer/core/css/css_style_sheet.idl
@@ -36,6 +36,6 @@ // Non-standard APIs [MeasureAs=CSSStyleSheetRules, RaisesException] readonly attribute CSSRuleList rules; - [MeasureAs=CSSStyleSheetAddRule, RaisesException] long addRule([Default=Undefined] optional DOMString selector, [Default=Undefined] optional DOMString style, optional unsigned long index); - [MeasureAs=CSSStyleSheetRemoveRule, RaisesException] void removeRule([Default=Undefined] optional unsigned long index); + [MeasureAs=CSSStyleSheetAddRule, RaisesException] long addRule([DefaultValue=Undefined] optional DOMString selector, [DefaultValue=Undefined] optional DOMString style, optional unsigned long index); + [MeasureAs=CSSStyleSheetRemoveRule, RaisesException] void removeRule([DefaultValue=Undefined] optional unsigned long index); };
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_selector.h b/third_party/blink/renderer/core/css/parser/css_parser_selector.h index b55eda0..6cc89694 100644 --- a/third_party/blink/renderer/core/css/parser/css_parser_selector.h +++ b/third_party/blink/renderer/core/css/parser/css_parser_selector.h
@@ -99,6 +99,7 @@ bool IsTreeAbidingPseudoElement() const { return selector_->IsTreeAbidingPseudoElement(); } + bool IsAllowedAfterPart() const { return selector_->IsAllowedAfterPart(); } const CSSSelectorList* SelectorList() const { return selector_->SelectorList(); }
diff --git a/third_party/blink/renderer/core/css/parser/css_selector_parser.cc b/third_party/blink/renderer/core/css/parser/css_selector_parser.cc index 5dfcf39..ddfeaa52 100644 --- a/third_party/blink/renderer/core/css/parser/css_selector_parser.cc +++ b/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
@@ -271,7 +271,7 @@ case CSSSelector::kPseudoSlotted: return simple_selector.IsTreeAbidingPseudoElement(); case CSSSelector::kPseudoPart: - if (simple_selector.IsTreeAbidingPseudoElement()) + if (simple_selector.IsAllowedAfterPart()) return true; break; default:
diff --git a/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc b/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc index 26b759c..c588c50 100644 --- a/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc +++ b/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc
@@ -564,8 +564,10 @@ } TEST(CSSSelectorParserTest, ShadowPartAndBeforeAfterPseudoElementValid) { - const char* test_cases[] = {"::part(ident)::before", "::part(ident)::after", - "::part(ident)::placeholder"}; + const char* test_cases[] = { + "::part(ident)::before", "::part(ident)::after", + "::part(ident)::placeholder", "::part(ident)::first-line", + "::part(ident)::first-letter", "::part(ident)::selection"}; for (auto* test_case : test_cases) { SCOPED_TRACE(test_case);
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc index 84c642d..69c35eae 100644 --- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc +++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -2598,5 +2598,12 @@ return css_property_parser_helpers::ConsumeColor(range, context.Mode()); } +css_property_parser_helpers::UnitlessQuirk UnitlessUnlessShorthand( + const CSSParserLocalContext& local_context) { + return local_context.CurrentShorthand() == CSSPropertyInvalid + ? css_property_parser_helpers::UnitlessQuirk::kAllow + : css_property_parser_helpers::UnitlessQuirk::kForbid; +} + } // namespace css_parsing_utils } // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h index c7cbb4c5..342e654 100644 --- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h +++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
@@ -237,6 +237,9 @@ CSSValue* ParsePaintStroke(CSSParserTokenRange&, const CSSParserContext&); CSSValue* ParseSpacing(CSSParserTokenRange&, const CSSParserContext&); +css_property_parser_helpers::UnitlessQuirk UnitlessUnlessShorthand( + const CSSParserLocalContext&); + template <CSSValueID start, CSSValueID end> CSSValue* ConsumePositionLonghand(CSSParserTokenRange& range, CSSParserMode css_parser_mode) {
diff --git a/third_party/blink/renderer/core/css/properties/longhands/bottom_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/bottom_custom.cc index 7f22bfd6..bed946f 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/bottom_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/bottom_custom.cc
@@ -17,12 +17,13 @@ namespace css_longhand { -const CSSValue* Bottom::ParseSingleValue(CSSParserTokenRange& range, - const CSSParserContext& context, - const CSSParserLocalContext&) const { +const CSSValue* Bottom::ParseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext& context, + const CSSParserLocalContext& local_context) const { return css_parsing_utils::ConsumeMarginOrOffset( range, context.Mode(), - css_property_parser_helpers::UnitlessQuirk::kAllow); + css_parsing_utils::UnitlessUnlessShorthand(local_context)); } bool Bottom::IsLayoutDependent(const ComputedStyle* style,
diff --git a/third_party/blink/renderer/core/css/properties/longhands/left_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/left_custom.cc index e9f4074e..d986478c 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/left_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/left_custom.cc
@@ -17,12 +17,13 @@ namespace css_longhand { -const CSSValue* Left::ParseSingleValue(CSSParserTokenRange& range, - const CSSParserContext& context, - const CSSParserLocalContext&) const { +const CSSValue* Left::ParseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext& context, + const CSSParserLocalContext& local_context) const { return css_parsing_utils::ConsumeMarginOrOffset( range, context.Mode(), - css_property_parser_helpers::UnitlessQuirk::kAllow); + css_parsing_utils::UnitlessUnlessShorthand(local_context)); } bool Left::IsLayoutDependent(const ComputedStyle* style,
diff --git a/third_party/blink/renderer/core/css/properties/longhands/right_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/right_custom.cc index 3ea4279..55e234c 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/right_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/right_custom.cc
@@ -17,12 +17,13 @@ namespace css_longhand { -const CSSValue* Right::ParseSingleValue(CSSParserTokenRange& range, - const CSSParserContext& context, - const CSSParserLocalContext&) const { +const CSSValue* Right::ParseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext& context, + const CSSParserLocalContext& local_context) const { return css_parsing_utils::ConsumeMarginOrOffset( range, context.Mode(), - css_property_parser_helpers::UnitlessQuirk::kAllow); + css_parsing_utils::UnitlessUnlessShorthand(local_context)); } bool Right::IsLayoutDependent(const ComputedStyle* style,
diff --git a/third_party/blink/renderer/core/css/properties/longhands/top_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/top_custom.cc index 3432849..2d56fcc 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/top_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/top_custom.cc
@@ -17,12 +17,13 @@ namespace css_longhand { -const CSSValue* Top::ParseSingleValue(CSSParserTokenRange& range, - const CSSParserContext& context, - const CSSParserLocalContext&) const { +const CSSValue* Top::ParseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext& context, + const CSSParserLocalContext& local_context) const { return css_parsing_utils::ConsumeMarginOrOffset( range, context.Mode(), - css_property_parser_helpers::UnitlessQuirk::kAllow); + css_parsing_utils::UnitlessUnlessShorthand(local_context)); } bool Top::IsLayoutDependent(const ComputedStyle* style,
diff --git a/third_party/blink/renderer/core/css/style_media.idl b/third_party/blink/renderer/core/css/style_media.idl index 5e11e72..f87108f 100644 --- a/third_party/blink/renderer/core/css/style_media.idl +++ b/third_party/blink/renderer/core/css/style_media.idl
@@ -35,5 +35,5 @@ NoInterfaceObject ] interface StyleMedia { [MeasureAs=StyleMediaType] readonly attribute DOMString type; - [MeasureAs=StyleMediaMatchMedium] boolean matchMedium([Default=Undefined] optional DOMString mediaquery); + [MeasureAs=StyleMediaMatchMedium] boolean matchMedium([DefaultValue=Undefined] optional DOMString mediaquery); };
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc index 0e1b3843..d553821 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -257,4 +257,79 @@ EXPECT_EQ(1, client.Count()); client.Reset(); } + +TEST_F(DisplayLockContextTest, LockedElementAndDescendantsAreNotFocusable) { + ResizeAndFocus(); + SetHtmlInnerHTML(R"HTML( + <style> + #container { + width: 100px; + height: 100px; + contain: content; + } + </style> + <body> + <div id="container"> + <input id="textfield", type="text"> + </div> + </body> + )HTML"); + + // We start off as being focusable. + ASSERT_TRUE(GetDocument().getElementById("textfield")->IsKeyboardFocusable()); + ASSERT_TRUE(GetDocument().getElementById("textfield")->IsMouseFocusable()); + ASSERT_TRUE(GetDocument().getElementById("textfield")->IsFocusable()); + + auto* element = GetDocument().getElementById("container"); + { + auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame()); + ScriptState::Scope scope(script_state); + element->getDisplayLockForBindings()->acquire(script_state, nullptr); + } + + // We should be in pending acquire state, which means we would allow things + // like style and layout but disallow paint. + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint()); + + UpdateAllLifecyclePhasesForTest(); + + // Sanity checks to ensure the element is locked. + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint()); + + // The input should not be focusable now. + EXPECT_FALSE( + GetDocument().getElementById("textfield")->IsKeyboardFocusable()); + EXPECT_FALSE(GetDocument().getElementById("textfield")->IsMouseFocusable()); + EXPECT_FALSE(GetDocument().getElementById("textfield")->IsFocusable()); + + // Calling explicit focus() should also not focus the element. + GetDocument().getElementById("textfield")->focus(); + EXPECT_FALSE(GetDocument().FocusedElement()); + + // Now commit the lock and ensure we can focus the input + { + auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame()); + ScriptState::Scope scope(script_state); + element->getDisplayLockForBindings()->commit(script_state); + } + + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout()); + EXPECT_TRUE(element->GetDisplayLockContext()->ShouldPaint()); + + UpdateAllLifecyclePhasesForTest(); + + EXPECT_TRUE(GetDocument().getElementById("textfield")->IsKeyboardFocusable()); + EXPECT_TRUE(GetDocument().getElementById("textfield")->IsMouseFocusable()); + EXPECT_TRUE(GetDocument().getElementById("textfield")->IsFocusable()); + + // Calling explicit focus() should focus the element + GetDocument().getElementById("textfield")->focus(); + EXPECT_EQ(GetDocument().FocusedElement(), + GetDocument().getElementById("textfield")); +} } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/attr.cc b/third_party/blink/renderer/core/dom/attr.cc index 13814ee..2fd0e8e 100644 --- a/third_party/blink/renderer/core/dom/attr.cc +++ b/third_party/blink/renderer/core/dom/attr.cc
@@ -110,7 +110,7 @@ standalone_value_or_attached_local_name_ = attached_local_name; } -void Attr::Trace(blink::Visitor* visitor) { +void Attr::Trace(Visitor* visitor) { visitor->Trace(element_); Node::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/attr.h b/third_party/blink/renderer/core/dom/attr.h index cdd530e9..d56a049 100644 --- a/third_party/blink/renderer/core/dom/attr.h +++ b/third_party/blink/renderer/core/dom/attr.h
@@ -62,7 +62,7 @@ const AtomicString& namespaceURI() const { return name_.NamespaceURI(); } const AtomicString& prefix() const { return name_.Prefix(); } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: bool IsElementNode() const =
diff --git a/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc b/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc index 3679895..7d9f0ae 100644 --- a/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc +++ b/third_party/blink/renderer/core/dom/child_list_mutation_scope.cc
@@ -151,7 +151,7 @@ return result; } -void ChildListMutationAccumulator::Trace(blink::Visitor* visitor) { +void ChildListMutationAccumulator::Trace(Visitor* visitor) { visitor->Trace(target_); visitor->Trace(removed_nodes_); visitor->Trace(added_nodes_);
diff --git a/third_party/blink/renderer/core/dom/child_list_mutation_scope.h b/third_party/blink/renderer/core/dom/child_list_mutation_scope.h index a8b1a34..62cd18ac 100644 --- a/third_party/blink/renderer/core/dom/child_list_mutation_scope.h +++ b/third_party/blink/renderer/core/dom/child_list_mutation_scope.h
@@ -66,7 +66,7 @@ void EnterMutationScope() { mutation_scopes_++; } void LeaveMutationScope(); - void Trace(blink::Visitor*); + void Trace(Visitor*); private: void EnqueueMutationRecord();
diff --git a/third_party/blink/renderer/core/dom/child_node_list.cc b/third_party/blink/renderer/core/dom/child_node_list.cc index e934698..457df19 100644 --- a/third_party/blink/renderer/core/dom/child_node_list.cc +++ b/third_party/blink/renderer/core/dom/child_node_list.cc
@@ -83,7 +83,7 @@ return nullptr; } -void ChildNodeList::Trace(blink::Visitor* visitor) { +void ChildNodeList::Trace(Visitor* visitor) { visitor->Trace(parent_); visitor->Trace(collection_index_cache_); NodeList::Trace(visitor);
diff --git a/third_party/blink/renderer/core/dom/child_node_list.h b/third_party/blink/renderer/core/dom/child_node_list.h index baad97dc..9a52569 100644 --- a/third_party/blink/renderer/core/dom/child_node_list.h +++ b/third_party/blink/renderer/core/dom/child_node_list.h
@@ -64,7 +64,7 @@ Node& current_node, unsigned& current_offset) const; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: bool IsChildNodeList() const override { return true; }
diff --git a/third_party/blink/renderer/core/dom/collection_index_cache.h b/third_party/blink/renderer/core/dom/collection_index_cache.h index 7572bea8c..caf4bf7 100644 --- a/third_party/blink/renderer/core/dom/collection_index_cache.h +++ b/third_party/blink/renderer/core/dom/collection_index_cache.h
@@ -66,7 +66,7 @@ void NodeInserted(); void NodeRemoved(); - virtual void Trace(blink::Visitor* visitor) { visitor->Trace(current_node_); } + virtual void Trace(Visitor* visitor) { visitor->Trace(current_node_); } protected: ALWAYS_INLINE NodeType* CachedNode() const { return current_node_; }
diff --git a/third_party/blink/renderer/core/dom/container_node.cc b/third_party/blink/renderer/core/dom/container_node.cc index 4202aa80..59467cf7 100644 --- a/third_party/blink/renderer/core/dom/container_node.cc +++ b/third_party/blink/renderer/core/dom/container_node.cc
@@ -651,7 +651,7 @@ ChildFrameDisconnector::kDescendantsOnly); } -void ContainerNode::Trace(blink::Visitor* visitor) { +void ContainerNode::Trace(Visitor* visitor) { visitor->Trace(first_child_); visitor->Trace(last_child_); Node::Trace(visitor);
diff --git a/third_party/blink/renderer/core/dom/container_node.h b/third_party/blink/renderer/core/dom/container_node.h index 49b5d8e..6e21966 100644 --- a/third_party/blink/renderer/core/dom/container_node.h +++ b/third_party/blink/renderer/core/dom/container_node.h
@@ -367,7 +367,7 @@ virtual bool ChildrenCanHaveStyle() const { return true; } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; protected: ContainerNode(TreeScope*, ConstructionType = kCreateContainer);
diff --git a/third_party/blink/renderer/core/dom/context_features_client_impl.cc b/third_party/blink/renderer/core/dom/context_features_client_impl.cc index 09ed8444..ce95f23 100644 --- a/third_party/blink/renderer/core/dom/context_features_client_impl.cc +++ b/third_party/blink/renderer/core/dom/context_features_client_impl.cc
@@ -84,7 +84,7 @@ void ValidateAgainst(Document*); - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { Supplement<Document>::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/context_lifecycle_observer.cc b/third_party/blink/renderer/core/dom/context_lifecycle_observer.cc index 3c3bf10..4df3f8a4 100644 --- a/third_party/blink/renderer/core/dom/context_lifecycle_observer.cc +++ b/third_party/blink/renderer/core/dom/context_lifecycle_observer.cc
@@ -34,7 +34,7 @@ return document ? document->GetFrame() : nullptr; } -void ContextClient::Trace(blink::Visitor* visitor) { +void ContextClient::Trace(Visitor* visitor) { visitor->Trace(execution_context_); } @@ -57,7 +57,7 @@ return dom_window_ ? dom_window_->GetFrame() : nullptr; } -void DOMWindowClient::Trace(blink::Visitor* visitor) { +void DOMWindowClient::Trace(Visitor* visitor) { visitor->Trace(dom_window_); } }
diff --git a/third_party/blink/renderer/core/dom/context_lifecycle_observer.h b/third_party/blink/renderer/core/dom/context_lifecycle_observer.h index b93e57d..c8648ad6 100644 --- a/third_party/blink/renderer/core/dom/context_lifecycle_observer.h +++ b/third_party/blink/renderer/core/dom/context_lifecycle_observer.h
@@ -75,7 +75,7 @@ // Returns null otherwise. LocalFrame* GetFrame() const; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; protected: explicit ContextClient(ExecutionContext*); @@ -155,7 +155,7 @@ LocalDOMWindow* DomWindow() const; LocalFrame* GetFrame() const; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; protected: explicit DOMWindowClient(LocalDOMWindow*);
diff --git a/third_party/blink/renderer/core/dom/dataset_dom_string_map.cc b/third_party/blink/renderer/core/dom/dataset_dom_string_map.cc index 0a18a0a..5a368399 100644 --- a/third_party/blink/renderer/core/dom/dataset_dom_string_map.cc +++ b/third_party/blink/renderer/core/dom/dataset_dom_string_map.cc
@@ -200,7 +200,7 @@ return false; } -void DatasetDOMStringMap::Trace(blink::Visitor* visitor) { +void DatasetDOMStringMap::Trace(Visitor* visitor) { visitor->Trace(element_); DOMStringMap::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/dataset_dom_string_map.h b/third_party/blink/renderer/core/dom/dataset_dom_string_map.h index 998d8f7..e3d457b1 100644 --- a/third_party/blink/renderer/core/dom/dataset_dom_string_map.h +++ b/third_party/blink/renderer/core/dom/dataset_dom_string_map.h
@@ -49,7 +49,7 @@ ExceptionState&) override; bool DeleteItem(const String& name) override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Member<Element> element_;
diff --git a/third_party/blink/renderer/core/dom/distributed_nodes.cc b/third_party/blink/renderer/core/dom/distributed_nodes.cc index 9ef449dc..8b7f447 100644 --- a/third_party/blink/renderer/core/dom/distributed_nodes.cc +++ b/third_party/blink/renderer/core/dom/distributed_nodes.cc
@@ -66,7 +66,7 @@ return at(index - 1); } -void DistributedNodes::Trace(blink::Visitor* visitor) { +void DistributedNodes::Trace(Visitor* visitor) { visitor->Trace(nodes_); visitor->Trace(indices_); }
diff --git a/third_party/blink/renderer/core/dom/distributed_nodes.h b/third_party/blink/renderer/core/dom/distributed_nodes.h index 003bcbc..265dd6e6 100644 --- a/third_party/blink/renderer/core/dom/distributed_nodes.h +++ b/third_party/blink/renderer/core/dom/distributed_nodes.h
@@ -64,7 +64,7 @@ void Swap(DistributedNodes& other); - void Trace(blink::Visitor*); + void Trace(Visitor*); private: HeapVector<Member<Node>> nodes_;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 32a12ca..288f376 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -576,7 +576,7 @@ online_observer_handle_ = nullptr; } - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { ContextLifecycleObserver::Trace(visitor); } @@ -2445,6 +2445,7 @@ DCHECK(IsMainThread()); HTMLFrameOwnerElement::PluginDisposeSuspendScope suspend_plugin_dispose; + ScriptForbiddenScope forbid_script; LocalFrameView* frame_view = View(); DCHECK(!frame_view || !frame_view->IsInPerformLayout()) @@ -2478,16 +2479,7 @@ // If we're restoring a scroll position from history, that takes precedence // over scrolling to the anchor in the URL. View()->InvokeFragmentAnchor(); - - // Script run in the call above may detach the document. - if (GetFrame() && View()) { - GetFrame()->Loader().RestoreScrollPositionAndViewState(); - - // The focus call above can execute JS which can dirty layout. Ensure - // layout is clean since this is called from UpdateLayout. - if (View()->NeedsLayout()) - View()->UpdateLayout(); - } + GetFrame()->Loader().RestoreScrollPositionAndViewState(); // Plugins can run script inside layout which can detach the page. // TODO(dcheng): Does it make sense to do any of this work if detached? @@ -3376,14 +3368,14 @@ return root_element; } -Document* Document::open(LocalDOMWindow* entered_window, +Document* Document::open(v8::Isolate* isolate, const AtomicString& type, const AtomicString& replace, ExceptionState& exception_state) { if (replace == "replace") { UseCounter::Count(Loader(), WebFeature::kDocumentOpenTwoArgsWithReplace); } - open(entered_window->document(), exception_state); + open(EnteredDOMWindow(isolate)->document(), exception_state); return this; } @@ -3972,11 +3964,9 @@ write("\n", entered_document); } -void Document::write(LocalDOMWindow* entered_window, +void Document::write(v8::Isolate* isolate, const Vector<String>& text, ExceptionState& exception_state) { - DCHECK(entered_window); - if (GetSecurityContext().RequireTrustedTypes()) { DCHECK(RuntimeEnabledFeatures::TrustedDOMTypesEnabled()); exception_state.ThrowTypeError( @@ -3990,14 +3980,13 @@ StringBuilder builder; for (const String& string : text) builder.Append(string); - write(builder.ToString(), entered_window->document(), exception_state); + write(builder.ToString(), EnteredDOMWindow(isolate)->document(), + exception_state); } -void Document::writeln(LocalDOMWindow* entered_window, +void Document::writeln(v8::Isolate* isolate, const Vector<String>& text, ExceptionState& exception_state) { - DCHECK(entered_window); - if (GetSecurityContext().RequireTrustedTypes()) { DCHECK(RuntimeEnabledFeatures::TrustedDOMTypesEnabled()); exception_state.ThrowTypeError( @@ -4011,23 +4000,24 @@ StringBuilder builder; for (const String& string : text) builder.Append(string); - writeln(builder.ToString(), entered_window->document(), exception_state); + writeln(builder.ToString(), EnteredDOMWindow(isolate)->document(), + exception_state); } -void Document::write(LocalDOMWindow* entered_window, +void Document::write(v8::Isolate* isolate, TrustedHTML* text, ExceptionState& exception_state) { - DCHECK(entered_window); DCHECK(RuntimeEnabledFeatures::TrustedDOMTypesEnabled()); - write(text->toString(), entered_window->document(), exception_state); + write(text->toString(), EnteredDOMWindow(isolate)->document(), + exception_state); } -void Document::writeln(LocalDOMWindow* entered_window, +void Document::writeln(v8::Isolate* isolate, TrustedHTML* text, ExceptionState& exception_state) { - DCHECK(entered_window); DCHECK(RuntimeEnabledFeatures::TrustedDOMTypesEnabled()); - writeln(text->toString(), entered_window->document(), exception_state); + writeln(text->toString(), EnteredDOMWindow(isolate)->document(), + exception_state); } DOMTimerCoordinator* Document::Timers() { @@ -7664,7 +7654,7 @@ return computed_style; } -void Document::Trace(blink::Visitor* visitor) { +void Document::Trace(Visitor* visitor) { visitor->Trace(imports_controller_); visitor->Trace(doc_type_); visitor->Trace(implementation_);
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index 4141048..bf10191 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -594,7 +594,7 @@ // This is the DOM API document.open() implementation. // document.open() opens a new window when called with three arguments. - Document* open(LocalDOMWindow* entered_window, + Document* open(v8::Isolate*, const AtomicString& type, const AtomicString& replace, ExceptionState&); @@ -657,17 +657,13 @@ void writeln(const String& text, Document* entered_document = nullptr, ExceptionState& = ASSERT_NO_EXCEPTION); - void write(LocalDOMWindow* entered_window, - const Vector<String>& text, - ExceptionState&); - void writeln(LocalDOMWindow* entered_window, - const Vector<String>& text, - ExceptionState&); + void write(v8::Isolate*, const Vector<String>& text, ExceptionState&); + void writeln(v8::Isolate*, const Vector<String>& text, ExceptionState&); // TrustedHTML variants of the above. // TODO(mkwst): Write a spec for this. - void write(LocalDOMWindow* entered_window, TrustedHTML*, ExceptionState&); - void writeln(LocalDOMWindow* entered_window, TrustedHTML*, ExceptionState&); + void write(v8::Isolate*, TrustedHTML*, ExceptionState&); + void writeln(v8::Isolate*, TrustedHTML*, ExceptionState&); bool WellFormed() const { return well_formed_; } @@ -1306,7 +1302,7 @@ void UpdateActiveStyle(); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; AtomicString ConvertLocalName(const AtomicString&);
diff --git a/third_party/blink/renderer/core/dom/document.idl b/third_party/blink/renderer/core/dom/document.idl index 4fe0dd0..f80ceaf 100644 --- a/third_party/blink/renderer/core/dom/document.idl +++ b/third_party/blink/renderer/core/dom/document.idl
@@ -116,16 +116,16 @@ [ImplementedAs=currentScriptForBinding] readonly attribute HTMLOrSVGScriptElement? currentScript; // dynamic markup insertion - [CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException, MeasureAs=DocumentOpenTwoArgs] Document open(optional DOMString type = "text/html", optional DOMString replace = ""); + [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException, MeasureAs=DocumentOpenTwoArgs] Document open(optional DOMString type = "text/html", optional DOMString replace = ""); [CallWith=Isolate, RaisesException, MeasureAs=DocumentOpenThreeArgs] Window open(URLString url, DOMString name, DOMString features); [CEReactions, RaisesException] void close(); - [CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException] void write(DOMString... text); - [CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException] void writeln(DOMString... text); + [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void write(DOMString... text); + [CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void writeln(DOMString... text); // TrustedTypes variants of the above. // TODO(mkwst): Write a spec for this. - [RuntimeEnabled=TrustedDOMTypes, CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException] void write(TrustedHTML text); - [RuntimeEnabled=TrustedDOMTypes, CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException] void writeln(TrustedHTML text); + [RuntimeEnabled=TrustedDOMTypes, CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void write(TrustedHTML text); + [RuntimeEnabled=TrustedDOMTypes, CallWith=Isolate, CEReactions, CustomElementCallbacks, RaisesException] void writeln(TrustedHTML text); // user interaction [Affects=Nothing] readonly attribute Window? defaultView; @@ -185,7 +185,7 @@ [RuntimeEnabled=CorsRFC1918, ImplementedAs=addressSpaceForBindings] readonly attribute AddressSpace addressSpace; // Non-standard APIs - [MeasureAs=DocumentCaretRangeFromPoint] Range caretRangeFromPoint([Default=Undefined] optional long x, [Default=Undefined] optional long y); + [MeasureAs=DocumentCaretRangeFromPoint] Range caretRangeFromPoint([DefaultValue=Undefined] optional long x, [DefaultValue=Undefined] optional long y); // https://wicg.github.io/feature-policy/#the-policy-object
diff --git a/third_party/blink/renderer/core/dom/document_parser.cc b/third_party/blink/renderer/core/dom/document_parser.cc index 996d00c59..4b5ad3ab 100644 --- a/third_party/blink/renderer/core/dom/document_parser.cc +++ b/third_party/blink/renderer/core/dom/document_parser.cc
@@ -42,7 +42,7 @@ DocumentParser::~DocumentParser() = default; -void DocumentParser::Trace(blink::Visitor* visitor) { +void DocumentParser::Trace(Visitor* visitor) { visitor->Trace(document_); visitor->Trace(clients_); }
diff --git a/third_party/blink/renderer/core/dom/document_parser.h b/third_party/blink/renderer/core/dom/document_parser.h index 9ffd54d4..16860fd 100644 --- a/third_party/blink/renderer/core/dom/document_parser.h +++ b/third_party/blink/renderer/core/dom/document_parser.h
@@ -42,7 +42,7 @@ public NameClient { public: virtual ~DocumentParser(); - virtual void Trace(blink::Visitor*); + virtual void Trace(Visitor*); const char* NameInHeapSnapshot() const override { return "DocumentParser"; } virtual ScriptableDocumentParser* AsScriptableDocumentParser() {
diff --git a/third_party/blink/renderer/core/dom/document_parser_client.h b/third_party/blink/renderer/core/dom/document_parser_client.h index 0f199fda..bdc55f19 100644 --- a/third_party/blink/renderer/core/dom/document_parser_client.h +++ b/third_party/blink/renderer/core/dom/document_parser_client.h
@@ -14,7 +14,7 @@ // This callback is called when all data pushed to parser has been consumed. virtual void NotifyParserStopped() = 0; - void Trace(blink::Visitor* visitor) override {} + void Trace(Visitor* visitor) override {} protected: DocumentParserClient() = default;
diff --git a/third_party/blink/renderer/core/dom/document_parser_timing.cc b/third_party/blink/renderer/core/dom/document_parser_timing.cc index d184e49..044ea560 100644 --- a/third_party/blink/renderer/core/dom/document_parser_timing.cc +++ b/third_party/blink/renderer/core/dom/document_parser_timing.cc
@@ -66,7 +66,7 @@ NotifyDocumentParserTimingChanged(); } -void DocumentParserTiming::Trace(blink::Visitor* visitor) { +void DocumentParserTiming::Trace(Visitor* visitor) { Supplement<Document>::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/document_parser_timing.h b/third_party/blink/renderer/core/dom/document_parser_timing.h index 8cd533d..98dbc0b1 100644 --- a/third_party/blink/renderer/core/dom/document_parser_timing.h +++ b/third_party/blink/renderer/core/dom/document_parser_timing.h
@@ -97,7 +97,7 @@ return parser_blocked_on_script_execution_from_document_write_duration_; } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: void NotifyDocumentParserTimingChanged();
diff --git a/third_party/blink/renderer/core/dom/document_test.cc b/third_party/blink/renderer/core/dom/document_test.cc index b621495..3ce1a80 100644 --- a/third_party/blink/renderer/core/dom/document_test.cc +++ b/third_party/blink/renderer/core/dom/document_test.cc
@@ -98,7 +98,7 @@ node_to_be_removed_(node_with_index.GetNode()), offset_(offset) {} - void Trace(blink::Visitor* visitor) { + void Trace(Visitor* visitor) { visitor->Trace(node_); visitor->Trace(node_to_be_removed_); } @@ -120,7 +120,7 @@ old_length_(old_length), new_length_(new_length) {} - void Trace(blink::Visitor* visitor) { visitor->Trace(node_); } + void Trace(Visitor* visitor) { visitor->Trace(node_); } }; TestSynchronousMutationObserver(Document&); @@ -160,7 +160,7 @@ return updated_character_data_records_; } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: // Implement |SynchronousMutationObserver| member functions. @@ -239,7 +239,7 @@ removed_nodes_.push_back(&node); } -void TestSynchronousMutationObserver::Trace(blink::Visitor* visitor) { +void TestSynchronousMutationObserver::Trace(Visitor* visitor) { visitor->Trace(children_changed_nodes_); visitor->Trace(merge_text_nodes_records_); visitor->Trace(move_tree_to_new_document_nodes_); @@ -263,7 +263,7 @@ return context_destroyed_called_counter_; } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: // Implement |DocumentShutdownObserver| member functions. @@ -282,7 +282,7 @@ ++context_destroyed_called_counter_; } -void TestDocumentShutdownObserver::Trace(blink::Visitor* visitor) { +void TestDocumentShutdownObserver::Trace(Visitor* visitor) { DocumentShutdownObserver::Trace(visitor); } @@ -317,7 +317,7 @@ } void WillBeDestroyed() override {} - // virtual void Trace(blink::Visitor* visitor) { + // virtual void Trace(Visitor* visitor) { // ValidationMessageClient::trace(visitor); } };
diff --git a/third_party/blink/renderer/core/dom/document_timing.cc b/third_party/blink/renderer/core/dom/document_timing.cc index 2644b1ec..bf58fc5 100644 --- a/third_party/blink/renderer/core/dom/document_timing.cc +++ b/third_party/blink/renderer/core/dom/document_timing.cc
@@ -14,7 +14,7 @@ DocumentTiming::DocumentTiming(Document& document) : document_(document) {} -void DocumentTiming::Trace(blink::Visitor* visitor) { +void DocumentTiming::Trace(Visitor* visitor) { visitor->Trace(document_); }
diff --git a/third_party/blink/renderer/core/dom/document_timing.h b/third_party/blink/renderer/core/dom/document_timing.h index 6fb3303..5aed897 100644 --- a/third_party/blink/renderer/core/dom/document_timing.h +++ b/third_party/blink/renderer/core/dom/document_timing.h
@@ -59,7 +59,7 @@ TimeTicks DomComplete() const { return dom_complete_; } TimeTicks FirstLayout() const { return first_layout_; } - void Trace(blink::Visitor*); + void Trace(Visitor*); private: LocalFrame* GetFrame() const;
diff --git a/third_party/blink/renderer/core/dom/dom_implementation.cc b/third_party/blink/renderer/core/dom/dom_implementation.cc index 3dac1a5a..31d7915 100644 --- a/third_party/blink/renderer/core/dom/dom_implementation.cc +++ b/third_party/blink/renderer/core/dom/dom_implementation.cc
@@ -292,7 +292,7 @@ return HTMLDocument::Create(init); } -void DOMImplementation::Trace(blink::Visitor* visitor) { +void DOMImplementation::Trace(Visitor* visitor) { visitor->Trace(document_); ScriptWrappable::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/dom_implementation.h b/third_party/blink/renderer/core/dom/dom_implementation.h index b30c6f1b..42b802d 100644 --- a/third_party/blink/renderer/core/dom/dom_implementation.h +++ b/third_party/blink/renderer/core/dom/dom_implementation.h
@@ -68,7 +68,7 @@ static bool IsTextMIMEType(const String&); static bool IsJSONMIMEType(const String&); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Member<Document> document_;
diff --git a/third_party/blink/renderer/core/dom/dom_token_list.cc b/third_party/blink/renderer/core/dom/dom_token_list.cc index b4b6a439..b20d2b2 100644 --- a/third_party/blink/renderer/core/dom/dom_token_list.cc +++ b/third_party/blink/renderer/core/dom/dom_token_list.cc
@@ -78,7 +78,7 @@ } // anonymous namespace -void DOMTokenList::Trace(blink::Visitor* visitor) { +void DOMTokenList::Trace(Visitor* visitor) { visitor->Trace(element_); ScriptWrappable::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/dom_token_list.h b/third_party/blink/renderer/core/dom/dom_token_list.h index 00c1f1f..b375512d 100644 --- a/third_party/blink/renderer/core/dom/dom_token_list.h +++ b/third_party/blink/renderer/core/dom/dom_token_list.h
@@ -49,7 +49,7 @@ DOMTokenList(Element& element, const QualifiedName& attr) : element_(element), attribute_name_(attr) {} ~DOMTokenList() override = default; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; unsigned length() const { return token_set_.size(); } const AtomicString item(unsigned index) const;
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 701e545..c971b86 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3357,7 +3357,8 @@ return isConnected() && !IsInert() && IsFocusableStyle() && ((SupportsFocus() && tabIndex() >= 0) || (RuntimeEnabledFeatures::KeyboardFocusableScrollersEnabled() && - IsScrollableNode(this))); + IsScrollableNode(this))) && + !IsDisplayLockedForFocus(); } bool Element::IsMouseFocusable() const { @@ -3365,7 +3366,29 @@ // isn't active (style can't be invalidated in a non-active document). DCHECK(!GetDocument().IsActive() || !GetDocument().NeedsLayoutTreeUpdateForNode(*this)); - return isConnected() && !IsInert() && IsFocusableStyle() && SupportsFocus(); + return isConnected() && !IsInert() && IsFocusableStyle() && SupportsFocus() && + !IsDisplayLockedForFocus(); +} + +bool Element::IsDisplayLockedForFocus() const { + if (!RuntimeEnabledFeatures::DisplayLockingEnabled()) + return false; + // TODO(vmpstr): Similar to Document::EnsurePaintLocationDataValidForNode(), + // this iterates up to the ancestor hierarchy looking for locked display + // locks. This is inefficient, particularly since it's unlikely that this will + // yield any "true" results in practice. We need to come up with a way to + // check whether a node is in a locked subtree quickly. + // See crbug.com/924550 for more details. + for (const Node* current = this; current; + current = current->ParentOrShadowHostNode()) { + if (!current->IsElementNode()) + continue; + if (auto* context = ToElement(current)->GetDisplayLockContext()) { + if (!context->IsSearchable()) + return true; + } + } + return false; } bool Element::IsFocusedElementInDocument() const { @@ -5105,7 +5128,7 @@ activity_logger->LogEvent("blinkSetAttribute", argv.size(), argv.data()); } -void Element::Trace(blink::Visitor* visitor) { +void Element::Trace(Visitor* visitor) { if (HasRareData()) visitor->TraceWithWrappers(GetElementRareData()); visitor->Trace(element_data_);
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h index cc157dc..f4528db 100644 --- a/third_party/blink/renderer/core/dom/element.h +++ b/third_party/blink/renderer/core/dom/element.h
@@ -882,7 +882,7 @@ const char element[], const AttributeModificationParams&); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; SpellcheckAttributeState GetSpellcheckAttributeState() const; @@ -1110,6 +1110,8 @@ void NotifyDisplayLockDidRecalcStyle(); + bool IsDisplayLockedForFocus() const; + Member<ElementData> element_data_; };
diff --git a/third_party/blink/renderer/core/dom/element_data.cc b/third_party/blink/renderer/core/dom/element_data.cc index a772eead..d556fd26 100644 --- a/third_party/blink/renderer/core/dom/element_data.cc +++ b/third_party/blink/renderer/core/dom/element_data.cc
@@ -108,7 +108,7 @@ return true; } -void ElementData::Trace(blink::Visitor* visitor) { +void ElementData::Trace(Visitor* visitor) { if (is_unique_) ToUniqueElementData(this)->TraceAfterDispatch(visitor); else
diff --git a/third_party/blink/renderer/core/dom/element_data.h b/third_party/blink/renderer/core/dom/element_data.h index 7ee0db9a..052ba7b55 100644 --- a/third_party/blink/renderer/core/dom/element_data.h +++ b/third_party/blink/renderer/core/dom/element_data.h
@@ -80,7 +80,7 @@ bool IsUnique() const { return is_unique_; } void TraceAfterDispatch(blink::Visitor*); - void Trace(blink::Visitor*); + void Trace(Visitor*); protected: ElementData();
diff --git a/third_party/blink/renderer/core/dom/element_data_cache.cc b/third_party/blink/renderer/core/dom/element_data_cache.cc index b090762..a729e0f 100644 --- a/third_party/blink/renderer/core/dom/element_data_cache.cc +++ b/third_party/blink/renderer/core/dom/element_data_cache.cc
@@ -64,7 +64,7 @@ ElementDataCache::ElementDataCache() = default; -void ElementDataCache::Trace(blink::Visitor* visitor) { +void ElementDataCache::Trace(Visitor* visitor) { visitor->Trace(shareable_element_data_cache_); }
diff --git a/third_party/blink/renderer/core/dom/element_data_cache.h b/third_party/blink/renderer/core/dom/element_data_cache.h index 9e11542..bf26dba 100644 --- a/third_party/blink/renderer/core/dom/element_data_cache.h +++ b/third_party/blink/renderer/core/dom/element_data_cache.h
@@ -48,7 +48,7 @@ ShareableElementData* CachedShareableElementDataWithAttributes( const Vector<Attribute>&); - void Trace(blink::Visitor*); + void Trace(Visitor*); private: typedef HeapHashMap<unsigned, Member<ShareableElementData>, AlreadyHashed>
diff --git a/third_party/blink/renderer/core/dom/element_visibility_observer.cc b/third_party/blink/renderer/core/dom/element_visibility_observer.cc index 912ea5fd..2ce69d3 100644 --- a/third_party/blink/renderer/core/dom/element_visibility_observer.cc +++ b/third_party/blink/renderer/core/dom/element_visibility_observer.cc
@@ -45,7 +45,7 @@ intersection_observer_->Deliver(); } -void ElementVisibilityObserver::Trace(blink::Visitor* visitor) { +void ElementVisibilityObserver::Trace(Visitor* visitor) { visitor->Trace(element_); visitor->Trace(intersection_observer_); }
diff --git a/third_party/blink/renderer/core/dom/element_visibility_observer.h b/third_party/blink/renderer/core/dom/element_visibility_observer.h index 34e1e08a..c095713 100644 --- a/third_party/blink/renderer/core/dom/element_visibility_observer.h +++ b/third_party/blink/renderer/core/dom/element_visibility_observer.h
@@ -43,7 +43,7 @@ void DeliverObservationsForTesting(); - virtual void Trace(blink::Visitor*); + virtual void Trace(Visitor*); private: class ElementVisibilityCallback;
diff --git a/third_party/blink/renderer/core/dom/empty_node_list.cc b/third_party/blink/renderer/core/dom/empty_node_list.cc index 01cc7ca6..7edbab9 100644 --- a/third_party/blink/renderer/core/dom/empty_node_list.cc +++ b/third_party/blink/renderer/core/dom/empty_node_list.cc
@@ -42,7 +42,7 @@ return &OwnerNode(); } -void EmptyNodeList::Trace(blink::Visitor* visitor) { +void EmptyNodeList::Trace(Visitor* visitor) { visitor->Trace(owner_); NodeList::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/empty_node_list.h b/third_party/blink/renderer/core/dom/empty_node_list.h index 85b73df..8e835b8 100644 --- a/third_party/blink/renderer/core/dom/empty_node_list.h +++ b/third_party/blink/renderer/core/dom/empty_node_list.h
@@ -47,7 +47,7 @@ Node& OwnerNode() const { return *owner_; } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: unsigned length() const override { return 0; }
diff --git a/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.cc b/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.cc index 746d8e4d..711feae9 100644 --- a/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.cc +++ b/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.cc
@@ -25,7 +25,7 @@ AddEventListenerOptionsResolved::~AddEventListenerOptionsResolved() = default; -void AddEventListenerOptionsResolved::Trace(blink::Visitor* visitor) { +void AddEventListenerOptionsResolved::Trace(Visitor* visitor) { AddEventListenerOptions::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h b/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h index b2e5753..e6872ac9 100644 --- a/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h +++ b/third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h
@@ -40,7 +40,7 @@ void SetPassiveSpecified(bool specified) { passive_specified_ = specified; } bool PassiveSpecified() const { return passive_specified_; } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: bool passive_forced_for_document_target_;
diff --git a/third_party/blink/renderer/core/dom/events/custom_event.cc b/third_party/blink/renderer/core/dom/events/custom_event.cc index 4316f9a7..2c4de684 100644 --- a/third_party/blink/renderer/core/dom/events/custom_event.cc +++ b/third_party/blink/renderer/core/dom/events/custom_event.cc
@@ -64,7 +64,7 @@ return event_interface_names::kCustomEvent; } -void CustomEvent::Trace(blink::Visitor* visitor) { +void CustomEvent::Trace(Visitor* visitor) { visitor->Trace(detail_); Event::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/events/custom_event.h b/third_party/blink/renderer/core/dom/events/custom_event.h index a44b05ab..3cce5f21c 100644 --- a/third_party/blink/renderer/core/dom/events/custom_event.h +++ b/third_party/blink/renderer/core/dom/events/custom_event.h
@@ -62,7 +62,7 @@ ScriptValue detail(ScriptState*) const; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: WorldSafeV8Reference<v8::Value> detail_;
diff --git a/third_party/blink/renderer/core/dom/events/event.cc b/third_party/blink/renderer/core/dom/events/event.cc index 7b3b0bf..a1e0e64c 100644 --- a/third_party/blink/renderer/core/dom/events/event.cc +++ b/third_party/blink/renderer/core/dom/events/event.cc
@@ -394,7 +394,7 @@ return dispatcher.Dispatch(); } -void Event::Trace(blink::Visitor* visitor) { +void Event::Trace(Visitor* visitor) { visitor->Trace(current_target_); visitor->Trace(target_); visitor->Trace(underlying_event_);
diff --git a/third_party/blink/renderer/core/dom/events/event.h b/third_party/blink/renderer/core/dom/events/event.h index c0570f71f..8c35bc5 100644 --- a/third_party/blink/renderer/core/dom/events/event.h +++ b/third_party/blink/renderer/core/dom/events/event.h
@@ -317,7 +317,7 @@ virtual DispatchEventResult DispatchEvent(EventDispatcher&); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; protected: virtual void ReceivedTarget();
diff --git a/third_party/blink/renderer/core/dom/events/event_dispatcher.h b/third_party/blink/renderer/core/dom/events/event_dispatcher.h index e09e49f..59eba27 100644 --- a/third_party/blink/renderer/core/dom/events/event_dispatcher.h +++ b/third_party/blink/renderer/core/dom/events/event_dispatcher.h
@@ -43,7 +43,7 @@ class EventDispatchHandlingState : public GarbageCollected<EventDispatchHandlingState> { public: - virtual void Trace(blink::Visitor* visitor) {} + virtual void Trace(Visitor* visitor) {} }; enum EventDispatchContinuation { kContinueDispatching, kDoneDispatching };
diff --git a/third_party/blink/renderer/core/dom/events/event_listener_map.cc b/third_party/blink/renderer/core/dom/events/event_listener_map.cc index f508802e..b6f19c4 100644 --- a/third_party/blink/renderer/core/dom/events/event_listener_map.cc +++ b/third_party/blink/renderer/core/dom/events/event_listener_map.cc
@@ -207,7 +207,7 @@ } } -void EventListenerMap::Trace(blink::Visitor* visitor) { +void EventListenerMap::Trace(Visitor* visitor) { visitor->Trace(entries_); }
diff --git a/third_party/blink/renderer/core/dom/events/event_listener_map.h b/third_party/blink/renderer/core/dom/events/event_listener_map.h index 57da2d1..0c16cfe 100644 --- a/third_party/blink/renderer/core/dom/events/event_listener_map.h +++ b/third_party/blink/renderer/core/dom/events/event_listener_map.h
@@ -72,7 +72,7 @@ void CopyEventListenersNotCreatedFromMarkupToTarget(EventTarget*); - void Trace(blink::Visitor*); + void Trace(Visitor*); private: friend class EventListenerIterator;
diff --git a/third_party/blink/renderer/core/dom/events/event_path.cc b/third_party/blink/renderer/core/dom/events/event_path.cc index a353eb9..d5bc6014 100644 --- a/third_party/blink/renderer/core/dom/events/event_path.cc +++ b/third_party/blink/renderer/core/dom/events/event_path.cc
@@ -417,7 +417,7 @@ } #endif -void EventPath::Trace(blink::Visitor* visitor) { +void EventPath::Trace(Visitor* visitor) { visitor->Trace(node_event_contexts_); visitor->Trace(node_); visitor->Trace(event_);
diff --git a/third_party/blink/renderer/core/dom/events/event_path.h b/third_party/blink/renderer/core/dom/events/event_path.h index be0d71d..07102f25 100644 --- a/third_party/blink/renderer/core/dom/events/event_path.h +++ b/third_party/blink/renderer/core/dom/events/event_path.h
@@ -83,7 +83,7 @@ static EventTarget& EventTargetRespectingTargetRules(Node&); - void Trace(blink::Visitor*); + void Trace(Visitor*); void Clear() { node_event_contexts_.clear(); tree_scope_event_contexts_.clear();
diff --git a/third_party/blink/renderer/core/dom/events/event_queue.cc b/third_party/blink/renderer/core/dom/events/event_queue.cc index 55abadf3..b3cb21d 100644 --- a/third_party/blink/renderer/core/dom/events/event_queue.cc +++ b/third_party/blink/renderer/core/dom/events/event_queue.cc
@@ -48,7 +48,7 @@ EventQueue::~EventQueue() = default; -void EventQueue::Trace(blink::Visitor* visitor) { +void EventQueue::Trace(Visitor* visitor) { visitor->Trace(queued_events_); ContextLifecycleObserver::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/events/event_queue.h b/third_party/blink/renderer/core/dom/events/event_queue.h index a1ecfb3d..35e60f3 100644 --- a/third_party/blink/renderer/core/dom/events/event_queue.h +++ b/third_party/blink/renderer/core/dom/events/event_queue.h
@@ -47,7 +47,7 @@ EventQueue(ExecutionContext*, TaskType); ~EventQueue(); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; bool EnqueueEvent(const base::Location&, Event&); void CancelAllEvents(); bool HasPendingEvents() const;
diff --git a/third_party/blink/renderer/core/dom/events/event_target.cc b/third_party/blink/renderer/core/dom/events/event_target.cc index 38ce598..a14c537 100644 --- a/third_party/blink/renderer/core/dom/events/event_target.cc +++ b/third_party/blink/renderer/core/dom/events/event_target.cc
@@ -162,7 +162,7 @@ EventTargetData::~EventTargetData() = default; -void EventTargetData::Trace(blink::Visitor* visitor) { +void EventTargetData::Trace(Visitor* visitor) { visitor->Trace(event_listener_map); }
diff --git a/third_party/blink/renderer/core/dom/events/event_target.h b/third_party/blink/renderer/core/dom/events/event_target.h index 119beb0e..60fa150 100644 --- a/third_party/blink/renderer/core/dom/events/event_target.h +++ b/third_party/blink/renderer/core/dom/events/event_target.h
@@ -81,7 +81,7 @@ EventTargetData(); ~EventTargetData(); - void Trace(blink::Visitor*); + void Trace(Visitor*); EventListenerMap event_listener_map; std::unique_ptr<FiringEventIteratorVector> firing_event_iterators; @@ -237,7 +237,7 @@ public: ~EventTargetWithInlineData() override = default; - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(event_target_data_); EventTarget::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/events/event_target_impl.cc b/third_party/blink/renderer/core/dom/events/event_target_impl.cc index 91a841a..7ffa91a 100644 --- a/third_party/blink/renderer/core/dom/events/event_target_impl.cc +++ b/third_party/blink/renderer/core/dom/events/event_target_impl.cc
@@ -18,7 +18,7 @@ return ContextLifecycleObserver::GetExecutionContext(); } -void EventTargetImpl::Trace(blink::Visitor* visitor) { +void EventTargetImpl::Trace(Visitor* visitor) { EventTargetWithInlineData::Trace(visitor); ContextLifecycleObserver::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/events/event_target_impl.h b/third_party/blink/renderer/core/dom/events/event_target_impl.h index 77fe99923..42f33ac 100644 --- a/third_party/blink/renderer/core/dom/events/event_target_impl.h +++ b/third_party/blink/renderer/core/dom/events/event_target_impl.h
@@ -32,7 +32,7 @@ const AtomicString& InterfaceName() const override; ExecutionContext* GetExecutionContext() const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/events/node_event_context.cc b/third_party/blink/renderer/core/dom/events/node_event_context.cc index 16d2610..ff6a94f 100644 --- a/third_party/blink/renderer/core/dom/events/node_event_context.cc +++ b/third_party/blink/renderer/core/dom/events/node_event_context.cc
@@ -38,7 +38,7 @@ NodeEventContext::NodeEventContext(Node& node, EventTarget& current_target) : node_(node), current_target_(current_target) {} -void NodeEventContext::Trace(blink::Visitor* visitor) { +void NodeEventContext::Trace(Visitor* visitor) { visitor->Trace(node_); visitor->Trace(current_target_); visitor->Trace(tree_scope_event_context_);
diff --git a/third_party/blink/renderer/core/dom/events/node_event_context.h b/third_party/blink/renderer/core/dom/events/node_event_context.h index 21c2ca2..feb59f0 100644 --- a/third_party/blink/renderer/core/dom/events/node_event_context.h +++ b/third_party/blink/renderer/core/dom/events/node_event_context.h
@@ -43,7 +43,7 @@ public: // FIXME: Use ContainerNode instead of Node. NodeEventContext(Node&, EventTarget& current_target); - void Trace(blink::Visitor*); + void Trace(Visitor*); Node& GetNode() const { return *node_; }
diff --git a/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc b/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc index 2133bac4..5d9e768 100644 --- a/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc +++ b/third_party/blink/renderer/core/dom/events/tree_scope_event_context.cc
@@ -96,7 +96,7 @@ pre_order_(-1), post_order_(-1) {} -void TreeScopeEventContext::Trace(blink::Visitor* visitor) { +void TreeScopeEventContext::Trace(Visitor* visitor) { visitor->Trace(tree_scope_); visitor->Trace(target_); visitor->Trace(related_target_);
diff --git a/third_party/blink/renderer/core/dom/events/tree_scope_event_context.h b/third_party/blink/renderer/core/dom/events/tree_scope_event_context.h index eac6b4a..b3aaa54 100644 --- a/third_party/blink/renderer/core/dom/events/tree_scope_event_context.h +++ b/third_party/blink/renderer/core/dom/events/tree_scope_event_context.h
@@ -50,7 +50,7 @@ static TreeScopeEventContext* Create(TreeScope&); TreeScopeEventContext(TreeScope&); - void Trace(blink::Visitor*); + void Trace(Visitor*); TreeScope& GetTreeScope() const { return *tree_scope_; } ContainerNode& RootNode() const { return tree_scope_->RootNode(); }
diff --git a/third_party/blink/renderer/core/dom/events/window_event_context.cc b/third_party/blink/renderer/core/dom/events/window_event_context.cc index 3e3de47..abf6206 100644 --- a/third_party/blink/renderer/core/dom/events/window_event_context.cc +++ b/third_party/blink/renderer/core/dom/events/window_event_context.cc
@@ -61,7 +61,7 @@ return true; } -void WindowEventContext::Trace(blink::Visitor* visitor) { +void WindowEventContext::Trace(Visitor* visitor) { visitor->Trace(window_); visitor->Trace(target_); visitor->Trace(related_target_);
diff --git a/third_party/blink/renderer/core/dom/events/window_event_context.h b/third_party/blink/renderer/core/dom/events/window_event_context.h index 07d72e5..3f95a3e 100644 --- a/third_party/blink/renderer/core/dom/events/window_event_context.h +++ b/third_party/blink/renderer/core/dom/events/window_event_context.h
@@ -46,7 +46,7 @@ EventTarget* RelatedTarget() const; bool HandleLocalEvents(Event&); - void Trace(blink::Visitor*); + void Trace(Visitor*); private: Member<LocalDOMWindow> window_;
diff --git a/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc b/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc index 02b71b6..b101838c 100644 --- a/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc +++ b/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc
@@ -88,7 +88,7 @@ callbacks_to_invoke_.clear(); } -void FrameRequestCallbackCollection::Trace(blink::Visitor* visitor) { +void FrameRequestCallbackCollection::Trace(Visitor* visitor) { visitor->Trace(callbacks_); visitor->Trace(callbacks_to_invoke_); visitor->Trace(context_);
diff --git a/third_party/blink/renderer/core/dom/frame_request_callback_collection.h b/third_party/blink/renderer/core/dom/frame_request_callback_collection.h index 3d69e24d..de0dec3 100644 --- a/third_party/blink/renderer/core/dom/frame_request_callback_collection.h +++ b/third_party/blink/renderer/core/dom/frame_request_callback_collection.h
@@ -31,7 +31,7 @@ : public GarbageCollectedFinalized<FrameCallback>, public NameClient { public: - virtual void Trace(blink::Visitor* visitor) {} + virtual void Trace(Visitor* visitor) {} const char* NameInHeapSnapshot() const override { return "FrameCallback"; } virtual ~FrameCallback() = default; virtual void Invoke(double) = 0; @@ -61,7 +61,7 @@ static V8FrameCallback* Create(V8FrameRequestCallback* callback) { return MakeGarbageCollected<V8FrameCallback>(callback); } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; const char* NameInHeapSnapshot() const override { return "V8FrameCallback"; } @@ -81,7 +81,7 @@ bool IsEmpty() const { return !callbacks_.size(); } - void Trace(blink::Visitor*); + void Trace(Visitor*); const char* NameInHeapSnapshot() const override { return "FrameRequestCallbackCollection"; }
diff --git a/third_party/blink/renderer/core/dom/id_target_observer.cc b/third_party/blink/renderer/core/dom/id_target_observer.cc index a4efa5a..2df3ab5f 100644 --- a/third_party/blink/renderer/core/dom/id_target_observer.cc +++ b/third_party/blink/renderer/core/dom/id_target_observer.cc
@@ -37,7 +37,7 @@ IdTargetObserver::~IdTargetObserver() = default; -void IdTargetObserver::Trace(blink::Visitor* visitor) { +void IdTargetObserver::Trace(Visitor* visitor) { visitor->Trace(registry_); }
diff --git a/third_party/blink/renderer/core/dom/id_target_observer.h b/third_party/blink/renderer/core/dom/id_target_observer.h index 69ae025..13bce1c 100644 --- a/third_party/blink/renderer/core/dom/id_target_observer.h +++ b/third_party/blink/renderer/core/dom/id_target_observer.h
@@ -36,7 +36,7 @@ class IdTargetObserver : public GarbageCollectedFinalized<IdTargetObserver> { public: virtual ~IdTargetObserver(); - virtual void Trace(blink::Visitor*); + virtual void Trace(Visitor*); virtual void IdTargetChanged() = 0; virtual void Unregister();
diff --git a/third_party/blink/renderer/core/dom/id_target_observer_registry.cc b/third_party/blink/renderer/core/dom/id_target_observer_registry.cc index 7c73ad21e..3c8baed1 100644 --- a/third_party/blink/renderer/core/dom/id_target_observer_registry.cc +++ b/third_party/blink/renderer/core/dom/id_target_observer_registry.cc
@@ -33,7 +33,7 @@ return MakeGarbageCollected<IdTargetObserverRegistry>(); } -void IdTargetObserverRegistry::Trace(blink::Visitor* visitor) { +void IdTargetObserverRegistry::Trace(Visitor* visitor) { visitor->Trace(registry_); visitor->Trace(notifying_observers_in_set_); }
diff --git a/third_party/blink/renderer/core/dom/id_target_observer_registry.h b/third_party/blink/renderer/core/dom/id_target_observer_registry.h index fd7d789..bb55fe6 100644 --- a/third_party/blink/renderer/core/dom/id_target_observer_registry.h +++ b/third_party/blink/renderer/core/dom/id_target_observer_registry.h
@@ -46,7 +46,7 @@ IdTargetObserverRegistry() : notifying_observers_in_set_(nullptr) {} - void Trace(blink::Visitor*); + void Trace(Visitor*); void NotifyObservers(const AtomicString& id); bool HasObservers(const AtomicString& id) const;
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder.cc b/third_party/blink/renderer/core/dom/layout_tree_builder.cc index 24f2266..0ab2778a 100644 --- a/third_party/blink/renderer/core/dom/layout_tree_builder.cc +++ b/third_party/blink/renderer/core/dom/layout_tree_builder.cc
@@ -292,7 +292,7 @@ state_ = State::kClosed; } -void ReattachLegacyLayoutObjectList::Trace(blink::Visitor* visitor) { +void ReattachLegacyLayoutObjectList::Trace(Visitor* visitor) { visitor->Trace(document_); }
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder.h b/third_party/blink/renderer/core/dom/layout_tree_builder.h index 1f565a3..ab2f711 100644 --- a/third_party/blink/renderer/core/dom/layout_tree_builder.h +++ b/third_party/blink/renderer/core/dom/layout_tree_builder.h
@@ -157,7 +157,7 @@ } void ForceLegacyLayoutIfNeeded(); - void Trace(blink::Visitor*); + void Trace(Visitor*); private: Member<Document> document_;
diff --git a/third_party/blink/renderer/core/dom/live_node_list.cc b/third_party/blink/renderer/core/dom/live_node_list.cc index 4be5c8db9..cb200589 100644 --- a/third_party/blink/renderer/core/dom/live_node_list.cc +++ b/third_party/blink/renderer/core/dom/live_node_list.cc
@@ -88,7 +88,7 @@ current_element, &RootNode(), offset, current_offset, IsMatch(*this)); } -void LiveNodeList::Trace(blink::Visitor* visitor) { +void LiveNodeList::Trace(Visitor* visitor) { visitor->Trace(collection_items_cache_); LiveNodeListBase::Trace(visitor); NodeList::Trace(visitor);
diff --git a/third_party/blink/renderer/core/dom/live_node_list.h b/third_party/blink/renderer/core/dom/live_node_list.h index b4dcb24..37f27fe 100644 --- a/third_party/blink/renderer/core/dom/live_node_list.h +++ b/third_party/blink/renderer/core/dom/live_node_list.h
@@ -71,7 +71,7 @@ Element& current_node, unsigned& current_offset) const; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Node* VirtualOwnerNode() const final;
diff --git a/third_party/blink/renderer/core/dom/live_node_list_base.h b/third_party/blink/renderer/core/dom/live_node_list_base.h index 2a1d029..0884032 100644 --- a/third_party/blink/renderer/core/dom/live_node_list_base.h +++ b/third_party/blink/renderer/core/dom/live_node_list_base.h
@@ -77,7 +77,7 @@ static bool ShouldInvalidateTypeOnAttributeChange(NodeListInvalidationType, const QualifiedName&); - void Trace(blink::Visitor* visitor) override { visitor->Trace(owner_node_); } + void Trace(Visitor* visitor) override { visitor->Trace(owner_node_); } protected: Document& GetDocument() const { return owner_node_->GetDocument(); }
diff --git a/third_party/blink/renderer/core/dom/live_node_list_registry.cc b/third_party/blink/renderer/core/dom/live_node_list_registry.cc index 1ca504d3..bb032edd 100644 --- a/third_party/blink/renderer/core/dom/live_node_list_registry.cc +++ b/third_party/blink/renderer/core/dom/live_node_list_registry.cc
@@ -30,7 +30,7 @@ RecomputeMask(); } -void LiveNodeListRegistry::Trace(blink::Visitor* visitor) { +void LiveNodeListRegistry::Trace(Visitor* visitor) { visitor->RegisterWeakMembers<LiveNodeListRegistry, &LiveNodeListRegistry::ClearWeakMembers>(this); }
diff --git a/third_party/blink/renderer/core/dom/live_node_list_registry.h b/third_party/blink/renderer/core/dom/live_node_list_registry.h index ae72920d..fb4b87d 100644 --- a/third_party/blink/renderer/core/dom/live_node_list_registry.h +++ b/third_party/blink/renderer/core/dom/live_node_list_registry.h
@@ -45,7 +45,7 @@ return mask_ & MaskForInvalidationType(type); } - void Trace(blink::Visitor*); + void Trace(Visitor*); private: static inline unsigned MaskForInvalidationType(
diff --git a/third_party/blink/renderer/core/dom/live_node_list_registry_test.cc b/third_party/blink/renderer/core/dom/live_node_list_registry_test.cc index 6b38ef7..1078380 100644 --- a/third_party/blink/renderer/core/dom/live_node_list_registry_test.cc +++ b/third_party/blink/renderer/core/dom/live_node_list_registry_test.cc
@@ -101,7 +101,7 @@ struct LiveNodeListRegistryWrapper : public GarbageCollectedFinalized<LiveNodeListRegistryWrapper> { LiveNodeListRegistry registry; - void Trace(blink::Visitor* visitor) { visitor->Trace(registry); } + void Trace(Visitor* visitor) { visitor->Trace(registry); } }; // The set of types which match should be updated as elements are removed due to
diff --git a/third_party/blink/renderer/core/dom/mutation_observer.cc b/third_party/blink/renderer/core/dom/mutation_observer.cc index 34227f7..a14b7aa 100644 --- a/third_party/blink/renderer/core/dom/mutation_observer.cc +++ b/third_party/blink/renderer/core/dom/mutation_observer.cc
@@ -73,7 +73,7 @@ callback_->InvokeAndReportException(&observer, records, &observer); } - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(callback_); MutationObserver::Delegate::Trace(visitor); ContextClient::Trace(visitor); @@ -372,7 +372,7 @@ slot->DispatchSlotChangeEvent(); } -void MutationObserver::Trace(blink::Visitor* visitor) { +void MutationObserver::Trace(Visitor* visitor) { visitor->Trace(delegate_); visitor->Trace(records_); visitor->Trace(registrations_);
diff --git a/third_party/blink/renderer/core/dom/mutation_observer.h b/third_party/blink/renderer/core/dom/mutation_observer.h index 5013393..b4dfc59 100644 --- a/third_party/blink/renderer/core/dom/mutation_observer.h +++ b/third_party/blink/renderer/core/dom/mutation_observer.h
@@ -85,7 +85,7 @@ virtual ExecutionContext* GetExecutionContext() const = 0; virtual void Deliver(const MutationRecordVector& records, MutationObserver&) = 0; - virtual void Trace(blink::Visitor* visitor) {} + virtual void Trace(Visitor* visitor) {} const char* NameInHeapSnapshot() const override { return "MutationObserver::Delegate"; } @@ -117,7 +117,7 @@ // Eagerly finalized as destructor accesses heap object members. EAGERLY_FINALIZE(); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: struct ObserverLessThan;
diff --git a/third_party/blink/renderer/core/dom/mutation_observer_interest_group.cc b/third_party/blink/renderer/core/dom/mutation_observer_interest_group.cc index e6c553e..899ff635 100644 --- a/third_party/blink/renderer/core/dom/mutation_observer_interest_group.cc +++ b/third_party/blink/renderer/core/dom/mutation_observer_interest_group.cc
@@ -88,7 +88,7 @@ } } -void MutationObserverInterestGroup::Trace(blink::Visitor* visitor) { +void MutationObserverInterestGroup::Trace(Visitor* visitor) { visitor->Trace(observers_); }
diff --git a/third_party/blink/renderer/core/dom/mutation_observer_interest_group.h b/third_party/blink/renderer/core/dom/mutation_observer_interest_group.h index 341a5cbd..966474e 100644 --- a/third_party/blink/renderer/core/dom/mutation_observer_interest_group.h +++ b/third_party/blink/renderer/core/dom/mutation_observer_interest_group.h
@@ -83,7 +83,7 @@ bool IsOldValueRequested(); void EnqueueMutationRecord(MutationRecord*); - void Trace(blink::Visitor*); + void Trace(Visitor*); private: static MutationObserverInterestGroup* CreateIfNeeded(
diff --git a/third_party/blink/renderer/core/dom/mutation_observer_registration.cc b/third_party/blink/renderer/core/dom/mutation_observer_registration.cc index 156a106e..cb96ce5 100644 --- a/third_party/blink/renderer/core/dom/mutation_observer_registration.cc +++ b/third_party/blink/renderer/core/dom/mutation_observer_registration.cc
@@ -148,7 +148,7 @@ nodes.insert(iter->Get()); } -void MutationObserverRegistration::Trace(blink::Visitor* visitor) { +void MutationObserverRegistration::Trace(Visitor* visitor) { visitor->Trace(observer_); visitor->Trace(registration_node_); visitor->Trace(registration_node_keep_alive_);
diff --git a/third_party/blink/renderer/core/dom/mutation_observer_registration.h b/third_party/blink/renderer/core/dom/mutation_observer_registration.h index bfcff43..57ee473 100644 --- a/third_party/blink/renderer/core/dom/mutation_observer_registration.h +++ b/third_party/blink/renderer/core/dom/mutation_observer_registration.h
@@ -88,7 +88,7 @@ void Dispose(); - void Trace(blink::Visitor*); + void Trace(Visitor*); const char* NameInHeapSnapshot() const override { return "MutationObserverRegistration"; }
diff --git a/third_party/blink/renderer/core/dom/mutation_observer_test.cc b/third_party/blink/renderer/core/dom/mutation_observer_test.cc index 2018836..63598f40 100644 --- a/third_party/blink/renderer/core/dom/mutation_observer_test.cc +++ b/third_party/blink/renderer/core/dom/mutation_observer_test.cc
@@ -22,7 +22,7 @@ void Deliver(const MutationRecordVector&, MutationObserver&) override {} - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(document_); MutationObserver::Delegate::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/mutation_record.cc b/third_party/blink/renderer/core/dom/mutation_record.cc index e8096d29..c4909cd8 100644 --- a/third_party/blink/renderer/core/dom/mutation_record.cc +++ b/third_party/blink/renderer/core/dom/mutation_record.cc
@@ -53,7 +53,7 @@ previous_sibling_(previous_sibling), next_sibling_(next_sibling) {} - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(target_); visitor->Trace(added_nodes_); visitor->Trace(removed_nodes_); @@ -82,7 +82,7 @@ RecordWithEmptyNodeLists(Node* target, const String& old_value) : target_(target), old_value_(old_value) {} - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(target_); visitor->Trace(added_nodes_); visitor->Trace(removed_nodes_); @@ -145,7 +145,7 @@ public: MutationRecordWithNullOldValue(MutationRecord* record) : record_(record) {} - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(record_); MutationRecord::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/named_node_map.cc b/third_party/blink/renderer/core/dom/named_node_map.cc index f0b19a3..af97e374 100644 --- a/third_party/blink/renderer/core/dom/named_node_map.cc +++ b/third_party/blink/renderer/core/dom/named_node_map.cc
@@ -126,7 +126,7 @@ return properties.Contains(name); } -void NamedNodeMap::Trace(blink::Visitor* visitor) { +void NamedNodeMap::Trace(Visitor* visitor) { visitor->Trace(element_); ScriptWrappable::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/named_node_map.h b/third_party/blink/renderer/core/dom/named_node_map.h index a8209b6c..4e7b144f 100644 --- a/third_party/blink/renderer/core/dom/named_node_map.h +++ b/third_party/blink/renderer/core/dom/named_node_map.h
@@ -69,7 +69,7 @@ void NamedPropertyEnumerator(Vector<String>& names, ExceptionState&) const; bool NamedPropertyQuery(const AtomicString&, ExceptionState&) const; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Member<Element> element_;
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc index 52b8672..651594a 100644 --- a/third_party/blink/renderer/core/dom/node.cc +++ b/third_party/blink/renderer/core/dom/node.cc
@@ -3038,7 +3038,7 @@ return false; } -void Node::Trace(blink::Visitor* visitor) { +void Node::Trace(Visitor* visitor) { visitor->Trace(parent_or_shadow_host_node_); visitor->Trace(previous_); visitor->Trace(next_);
diff --git a/third_party/blink/renderer/core/dom/node.h b/third_party/blink/renderer/core/dom/node.h index d6c090e..9d10e86 100644 --- a/third_party/blink/renderer/core/dom/node.h +++ b/third_party/blink/renderer/core/dom/node.h
@@ -886,7 +886,7 @@ // If the node is a plugin, then this returns its WebPluginContainer. WebPluginContainerImpl* GetWebPluginContainer() const; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: enum NodeFlags {
diff --git a/third_party/blink/renderer/core/dom/node_iterator.cc b/third_party/blink/renderer/core/dom/node_iterator.cc index 7c514b0..a54a1aa 100644 --- a/third_party/blink/renderer/core/dom/node_iterator.cc +++ b/third_party/blink/renderer/core/dom/node_iterator.cc
@@ -199,7 +199,7 @@ } } -void NodeIterator::Trace(blink::Visitor* visitor) { +void NodeIterator::Trace(Visitor* visitor) { visitor->Trace(reference_node_); visitor->Trace(candidate_node_); ScriptWrappable::Trace(visitor);
diff --git a/third_party/blink/renderer/core/dom/node_iterator.h b/third_party/blink/renderer/core/dom/node_iterator.h index b3707560..4ad2a3b 100644 --- a/third_party/blink/renderer/core/dom/node_iterator.h +++ b/third_party/blink/renderer/core/dom/node_iterator.h
@@ -58,7 +58,7 @@ // This function is called before any node is removed from the document tree. void NodeWillBeRemoved(Node&); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: class NodePointer { @@ -75,7 +75,7 @@ Member<Node> node; bool is_pointer_before_node; - void Trace(blink::Visitor* visitor) { visitor->Trace(node); } + void Trace(Visitor* visitor) { visitor->Trace(node); } }; void UpdateForNodeRemoval(Node& node_to_be_removed, NodePointer&) const;
diff --git a/third_party/blink/renderer/core/dom/node_iterator_base.cc b/third_party/blink/renderer/core/dom/node_iterator_base.cc index 6835dd7..5c09ca0 100644 --- a/third_party/blink/renderer/core/dom/node_iterator_base.cc +++ b/third_party/blink/renderer/core/dom/node_iterator_base.cc
@@ -88,7 +88,7 @@ return result; } -void NodeIteratorBase::Trace(blink::Visitor* visitor) { +void NodeIteratorBase::Trace(Visitor* visitor) { visitor->Trace(root_); visitor->Trace(filter_); }
diff --git a/third_party/blink/renderer/core/dom/node_iterator_base.h b/third_party/blink/renderer/core/dom/node_iterator_base.h index d58dcf6..f90d919 100644 --- a/third_party/blink/renderer/core/dom/node_iterator_base.h +++ b/third_party/blink/renderer/core/dom/node_iterator_base.h
@@ -42,7 +42,7 @@ unsigned whatToShow() const { return what_to_show_; } V8NodeFilter* filter() const { return filter_.Get(); } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; protected: NodeIteratorBase(Node*, unsigned what_to_show, V8NodeFilter*);
diff --git a/third_party/blink/renderer/core/dom/node_lists_node_data.cc b/third_party/blink/renderer/core/dom/node_lists_node_data.cc index dfa31e4f..055dc5a 100644 --- a/third_party/blink/renderer/core/dom/node_lists_node_data.cc +++ b/third_party/blink/renderer/core/dom/node_lists_node_data.cc
@@ -45,7 +45,7 @@ cache.value->InvalidateCache(); } -void NodeListsNodeData::Trace(blink::Visitor* visitor) { +void NodeListsNodeData::Trace(Visitor* visitor) { visitor->Trace(child_node_list_); visitor->Trace(atomic_name_caches_); visitor->Trace(tag_collection_ns_caches_);
diff --git a/third_party/blink/renderer/core/dom/node_lists_node_data.h b/third_party/blink/renderer/core/dom/node_lists_node_data.h index e562e8b..246d997b 100644 --- a/third_party/blink/renderer/core/dom/node_lists_node_data.h +++ b/third_party/blink/renderer/core/dom/node_lists_node_data.h
@@ -174,7 +174,7 @@ } } - void Trace(blink::Visitor*); + void Trace(Visitor*); private: // Can be a ChildNodeList or an EmptyNodeList.
diff --git a/third_party/blink/renderer/core/dom/node_rare_data.cc b/third_party/blink/renderer/core/dom/node_rare_data.cc index 89c6f58..8ec8440 100644 --- a/third_party/blink/renderer/core/dom/node_rare_data.cc +++ b/third_party/blink/renderer/core/dom/node_rare_data.cc
@@ -55,7 +55,7 @@ static_assert(sizeof(NodeRareData) == sizeof(SameSizeAsNodeRareData), "NodeRareData should stay small"); -void NodeMutationObserverData::Trace(blink::Visitor* visitor) { +void NodeMutationObserverData::Trace(Visitor* visitor) { visitor->Trace(registry_); visitor->Trace(transient_registry_); } @@ -92,7 +92,7 @@ visitor->Trace(node_lists_); } -void NodeRareData::Trace(blink::Visitor* visitor) { +void NodeRareData::Trace(Visitor* visitor) { if (is_element_rare_data_) static_cast<ElementRareData*>(this)->TraceAfterDispatch(visitor); else
diff --git a/third_party/blink/renderer/core/dom/node_rare_data.h b/third_party/blink/renderer/core/dom/node_rare_data.h index 2e4ec9c..fe3e6ca 100644 --- a/third_party/blink/renderer/core/dom/node_rare_data.h +++ b/third_party/blink/renderer/core/dom/node_rare_data.h
@@ -59,7 +59,7 @@ void AddRegistration(MutationObserverRegistration* registration); void RemoveRegistration(MutationObserverRegistration* registration); - void Trace(blink::Visitor* visitor); + void Trace(Visitor* visitor); private: HeapVector<TraceWrapperMember<MutationObserverRegistration>> registry_; @@ -191,7 +191,7 @@ kNumberOfDynamicRestyleFlags = 14 }; - void Trace(blink::Visitor*); + void Trace(Visitor*); void TraceAfterDispatch(blink::Visitor*); void FinalizeGarbageCollectedObject();
diff --git a/third_party/blink/renderer/core/dom/nth_index_cache.cc b/third_party/blink/renderer/core/dom/nth_index_cache.cc index 8c31f85..ead53713 100644 --- a/third_party/blink/renderer/core/dom/nth_index_cache.cc +++ b/third_party/blink/renderer/core/dom/nth_index_cache.cc
@@ -257,7 +257,7 @@ count_ = count; } -void NthIndexData::Trace(blink::Visitor* visitor) { +void NthIndexData::Trace(Visitor* visitor) { visitor->Trace(element_index_map_); }
diff --git a/third_party/blink/renderer/core/dom/nth_index_cache.h b/third_party/blink/renderer/core/dom/nth_index_cache.h index 1b9a9ccc..b2aa37a7 100644 --- a/third_party/blink/renderer/core/dom/nth_index_cache.h +++ b/third_party/blink/renderer/core/dom/nth_index_cache.h
@@ -25,7 +25,7 @@ unsigned NthOfTypeIndex(Element&) const; unsigned NthLastOfTypeIndex(Element&) const; - void Trace(blink::Visitor*); + void Trace(Visitor*); private: HeapHashMap<Member<Element>, unsigned> element_index_map_;
diff --git a/third_party/blink/renderer/core/dom/presentation_attribute_style.cc b/third_party/blink/renderer/core/dom/presentation_attribute_style.cc index 78e52699..c4591614 100644 --- a/third_party/blink/renderer/core/dom/presentation_attribute_style.cc +++ b/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
@@ -64,7 +64,7 @@ struct PresentationAttributeCacheEntry final : public GarbageCollectedFinalized<PresentationAttributeCacheEntry> { public: - void Trace(blink::Visitor* visitor) { visitor->Trace(value); } + void Trace(Visitor* visitor) { visitor->Trace(value); } PresentationAttributeCacheKey key; Member<CSSPropertyValueSet> value;
diff --git a/third_party/blink/renderer/core/dom/processing_instruction.cc b/third_party/blink/renderer/core/dom/processing_instruction.cc index e349976..876b8a5 100644 --- a/third_party/blink/renderer/core/dom/processing_instruction.cc +++ b/third_party/blink/renderer/core/dom/processing_instruction.cc
@@ -289,7 +289,7 @@ style_engine_context_); } -void ProcessingInstruction::Trace(blink::Visitor* visitor) { +void ProcessingInstruction::Trace(Visitor* visitor) { visitor->Trace(sheet_); visitor->Trace(listener_for_xslt_); CharacterData::Trace(visitor);
diff --git a/third_party/blink/renderer/core/dom/processing_instruction.h b/third_party/blink/renderer/core/dom/processing_instruction.h index 8341102c..8975bc5a 100644 --- a/third_party/blink/renderer/core/dom/processing_instruction.h +++ b/third_party/blink/renderer/core/dom/processing_instruction.h
@@ -44,7 +44,7 @@ ProcessingInstruction(Document&, const String& target, const String& data); ~ProcessingInstruction() override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; const String& target() const { return target_; } const String& LocalHref() const { return local_href_; } @@ -64,7 +64,7 @@ // Detach event listener from its processing instruction. virtual void Detach() = 0; - void Trace(blink::Visitor* visitor) override {} + void Trace(Visitor* visitor) override {} }; void SetEventListenerForXSLT(DetachableEventListener* listener) {
diff --git a/third_party/blink/renderer/core/dom/pseudo_element_data.h b/third_party/blink/renderer/core/dom/pseudo_element_data.h index 76db5ac..2e3d64f2 100644 --- a/third_party/blink/renderer/core/dom/pseudo_element_data.h +++ b/third_party/blink/renderer/core/dom/pseudo_element_data.h
@@ -21,7 +21,7 @@ PseudoElement* GetPseudoElement(PseudoId) const; bool HasPseudoElements() const; void ClearPseudoElements(); - void Trace(blink::Visitor* visitor) { + void Trace(Visitor* visitor) { visitor->Trace(generated_before_); visitor->Trace(generated_after_); visitor->Trace(generated_first_letter_);
diff --git a/third_party/blink/renderer/core/dom/range.cc b/third_party/blink/renderer/core/dom/range.cc index 2a626e8..e2f86e3c 100644 --- a/third_party/blink/renderer/core/dom/range.cc +++ b/third_party/blink/renderer/core/dom/range.cc
@@ -1823,7 +1823,7 @@ selection.ClearDocumentCachedRange(); } -void Range::Trace(blink::Visitor* visitor) { +void Range::Trace(Visitor* visitor) { visitor->Trace(owner_document_); visitor->Trace(start_); visitor->Trace(end_);
diff --git a/third_party/blink/renderer/core/dom/range.h b/third_party/blink/renderer/core/dom/range.h index ec46883..e25d568 100644 --- a/third_party/blink/renderer/core/dom/range.h +++ b/third_party/blink/renderer/core/dom/range.h
@@ -176,7 +176,7 @@ static Node* CheckNodeWOffset(Node*, unsigned offset, ExceptionState&); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: void SetDocument(Document&);
diff --git a/third_party/blink/renderer/core/dom/range.idl b/third_party/blink/renderer/core/dom/range.idl index 83f4117..2095976 100644 --- a/third_party/blink/renderer/core/dom/range.idl +++ b/third_party/blink/renderer/core/dom/range.idl
@@ -72,5 +72,5 @@ [NewObject, RaisesException, CEReactions, CustomElementCallbacks] DocumentFragment createContextualFragment(HTMLString fragment); // Non-standard API - [RaisesException, DeprecateAs=RangeExpand] void expand([Default=Undefined] optional DOMString unit); + [RaisesException, DeprecateAs=RangeExpand] void expand([DefaultValue=Undefined] optional DOMString unit); };
diff --git a/third_party/blink/renderer/core/dom/range_boundary_point.h b/third_party/blink/renderer/core/dom/range_boundary_point.h index 1329ced..a4f4656f 100644 --- a/third_party/blink/renderer/core/dom/range_boundary_point.h +++ b/third_party/blink/renderer/core/dom/range_boundary_point.h
@@ -59,7 +59,7 @@ void InvalidateOffset(); void MarkValid() const; - void Trace(blink::Visitor* visitor) { + void Trace(Visitor* visitor) { visitor->Trace(container_node_); visitor->Trace(child_before_boundary_); }
diff --git a/third_party/blink/renderer/core/dom/scriptable_document_parser.cc b/third_party/blink/renderer/core/dom/scriptable_document_parser.cc index 8a99807a..be1db31 100644 --- a/third_party/blink/renderer/core/dom/scriptable_document_parser.cc +++ b/third_party/blink/renderer/core/dom/scriptable_document_parser.cc
@@ -42,7 +42,7 @@ return IsParsing() && !IsWaitingForScripts() && !IsExecutingScript(); } -void ScriptableDocumentParser::Trace(blink::Visitor* visitor) { +void ScriptableDocumentParser::Trace(Visitor* visitor) { visitor->Trace(inline_script_cache_handler_); DecodedDataDocumentParser::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/scriptable_document_parser.h b/third_party/blink/renderer/core/dom/scriptable_document_parser.h index f2d0177..8f13d6a6 100644 --- a/third_party/blink/renderer/core/dom/scriptable_document_parser.h +++ b/third_party/blink/renderer/core/dom/scriptable_document_parser.h
@@ -37,7 +37,7 @@ class CORE_EXPORT ScriptableDocumentParser : public DecodedDataDocumentParser { public: - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; // Only used by Document::open for deciding if its safe to act on a // JavaScript document.open() call right now, or it should be ignored.
diff --git a/third_party/blink/renderer/core/dom/scripted_animation_controller.cc b/third_party/blink/renderer/core/dom/scripted_animation_controller.cc index 0bcedc8..2ee4b8ee 100644 --- a/third_party/blink/renderer/core/dom/scripted_animation_controller.cc +++ b/third_party/blink/renderer/core/dom/scripted_animation_controller.cc
@@ -45,7 +45,7 @@ ScriptedAnimationController::ScriptedAnimationController(Document* document) : document_(document), callback_collection_(document), suspend_count_(0) {} -void ScriptedAnimationController::Trace(blink::Visitor* visitor) { +void ScriptedAnimationController::Trace(Visitor* visitor) { visitor->Trace(document_); visitor->Trace(callback_collection_); visitor->Trace(event_queue_);
diff --git a/third_party/blink/renderer/core/dom/scripted_animation_controller.h b/third_party/blink/renderer/core/dom/scripted_animation_controller.h index a1ca3e6..6b088872 100644 --- a/third_party/blink/renderer/core/dom/scripted_animation_controller.h +++ b/third_party/blink/renderer/core/dom/scripted_animation_controller.h
@@ -53,7 +53,7 @@ explicit ScriptedAnimationController(Document*); virtual ~ScriptedAnimationController() = default; - void Trace(blink::Visitor*); + void Trace(Visitor*); const char* NameInHeapSnapshot() const override { return "ScriptedAnimationController"; }
diff --git a/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc b/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc index ec42ac0..5a9aac8 100644 --- a/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc +++ b/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc
@@ -79,7 +79,7 @@ V8IdleRequestCallback* callback) : callback_(callback) {} -void ScriptedIdleTaskController::V8IdleTask::Trace(blink::Visitor* visitor) { +void ScriptedIdleTaskController::V8IdleTask::Trace(Visitor* visitor) { visitor->Trace(callback_); ScriptedIdleTaskController::IdleTask::Trace(visitor); } @@ -99,7 +99,7 @@ ScriptedIdleTaskController::~ScriptedIdleTaskController() = default; -void ScriptedIdleTaskController::Trace(blink::Visitor* visitor) { +void ScriptedIdleTaskController::Trace(Visitor* visitor) { visitor->Trace(idle_tasks_); PausableObject::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h b/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h index 39754b4b..8d347bdd 100644 --- a/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h +++ b/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h
@@ -37,7 +37,7 @@ explicit ScriptedIdleTaskController(ExecutionContext*); ~ScriptedIdleTaskController() override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; const char* NameInHeapSnapshot() const override { return "ScriptedIdleTaskController"; } @@ -49,7 +49,7 @@ class IdleTask : public GarbageCollectedFinalized<IdleTask>, public NameClient { public: - virtual void Trace(blink::Visitor* visitor) {} + virtual void Trace(Visitor* visitor) {} const char* NameInHeapSnapshot() const override { return "IdleTask"; } virtual ~IdleTask() = default; virtual void invoke(IdleDeadline*) = 0; @@ -67,7 +67,7 @@ ~V8IdleTask() override = default; void invoke(IdleDeadline*) override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: TraceWrapperMember<V8IdleRequestCallback> callback_;
diff --git a/third_party/blink/renderer/core/dom/scripted_task_queue.cc b/third_party/blink/renderer/core/dom/scripted_task_queue.cc index 6728f1ed..0cc70fb 100644 --- a/third_party/blink/renderer/core/dom/scripted_task_queue.cc +++ b/third_party/blink/renderer/core/dom/scripted_task_queue.cc
@@ -52,7 +52,7 @@ task_runner_ = GetExecutionContext()->GetTaskRunner(task_type); } -void ScriptedTaskQueue::Trace(blink::Visitor* visitor) { +void ScriptedTaskQueue::Trace(Visitor* visitor) { visitor->Trace(pending_tasks_); ScriptWrappable::Trace(visitor); ContextLifecycleObserver::Trace(visitor);
diff --git a/third_party/blink/renderer/core/dom/scripted_task_queue.h b/third_party/blink/renderer/core/dom/scripted_task_queue.h index 0aa1107..03d7f1a 100644 --- a/third_party/blink/renderer/core/dom/scripted_task_queue.h +++ b/third_party/blink/renderer/core/dom/scripted_task_queue.h
@@ -38,7 +38,7 @@ void CallbackFired(CallbackId id); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: // ContextLifecycleObserver interface.
diff --git a/third_party/blink/renderer/core/dom/scripted_task_queue_controller.cc b/third_party/blink/renderer/core/dom/scripted_task_queue_controller.cc index 86087fb..fa6c7ad 100644 --- a/third_party/blink/renderer/core/dom/scripted_task_queue_controller.cc +++ b/third_party/blink/renderer/core/dom/scripted_task_queue_controller.cc
@@ -30,7 +30,7 @@ ExecutionContext* context) : ContextLifecycleObserver(context) {} -void ScriptedTaskQueueController::Trace(blink::Visitor* visitor) { +void ScriptedTaskQueueController::Trace(Visitor* visitor) { visitor->Trace(task_queues_); Supplement<Document>::Trace(visitor); ScriptWrappable::Trace(visitor);
diff --git a/third_party/blink/renderer/core/dom/scripted_task_queue_controller.h b/third_party/blink/renderer/core/dom/scripted_task_queue_controller.h index 50bd28cd..9f5084c 100644 --- a/third_party/blink/renderer/core/dom/scripted_task_queue_controller.h +++ b/third_party/blink/renderer/core/dom/scripted_task_queue_controller.h
@@ -36,7 +36,7 @@ explicit ScriptedTaskQueueController(ExecutionContext*); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: HeapHashMap<String, TraceWrapperMember<ScriptedTaskQueue>> task_queues_;
diff --git a/third_party/blink/renderer/core/dom/shadow_root.cc b/third_party/blink/renderer/core/dom/shadow_root.cc index 7e88116..39d2eed15 100644 --- a/third_party/blink/renderer/core/dom/shadow_root.cc +++ b/third_party/blink/renderer/core/dom/shadow_root.cc
@@ -252,7 +252,7 @@ V0().ClearDistribution(); } -void ShadowRoot::Trace(blink::Visitor* visitor) { +void ShadowRoot::Trace(Visitor* visitor) { visitor->Trace(style_sheet_list_); visitor->Trace(slot_assignment_); visitor->Trace(shadow_root_v0_);
diff --git a/third_party/blink/renderer/core/dom/shadow_root.h b/third_party/blink/renderer/core/dom/shadow_root.h index 2f981ad6..632cc0e 100644 --- a/third_party/blink/renderer/core/dom/shadow_root.h +++ b/third_party/blink/renderer/core/dom/shadow_root.h
@@ -171,7 +171,7 @@ style_sheet_list_ = style_sheet_list; } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: ~ShadowRoot() override;
diff --git a/third_party/blink/renderer/core/dom/shadow_root_v0.h b/third_party/blink/renderer/core/dom/shadow_root_v0.h index d836af7..c95f0d8 100644 --- a/third_party/blink/renderer/core/dom/shadow_root_v0.h +++ b/third_party/blink/renderer/core/dom/shadow_root_v0.h
@@ -80,7 +80,7 @@ void SetNeedsSelectFeatureSet() { needs_select_feature_set_ = true; } SelectRuleFeatureSet& SelectFeatures() { return select_features_; } - void Trace(blink::Visitor* visitor) { + void Trace(Visitor* visitor) { visitor->Trace(shadow_root_); visitor->Trace(descendant_insertion_points_); visitor->Trace(node_to_insertion_points_);
diff --git a/third_party/blink/renderer/core/dom/slot_assignment.cc b/third_party/blink/renderer/core/dom/slot_assignment.cc index 9b4c9fae..50900696 100644 --- a/third_party/blink/renderer/core/dom/slot_assignment.cc +++ b/third_party/blink/renderer/core/dom/slot_assignment.cc
@@ -365,7 +365,7 @@ return nullptr; } -void SlotAssignment::Trace(blink::Visitor* visitor) { +void SlotAssignment::Trace(Visitor* visitor) { visitor->Trace(slots_); visitor->Trace(slot_map_); visitor->Trace(owner_);
diff --git a/third_party/blink/renderer/core/dom/slot_assignment.h b/third_party/blink/renderer/core/dom/slot_assignment.h index 36230f64..c2647ea 100644 --- a/third_party/blink/renderer/core/dom/slot_assignment.h +++ b/third_party/blink/renderer/core/dom/slot_assignment.h
@@ -55,7 +55,7 @@ HTMLSlotElement* FindSlotChange(HTMLSlotElement& slot, Node& child); - void Trace(blink::Visitor*); + void Trace(Visitor*); bool NeedsAssignmentRecalc() const { return needs_assignment_recalc_; } void SetNeedsAssignmentRecalc();
diff --git a/third_party/blink/renderer/core/dom/slot_assignment_engine.cc b/third_party/blink/renderer/core/dom/slot_assignment_engine.cc index c4bb49a..d3eb721 100644 --- a/third_party/blink/renderer/core/dom/slot_assignment_engine.cc +++ b/third_party/blink/renderer/core/dom/slot_assignment_engine.cc
@@ -51,7 +51,7 @@ DCHECK(shadow_roots_needing_recalc_.IsEmpty()); } -void SlotAssignmentEngine::Trace(blink::Visitor* visitor) { +void SlotAssignmentEngine::Trace(Visitor* visitor) { visitor->Trace(shadow_roots_needing_recalc_); }
diff --git a/third_party/blink/renderer/core/dom/slot_assignment_engine.h b/third_party/blink/renderer/core/dom/slot_assignment_engine.h index ae8a0f6..c1fb449 100644 --- a/third_party/blink/renderer/core/dom/slot_assignment_engine.h +++ b/third_party/blink/renderer/core/dom/slot_assignment_engine.h
@@ -32,7 +32,7 @@ void RecalcSlotAssignments(); - void Trace(blink::Visitor*); + void Trace(Visitor*); private: HeapHashSet<WeakMember<ShadowRoot>> shadow_roots_needing_recalc_;
diff --git a/third_party/blink/renderer/core/dom/static_node_list.h b/third_party/blink/renderer/core/dom/static_node_list.h index 805581b..115f52ab 100644 --- a/third_party/blink/renderer/core/dom/static_node_list.h +++ b/third_party/blink/renderer/core/dom/static_node_list.h
@@ -53,7 +53,7 @@ unsigned length() const override; NodeType* item(unsigned index) const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: HeapVector<TraceWrapperMember<NodeType>> nodes_;
diff --git a/third_party/blink/renderer/core/dom/static_range.cc b/third_party/blink/renderer/core/dom/static_range.cc index c5d3f6c..0015892 100644 --- a/third_party/blink/renderer/core/dom/static_range.cc +++ b/third_party/blink/renderer/core/dom/static_range.cc
@@ -58,7 +58,7 @@ return range; } -void StaticRange::Trace(blink::Visitor* visitor) { +void StaticRange::Trace(Visitor* visitor) { visitor->Trace(owner_document_); visitor->Trace(start_container_); visitor->Trace(end_container_);
diff --git a/third_party/blink/renderer/core/dom/static_range.h b/third_party/blink/renderer/core/dom/static_range.h index 8989453..09b83bdb3 100644 --- a/third_party/blink/renderer/core/dom/static_range.h +++ b/third_party/blink/renderer/core/dom/static_range.h
@@ -68,7 +68,7 @@ Range* toRange(ExceptionState& = ASSERT_NO_EXCEPTION) const; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Member<Document> owner_document_; // Required by |toRange()|.
diff --git a/third_party/blink/renderer/core/dom/template_content_document_fragment.h b/third_party/blink/renderer/core/dom/template_content_document_fragment.h index a68faf52..5a1c6462 100644 --- a/third_party/blink/renderer/core/dom/template_content_document_fragment.h +++ b/third_party/blink/renderer/core/dom/template_content_document_fragment.h
@@ -44,7 +44,7 @@ Element* Host() const { return host_; } - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { visitor->Trace(host_); DocumentFragment::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/text.cc b/third_party/blink/renderer/core/dom/text.cc index b4de6e4c..7ee5d04f 100644 --- a/third_party/blink/renderer/core/dom/text.cc +++ b/third_party/blink/renderer/core/dom/text.cc
@@ -472,7 +472,7 @@ return Create(factory, data); } -void Text::Trace(blink::Visitor* visitor) { +void Text::Trace(Visitor* visitor) { CharacterData::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/text.h b/third_party/blink/renderer/core/dom/text.h index e44317a..5a5b7ba 100644 --- a/third_party/blink/renderer/core/dom/text.h +++ b/third_party/blink/renderer/core/dom/text.h
@@ -72,7 +72,7 @@ bool CanContainRangeEndPoint() const final { return true; } NodeType getNodeType() const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: String nodeName() const override;
diff --git a/third_party/blink/renderer/core/dom/tree_ordered_list.cc b/third_party/blink/renderer/core/dom/tree_ordered_list.cc index 9d7157e..652c9c71 100644 --- a/third_party/blink/renderer/core/dom/tree_ordered_list.cc +++ b/third_party/blink/renderer/core/dom/tree_ordered_list.cc
@@ -63,7 +63,7 @@ nodes_.erase(const_cast<Node*>(node)); } -void TreeOrderedList::Trace(blink::Visitor* visitor) { +void TreeOrderedList::Trace(Visitor* visitor) { visitor->Trace(nodes_); }
diff --git a/third_party/blink/renderer/core/dom/tree_ordered_list.h b/third_party/blink/renderer/core/dom/tree_ordered_list.h index 19fb759..0cf1307 100644 --- a/third_party/blink/renderer/core/dom/tree_ordered_list.h +++ b/third_party/blink/renderer/core/dom/tree_ordered_list.h
@@ -63,7 +63,7 @@ const_reverse_iterator rbegin() const { return nodes_.rbegin(); } const_reverse_iterator rend() const { return nodes_.rend(); } - void Trace(blink::Visitor*); + void Trace(Visitor*); private: HeapListHashSet<Member<Node>, 32> nodes_;
diff --git a/third_party/blink/renderer/core/dom/tree_ordered_map.cc b/third_party/blink/renderer/core/dom/tree_ordered_map.cc index 4d70591..c81c81c1 100644 --- a/third_party/blink/renderer/core/dom/tree_ordered_map.cc +++ b/third_party/blink/renderer/core/dom/tree_ordered_map.cc
@@ -205,11 +205,11 @@ return entry->element; } -void TreeOrderedMap::Trace(blink::Visitor* visitor) { +void TreeOrderedMap::Trace(Visitor* visitor) { visitor->Trace(map_); } -void TreeOrderedMap::MapEntry::Trace(blink::Visitor* visitor) { +void TreeOrderedMap::MapEntry::Trace(Visitor* visitor) { visitor->Trace(element); visitor->Trace(ordered_list); }
diff --git a/third_party/blink/renderer/core/dom/tree_ordered_map.h b/third_party/blink/renderer/core/dom/tree_ordered_map.h index 5ca8d4f..5eecc622 100644 --- a/third_party/blink/renderer/core/dom/tree_ordered_map.h +++ b/third_party/blink/renderer/core/dom/tree_ordered_map.h
@@ -67,7 +67,7 @@ // TreeOrderedMap exactly. Element* GetCachedFirstElementWithoutAccessingNodeTree(const AtomicString&); - void Trace(blink::Visitor*); + void Trace(Visitor*); #if DCHECK_IS_ON() // While removing a ContainerNode, ID lookups won't be precise should the tree @@ -101,7 +101,7 @@ explicit MapEntry(Element& first_element) : element(first_element), count(1) {} - void Trace(blink::Visitor*); + void Trace(Visitor*); Member<Element> element; unsigned count;
diff --git a/third_party/blink/renderer/core/dom/tree_scope.cc b/third_party/blink/renderer/core/dom/tree_scope.cc index b59f6ad..1f5d8b6a 100644 --- a/third_party/blink/renderer/core/dom/tree_scope.cc +++ b/third_party/blink/renderer/core/dom/tree_scope.cc
@@ -619,7 +619,7 @@ } } -void TreeScope::Trace(blink::Visitor* visitor) { +void TreeScope::Trace(Visitor* visitor) { visitor->Trace(root_node_); visitor->Trace(document_); visitor->Trace(parent_tree_scope_);
diff --git a/third_party/blink/renderer/core/dom/tree_scope.h b/third_party/blink/renderer/core/dom/tree_scope.h index e467172c..d2adf8f 100644 --- a/third_party/blink/renderer/core/dom/tree_scope.h +++ b/third_party/blink/renderer/core/dom/tree_scope.h
@@ -131,7 +131,7 @@ Element* GetElementByAccessKey(const String& key) const; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; ScopedStyleResolver* GetScopedStyleResolver() const { return scoped_style_resolver_.Get();
diff --git a/third_party/blink/renderer/core/dom/tree_walker.cc b/third_party/blink/renderer/core/dom/tree_walker.cc index 19491db..605d031 100644 --- a/third_party/blink/renderer/core/dom/tree_walker.cc +++ b/third_party/blink/renderer/core/dom/tree_walker.cc
@@ -248,7 +248,7 @@ return nullptr; } -void TreeWalker::Trace(blink::Visitor* visitor) { +void TreeWalker::Trace(Visitor* visitor) { visitor->Trace(current_); ScriptWrappable::Trace(visitor); NodeIteratorBase::Trace(visitor);
diff --git a/third_party/blink/renderer/core/dom/tree_walker.h b/third_party/blink/renderer/core/dom/tree_walker.h index 43f338b..875c7ec 100644 --- a/third_party/blink/renderer/core/dom/tree_walker.h +++ b/third_party/blink/renderer/core/dom/tree_walker.h
@@ -57,7 +57,7 @@ Node* previousNode(ExceptionState&); Node* nextNode(ExceptionState&); - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: Node* SetCurrent(Node*);
diff --git a/third_party/blink/renderer/core/dom/user_action_element_set.cc b/third_party/blink/renderer/core/dom/user_action_element_set.cc index 409ab5a..eabc3e8 100644 --- a/third_party/blink/renderer/core/dom/user_action_element_set.cc +++ b/third_party/blink/renderer/core/dom/user_action_element_set.cc
@@ -102,7 +102,7 @@ elements_.insert(element, flags); } -void UserActionElementSet::Trace(blink::Visitor* visitor) { +void UserActionElementSet::Trace(Visitor* visitor) { visitor->Trace(elements_); }
diff --git a/third_party/blink/renderer/core/dom/user_action_element_set.h b/third_party/blink/renderer/core/dom/user_action_element_set.h index 9287449d..408825e 100644 --- a/third_party/blink/renderer/core/dom/user_action_element_set.h +++ b/third_party/blink/renderer/core/dom/user_action_element_set.h
@@ -73,7 +73,7 @@ void DidDetach(Element&); - void Trace(blink::Visitor*); + void Trace(Visitor*); private: enum ElementFlags {
diff --git a/third_party/blink/renderer/core/dom/v0_insertion_point.cc b/third_party/blink/renderer/core/dom/v0_insertion_point.cc index 930d432..d0779c2 100644 --- a/third_party/blink/renderer/core/dom/v0_insertion_point.cc +++ b/third_party/blink/renderer/core/dom/v0_insertion_point.cc
@@ -262,7 +262,7 @@ HTMLElement::RemovedFrom(insertion_point); } -void V0InsertionPoint::Trace(blink::Visitor* visitor) { +void V0InsertionPoint::Trace(Visitor* visitor) { visitor->Trace(distributed_nodes_); HTMLElement::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/dom/v0_insertion_point.h b/third_party/blink/renderer/core/dom/v0_insertion_point.h index e50c8f4..ad84b8ec 100644 --- a/third_party/blink/renderer/core/dom/v0_insertion_point.h +++ b/third_party/blink/renderer/core/dom/v0_insertion_point.h
@@ -75,7 +75,7 @@ return distributed_nodes_.PreviousTo(node); } - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; protected: V0InsertionPoint(const QualifiedName&, Document&);
diff --git a/third_party/blink/renderer/core/dom/visited_link_state.cc b/third_party/blink/renderer/core/dom/visited_link_state.cc index 9541ae5..211ab8a 100644 --- a/third_party/blink/renderer/core/dom/visited_link_state.cc +++ b/third_party/blink/renderer/core/dom/visited_link_state.cc
@@ -135,7 +135,7 @@ return EInsideLink::kInsideUnvisitedLink; } -void VisitedLinkState::Trace(blink::Visitor* visitor) { +void VisitedLinkState::Trace(Visitor* visitor) { visitor->Trace(document_); }
diff --git a/third_party/blink/renderer/core/dom/visited_link_state.h b/third_party/blink/renderer/core/dom/visited_link_state.h index 7b663e99..9df9e21 100644 --- a/third_party/blink/renderer/core/dom/visited_link_state.h +++ b/third_party/blink/renderer/core/dom/visited_link_state.h
@@ -57,7 +57,7 @@ return EInsideLink::kNotInsideLink; } - void Trace(blink::Visitor*); + void Trace(Visitor*); private: const Document& GetDocument() const { return *document_; }
diff --git a/third_party/blink/renderer/core/dom/weak_identifier_map.h b/third_party/blink/renderer/core/dom/weak_identifier_map.h index 4f70063..eed341b 100644 --- a/third_party/blink/renderer/core/dom/weak_identifier_map.h +++ b/third_party/blink/renderer/core/dom/weak_identifier_map.h
@@ -30,7 +30,7 @@ class WeakIdentifierMapBase<T, IdentifierType, true> : public GarbageCollected<WeakIdentifierMapBase<T, IdentifierType, true>> { public: - void Trace(blink::Visitor* visitor) { + void Trace(Visitor* visitor) { visitor->Trace(object_to_identifier_); visitor->Trace(identifier_to_object_); }
diff --git a/third_party/blink/renderer/core/editing/selection.idl b/third_party/blink/renderer/core/editing/selection.idl index fc128c05..d6d5cf0 100644 --- a/third_party/blink/renderer/core/editing/selection.idl +++ b/third_party/blink/renderer/core/editing/selection.idl
@@ -66,7 +66,7 @@ [MeasureAs=SelectionExtentOffset] readonly attribute unsigned long extentOffset; // https://github.com/w3c/selection-api/issues/37 - [MeasureAs=SelectionModify] void modify([Default=Undefined] optional DOMString alter, - [Default=Undefined] optional DOMString direction, - [Default=Undefined] optional DOMString granularity); + [MeasureAs=SelectionModify] void modify([DefaultValue=Undefined] optional DOMString alter, + [DefaultValue=Undefined] optional DOMString direction, + [DefaultValue=Undefined] optional DOMString granularity); };
diff --git a/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc b/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc index 4f1134d..ebae338 100644 --- a/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc +++ b/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc
@@ -59,12 +59,14 @@ void DidFinishCheckingText( const WebVector<WebTextCheckingResult>& results) override { - request_->DidSucceed(ToCoreResults(results)); + if (request_) + request_->DidSucceed(ToCoreResults(results)); delete this; } void DidCancelCheckingText() override { - request_->DidCancel(); + if (request_) + request_->DidCancel(); // TODO(dgozman): use std::unique_ptr. delete this; } @@ -72,7 +74,9 @@ private: virtual ~WebTextCheckingCompletionImpl() = default; - Persistent<SpellCheckRequest> request_; + // As |WebTextCheckingCompletionImpl| is mananaged outside Blink, it should + // only keep weak references to Blink objects to prevent memory leaks. + WeakPersistent<SpellCheckRequest> request_; }; } // namespace
diff --git a/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h b/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h index c25947e..419b1d02 100644 --- a/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h +++ b/third_party/blink/renderer/core/editing/spellcheck/spell_checker.h
@@ -97,6 +97,9 @@ // // Hence allow the leak detector to effectively stop the spell checker to // ensure leak reporting stability. + // + // TODO(xiaochengh): Now that there's no strong reference to SpellCheckRequest + // from outside Blink, this function may have become redundant. Investigate. void PrepareForLeakDetection(); void DidAttachDocument(Document*);
diff --git a/third_party/blink/renderer/core/events/composition_event.idl b/third_party/blink/renderer/core/events/composition_event.idl index 891ba59..fd8a179 100644 --- a/third_party/blink/renderer/core/events/composition_event.idl +++ b/third_party/blink/renderer/core/events/composition_event.idl
@@ -34,9 +34,9 @@ // https://w3c.github.io/uievents/#idl-interface-CompositionEvent-initializers // TODO(foolip): None of the initCompositionEvent() arguments should be // optional, and the spec has a locale argument after data. - [Measure] void initCompositionEvent([Default=Undefined] optional DOMString type, - [Default=Undefined] optional boolean bubbles, - [Default=Undefined] optional boolean cancelable, - [Default=Undefined] optional Window? view, - [Default=Undefined] optional DOMString data); + [Measure] void initCompositionEvent([DefaultValue=Undefined] optional DOMString type, + [DefaultValue=Undefined] optional boolean bubbles, + [DefaultValue=Undefined] optional boolean cancelable, + [DefaultValue=Undefined] optional Window? view, + [DefaultValue=Undefined] optional DOMString data); };
diff --git a/third_party/blink/renderer/core/events/message_event.idl b/third_party/blink/renderer/core/events/message_event.idl index 317eda1..250ed2c 100644 --- a/third_party/blink/renderer/core/events/message_event.idl +++ b/third_party/blink/renderer/core/events/message_event.idl
@@ -40,14 +40,14 @@ [CachedAttribute=isPortsDirty] readonly attribute FrozenArray<MessagePort> ports; [RuntimeEnabled=UserActivationAPI] readonly attribute UserActivation? userActivation; - // TODO(foolip): none of the arguments should have [Default=Undefined] (they + // TODO(foolip): none of the arguments should have [DefaultValue=Undefined] (they // have other default values in the spec) and |sourceArg|'s type is wrong. [Custom, MeasureAs=InitMessageEvent] void initMessageEvent(DOMString typeArg, - [Default=Undefined] optional boolean canBubbleArg, - [Default=Undefined] optional boolean cancelableArg, - [Default=Undefined] optional any dataArg, - [Default=Undefined] optional DOMString originArg, - [Default=Undefined] optional DOMString lastEventIdArg, - [Default=Undefined] optional EventTarget sourceArg, - [Default=Undefined] optional sequence<MessagePort> portsArg); + [DefaultValue=Undefined] optional boolean canBubbleArg, + [DefaultValue=Undefined] optional boolean cancelableArg, + [DefaultValue=Undefined] optional any dataArg, + [DefaultValue=Undefined] optional DOMString originArg, + [DefaultValue=Undefined] optional DOMString lastEventIdArg, + [DefaultValue=Undefined] optional EventTarget sourceArg, + [DefaultValue=Undefined] optional sequence<MessagePort> portsArg); };
diff --git a/third_party/blink/renderer/core/events/mouse_event.idl b/third_party/blink/renderer/core/events/mouse_event.idl index 8dc2e48..3135644 100644 --- a/third_party/blink/renderer/core/events/mouse_event.idl +++ b/third_party/blink/renderer/core/events/mouse_event.idl
@@ -39,21 +39,21 @@ // https://w3c.github.io/uievents/#idl-interface-MouseEvent-initializers // TODO(foolip): None of the initMouseEvent() arguments should be optional. - [CallWith=ScriptState, Measure] void initMouseEvent([Default=Undefined] optional DOMString type, - [Default=Undefined] optional boolean bubbles, - [Default=Undefined] optional boolean cancelable, - [Default=Undefined] optional Window? view, - [Default=Undefined] optional long detail, - [Default=Undefined] optional long screenX, - [Default=Undefined] optional long screenY, - [Default=Undefined] optional long clientX, - [Default=Undefined] optional long clientY, - [Default=Undefined] optional boolean ctrlKey, - [Default=Undefined] optional boolean altKey, - [Default=Undefined] optional boolean shiftKey, - [Default=Undefined] optional boolean metaKey, - [Default=Undefined] optional unsigned short button, - [Default=Undefined] optional EventTarget? relatedTarget); + [CallWith=ScriptState, Measure] void initMouseEvent([DefaultValue=Undefined] optional DOMString type, + [DefaultValue=Undefined] optional boolean bubbles, + [DefaultValue=Undefined] optional boolean cancelable, + [DefaultValue=Undefined] optional Window? view, + [DefaultValue=Undefined] optional long detail, + [DefaultValue=Undefined] optional long screenX, + [DefaultValue=Undefined] optional long screenY, + [DefaultValue=Undefined] optional long clientX, + [DefaultValue=Undefined] optional long clientY, + [DefaultValue=Undefined] optional boolean ctrlKey, + [DefaultValue=Undefined] optional boolean altKey, + [DefaultValue=Undefined] optional boolean shiftKey, + [DefaultValue=Undefined] optional boolean metaKey, + [DefaultValue=Undefined] optional unsigned short button, + [DefaultValue=Undefined] optional EventTarget? relatedTarget); readonly attribute double pageX; readonly attribute double pageY;
diff --git a/third_party/blink/renderer/core/events/mutation_event.idl b/third_party/blink/renderer/core/events/mutation_event.idl index c377ae5..5620495 100644 --- a/third_party/blink/renderer/core/events/mutation_event.idl +++ b/third_party/blink/renderer/core/events/mutation_event.idl
@@ -31,12 +31,12 @@ readonly attribute DOMString attrName; readonly attribute unsigned short attrChange; // TODO(foolip): None of the initMutationEvent() arguments should be optional. - [Measure] void initMutationEvent([Default=Undefined] optional DOMString type, - [Default=Undefined] optional boolean bubbles, - [Default=Undefined] optional boolean cancelable, - [Default=Undefined] optional Node? relatedNode, - [Default=Undefined] optional DOMString prevValue, - [Default=Undefined] optional DOMString newValue, - [Default=Undefined] optional DOMString attrName, - [Default=Undefined] optional unsigned short attrChange); + [Measure] void initMutationEvent([DefaultValue=Undefined] optional DOMString type, + [DefaultValue=Undefined] optional boolean bubbles, + [DefaultValue=Undefined] optional boolean cancelable, + [DefaultValue=Undefined] optional Node? relatedNode, + [DefaultValue=Undefined] optional DOMString prevValue, + [DefaultValue=Undefined] optional DOMString newValue, + [DefaultValue=Undefined] optional DOMString attrName, + [DefaultValue=Undefined] optional unsigned short attrChange); };
diff --git a/third_party/blink/renderer/core/events/text_event.idl b/third_party/blink/renderer/core/events/text_event.idl index 2ae52eb..37ea253 100644 --- a/third_party/blink/renderer/core/events/text_event.idl +++ b/third_party/blink/renderer/core/events/text_event.idl
@@ -35,10 +35,10 @@ [Measure] readonly attribute DOMString data; - [Measure] void initTextEvent([Default=Undefined] optional DOMString type, - [Default=Undefined] optional boolean bubbles, - [Default=Undefined] optional boolean cancelable, - [Default=Undefined] optional Window? view, - [Default=Undefined] optional DOMString data); + [Measure] void initTextEvent([DefaultValue=Undefined] optional DOMString type, + [DefaultValue=Undefined] optional boolean bubbles, + [DefaultValue=Undefined] optional boolean cancelable, + [DefaultValue=Undefined] optional Window? view, + [DefaultValue=Undefined] optional DOMString data); };
diff --git a/third_party/blink/renderer/core/events/ui_event.idl b/third_party/blink/renderer/core/events/ui_event.idl index 20e8fc9..ed34dba 100644 --- a/third_party/blink/renderer/core/events/ui_event.idl +++ b/third_party/blink/renderer/core/events/ui_event.idl
@@ -29,11 +29,11 @@ // https://w3c.github.io/uievents/#idl-interface-UIEvent-initializers // TODO(foolip): None of the initUIEvent() arguments should be optional. - [Measure] void initUIEvent([Default=Undefined] optional DOMString type, - [Default=Undefined] optional boolean bubbles, - [Default=Undefined] optional boolean cancelable, - [Default=Undefined] optional Window? view, - [Default=Undefined] optional long detail); + [Measure] void initUIEvent([DefaultValue=Undefined] optional DOMString type, + [DefaultValue=Undefined] optional boolean bubbles, + [DefaultValue=Undefined] optional boolean cancelable, + [DefaultValue=Undefined] optional Window? view, + [DefaultValue=Undefined] optional long detail); readonly attribute unsigned long which; };
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc index 3d1bec85..3270b3a8 100644 --- a/third_party/blink/renderer/core/exported/web_frame_test.cc +++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -9551,6 +9551,7 @@ void Navigate(const WebURLRequest& request, bool should_replace_current_entry, bool is_opener_navigation, + bool prevent_sandboxed_download, mojo::ScopedMessagePipeHandle) override { last_request_ = request; }
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.cc b/third_party/blink/renderer/core/exported/web_settings_impl.cc index 5c95a24..12d89ca6 100644 --- a/third_party/blink/renderer/core/exported/web_settings_impl.cc +++ b/third_party/blink/renderer/core/exported/web_settings_impl.cc
@@ -564,6 +564,10 @@ settings_->SetScrollAnimatorEnabled(enabled); } +void WebSettingsImpl::SetPrefersReducedMotion(bool enabled) { + settings_->SetPrefersReducedMotion(enabled); +} + void WebSettingsImpl::SetEnableTouchAdjustment(bool enabled) { settings_->SetTouchAdjustmentEnabled(enabled); }
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.h b/third_party/blink/renderer/core/exported/web_settings_impl.h index 20af3c579..ea7a9fe 100644 --- a/third_party/blink/renderer/core/exported/web_settings_impl.h +++ b/third_party/blink/renderer/core/exported/web_settings_impl.h
@@ -82,6 +82,7 @@ void SetDownloadableBinaryFontsEnabled(bool) override; void SetEditingBehavior(EditingBehavior) override; void SetEnableScrollAnimator(bool) override; + void SetPrefersReducedMotion(bool) override; void SetEnableTouchAdjustment(bool) override; void SetWebGL1Enabled(bool) override; void SetWebGL2Enabled(bool) override;
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc index 4ee525a..2455c372 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -135,6 +135,7 @@ #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/page/page_popup_client.h" #include "third_party/blink/renderer/core/page/pointer_lock_controller.h" +#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h" #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h" #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h" #include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h" @@ -1507,6 +1508,11 @@ if (!MainFrameImpl()) return; + if (LocalFrameView* view = MainFrameImpl()->GetFrameView()) { + if (FragmentAnchor* anchor = view->GetFragmentAnchor()) + anchor->PerformPreRafActions(); + } + DocumentLifecycle::AllowThrottlingScope throttling_scope( MainFrameImpl()->GetFrame()->GetDocument()->Lifecycle()); PageWidgetDelegate::Animate(*AsView().page, last_frame_time);
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc index a7ef9525..7c4e37f 100644 --- a/third_party/blink/renderer/core/exported/web_view_test.cc +++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -5220,14 +5220,21 @@ web_view->MainFrameWidget()->HandleInputEvent( WebCoalescedInputEvent(key_event3)); - histogram_tester.ExpectTotalCount("PageLoad.InteractiveTiming.InputDelay", 3); - histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputDelay", 50, 2); - histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputDelay", 70, 1); + histogram_tester.ExpectTotalCount("PageLoad.InteractiveTiming.InputDelay2", + 3); + histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputDelay2", + 50, 2); + histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputDelay2", + 70, 1); - histogram_tester.ExpectTotalCount("PageLoad.InteractiveTiming.InputTimestamp", 3); - histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputTimestamp", 70, 1); - histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputTimestamp", 120, 1); - histogram_tester.ExpectBucketCount("PageLoad.InteractiveTiming.InputTimestamp", 170, 1); + histogram_tester.ExpectTotalCount( + "PageLoad.InteractiveTiming.InputTimestamp2", 3); + histogram_tester.ExpectBucketCount( + "PageLoad.InteractiveTiming.InputTimestamp2", 70, 1); + histogram_tester.ExpectBucketCount( + "PageLoad.InteractiveTiming.InputTimestamp2", 120, 1); + histogram_tester.ExpectBucketCount( + "PageLoad.InteractiveTiming.InputTimestamp2", 170, 1); } // Tests that if the page was backgrounded while an input event was queued, @@ -5429,6 +5436,7 @@ ASSERT_NE(nullptr, document); WTF::ScopedMockClock clock; + clock.Advance(TimeDelta::FromMilliseconds(70)); InteractiveDetector* interactive_detector( InteractiveDetector::From(*document)); @@ -5446,7 +5454,7 @@ // can't report its delay. We don't consider a scroll to be meaningful input. EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero()); - // When we receive a pointer up, we report the delay of the pointer down. + // When we receive a pointer cancel, we should not report the pointer down. WebPointerEvent pointer_cancel( WebInputEvent::kPointerCancel, WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5); @@ -5461,6 +5469,130 @@ EXPECT_TRUE(interactive_detector->GetFirstInputTimestamp().is_null()); } +// Check that input delay isn't reported when there is pointer down, pointer +// cancel, and pointer up. +TEST_F(WebViewTest, PointerDownCancelUpInputDelay) { + WebViewImpl* web_view = web_view_helper_.Initialize(); + WebURL base_url = url_test_helpers::ToKURL("http://example.com/"); + frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(), + "<html><body></body onpointerdown=" + "></html>", + base_url); + + LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame(); + ASSERT_NE(nullptr, main_frame); + Document* document = main_frame->GetDocument(); + ASSERT_NE(nullptr, document); + + WTF::ScopedMockClock clock; + clock.Advance(TimeDelta::FromMilliseconds(70)); + + InteractiveDetector* interactive_detector( + InteractiveDetector::From(*document)); + ASSERT_NE(nullptr, interactive_detector); + + WebPointerEvent pointer_down( + WebInputEvent::kPointerDown, + WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5); + pointer_down.SetTimeStamp(CurrentTimeTicks()); + clock.Advance(TimeDelta::FromMilliseconds(50)); + web_view->MainFrameWidget()->HandleInputEvent( + WebCoalescedInputEvent(pointer_down)); + + // We don't know if this pointer event will result in a scroll or not, so we + // can't report its delay. We don't consider a scroll to be meaningful input. + EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero()); + + // When we receive a pointer cancel, we should not report the pointer down. + WebPointerEvent pointer_cancel( + WebInputEvent::kPointerCancel, + WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5); + clock.Advance(TimeDelta::FromMilliseconds(60)); + pointer_cancel.SetTimeStamp(CurrentTimeTicks()); + web_view->MainFrameWidget()->HandleInputEvent( + WebCoalescedInputEvent(pointer_cancel)); + + EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero()); + + // When we receive a pointer up, because we received a pointer cancel, no + // input delay should be recorded. + WebPointerEvent pointer_up( + WebInputEvent::kPointerUp, + WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5); + clock.Advance(TimeDelta::FromMilliseconds(60)); + pointer_up.SetTimeStamp(CurrentTimeTicks()); + web_view->MainFrameWidget()->HandleInputEvent( + WebCoalescedInputEvent(pointer_up)); + + EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero()); + EXPECT_TRUE(interactive_detector->GetFirstInputTimestamp().is_null()); + EXPECT_TRUE(interactive_detector->GetLongestInputDelay().is_zero()); + EXPECT_TRUE(interactive_detector->GetLongestInputTimestamp().is_null()); +} + +// Check that first input delay isn't reported when there is pointer down, +// pointer caused UA action, and pointer up. +TEST_F(WebViewTest, PointerDownCausedUaActionUpInputDelay) { + WebViewImpl* web_view = web_view_helper_.Initialize(); + WebURL base_url = url_test_helpers::ToKURL("http://example.com/"); + frame_test_helpers::LoadHTMLString(web_view->MainFrameImpl(), + "<html><body></body onpointerdown=" + "></html>", + base_url); + + LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame(); + ASSERT_NE(nullptr, main_frame); + Document* document = main_frame->GetDocument(); + ASSERT_NE(nullptr, document); + + WTF::ScopedMockClock clock; + clock.Advance(TimeDelta::FromMilliseconds(70)); + + InteractiveDetector* interactive_detector( + InteractiveDetector::From(*document)); + ASSERT_NE(nullptr, interactive_detector); + + WebPointerEvent pointer_down( + WebInputEvent::kPointerDown, + WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5); + pointer_down.SetTimeStamp(CurrentTimeTicks()); + clock.Advance(TimeDelta::FromMilliseconds(50)); + web_view->MainFrameWidget()->HandleInputEvent( + WebCoalescedInputEvent(pointer_down)); + + // We don't know if this pointer event will result in a scroll or not, so we + // can't report its delay. We don't consider a scroll to be meaningful input. + EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero()); + + // When we receive a pointer caused UA action, we should not report the + // pointer down. + WebPointerEvent pointer_cancel( + WebInputEvent::kPointerCausedUaAction, + WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5); + clock.Advance(TimeDelta::FromMilliseconds(60)); + pointer_cancel.SetTimeStamp(CurrentTimeTicks()); + web_view->MainFrameWidget()->HandleInputEvent( + WebCoalescedInputEvent(pointer_cancel)); + + EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero()); + EXPECT_TRUE(interactive_detector->GetFirstInputTimestamp().is_null()); + + // When we receive a pointer up, because we received a pointer caused UA + // action, no input delay should be recorded. + WebPointerEvent pointer_up( + WebInputEvent::kPointerUp, + WebPointerProperties(1, WebPointerProperties::PointerType::kTouch), 5, 5); + clock.Advance(TimeDelta::FromMilliseconds(60)); + pointer_up.SetTimeStamp(CurrentTimeTicks()); + web_view->MainFrameWidget()->HandleInputEvent( + WebCoalescedInputEvent(pointer_up)); + + EXPECT_TRUE(interactive_detector->GetFirstInputDelay().is_zero()); + EXPECT_TRUE(interactive_detector->GetFirstInputTimestamp().is_null()); + EXPECT_TRUE(interactive_detector->GetLongestInputDelay().is_zero()); + EXPECT_TRUE(interactive_detector->GetLongestInputTimestamp().is_null()); +} + // We need a way for JS to advance the mock clock. Hook into console.log, so // that logging advances the clock by |event_handling_delay| seconds. class MockClockAdvancingWebFrameClient
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc b/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc index 6e90a55..083afa2 100644 --- a/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc +++ b/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
@@ -67,15 +67,6 @@ ~FeaturePolicyParserTest() override = default; - /*void SetUp() override { - chrome_client_ = MakeGarbageCollected<ConsoleCapturingChromeClient>(); - Page::PageClients clients; - FillWithEmptyClients(clients); - clients.chrome_client = chrome_client_.Get(); - SetupPageWithClients(&clients); - Page::InsertOrdinaryPageForTesting(&GetPage()); - }*/ - scoped_refptr<const SecurityOrigin> origin_a_ = SecurityOrigin::CreateFromString(ORIGIN_A); scoped_refptr<const SecurityOrigin> origin_b_ =
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc index f30c87e..b3e2678 100644 --- a/third_party/blink/renderer/core/frame/deprecation.cc +++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -173,18 +173,6 @@ feature, MilestoneString(milestone), replacement, details); } -String DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe( - const char* function, - const char* allow_string, - Milestone milestone) { - return String::Format( - "%s usage in cross-origin iframes is deprecated and will be disabled in " - "%s. To continue to use this feature, it must be enabled by the " - "embedding document using Feature Policy, e.g. " - "<iframe allow=\"%s\" ...>. See https://goo.gl/EuHzyv for more details.", - function, MilestoneString(milestone), allow_string); -} - DeprecationInfo GetDeprecationInfo(WebFeature feature) { switch (feature) { // Quota @@ -479,39 +467,6 @@ ReplacedWillBeRemoved(":unresolved pseudo selector", ":not(:defined)", kM73, "4642138092470272")}; - case WebFeature:: - kEncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe: - return {"EncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe", - kM64, - DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe( - "requestMediaKeySystemAccess", "encrypted-media", kM64)}; - - case WebFeature::kGeolocationDisallowedByFeaturePolicyInCrossOriginIframe: - return {"GeolocationDisallowedByFeaturePolicyInCrossOriginIframe", kM64, - DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe( - "getCurrentPosition and watchPosition", "geolocation", kM64)}; - - case WebFeature:: - kGetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe: - return {"GetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe", - kM64, - DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe( - "getUserMedia (microphone)", "microphone", kM64)}; - - case WebFeature:: - kGetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe: - return {"GetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe", - kM64, - DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe( - "getUserMedia (camera)", "camera", kM64)}; - - case WebFeature:: - kRequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe: - return {"RequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe", - kM64, - DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe( - "requestMIDIAccess", "midi", kM64)}; - case WebFeature::kPresentationRequestStartInsecureOrigin: case WebFeature::kPresentationReceiverInsecureOrigin: return { @@ -748,58 +703,6 @@ CountDeprecationCrossOriginIframe(frame, feature); } -void Deprecation::CountDeprecationFeaturePolicy( - const Document& document, - mojom::FeaturePolicyFeature feature) { - LocalFrame* frame = document.GetFrame(); - if (!frame) - return; - - // If the feature is allowed, don't log a warning. - if (document.IsFeatureEnabled(feature)) - return; - - // If the feature is disabled, log a warning but only if the request is from a - // cross-origin iframe. Ideally we would check here if the feature is actually - // disabled due to the parent frame's policy (as opposed to the current frame - // disabling the feature on itself) but that can't happen right now anyway - // (until the general syntax is shipped) and this is also a good enough - // approximation for deprecation messages. - switch (feature) { - case mojom::FeaturePolicyFeature::kEncryptedMedia: - CountDeprecationCrossOriginIframe( - frame, - WebFeature:: - kEncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe); - break; - case mojom::FeaturePolicyFeature::kGeolocation: - CountDeprecationCrossOriginIframe( - frame, - WebFeature::kGeolocationDisallowedByFeaturePolicyInCrossOriginIframe); - break; - case mojom::FeaturePolicyFeature::kMicrophone: - CountDeprecationCrossOriginIframe( - frame, - WebFeature:: - kGetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe); - break; - case mojom::FeaturePolicyFeature::kCamera: - CountDeprecationCrossOriginIframe( - frame, - WebFeature:: - kGetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe); - break; - case mojom::FeaturePolicyFeature::kMidiFeature: - CountDeprecationCrossOriginIframe( - frame, - WebFeature:: - kRequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe); - break; - default: - NOTREACHED(); - } -} - void Deprecation::GenerateReport(const LocalFrame* frame, WebFeature feature) { DeprecationInfo info = GetDeprecationInfo(feature);
diff --git a/third_party/blink/renderer/core/frame/deprecation.h b/third_party/blink/renderer/core/frame/deprecation.h index 6cc1eff3..dbdc93be 100644 --- a/third_party/blink/renderer/core/frame/deprecation.h +++ b/third_party/blink/renderer/core/frame/deprecation.h
@@ -49,9 +49,6 @@ static void CountDeprecationCrossOriginIframe(const LocalFrame*, WebFeature); static void CountDeprecationCrossOriginIframe(const Document&, WebFeature); - static void CountDeprecationFeaturePolicy(const Document&, - mojom::FeaturePolicyFeature); - static String DeprecationMessage(WebFeature); // Note: this is only public for tests.
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index cf626de..065f06cd 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -747,195 +747,193 @@ DCHECK_EQ(frame_->View(), this); DCHECK(frame_->GetPage()); + ScriptForbiddenScope forbid_script; + + if (IsInPerformLayout() || ShouldThrottleRendering() || + !frame_->GetDocument()->IsActive()) + return; + + TRACE_EVENT0("blink,benchmark", "LocalFrameView::layout"); + + RUNTIME_CALL_TIMER_SCOPE(V8PerIsolateData::MainThreadIsolate(), + RuntimeCallStats::CounterId::kUpdateLayout); + + // The actual call to UpdateGeometries is in PerformPostLayoutTasks. + SetNeedsUpdateGeometries(); + + if (auto_size_info_) + auto_size_info_->AutoSizeIfNeeded(); + + has_pending_layout_ = false; + + Document* document = frame_->GetDocument(); + TRACE_EVENT_BEGIN1("devtools.timeline", "Layout", "beginData", + inspector_layout_event::BeginData(this)); + probe::UpdateLayout probe(document); + + PerformPreLayoutTasks(); + + VisualViewport& visual_viewport = frame_->GetPage()->GetVisualViewport(); + DoubleSize viewport_size(visual_viewport.VisibleWidthCSSPx(), + visual_viewport.VisibleHeightCSSPx()); + + // TODO(crbug.com/460956): The notion of a single root for layout is no + // longer applicable. Remove or update this code. + LayoutObject* root_for_this_layout = GetLayoutView(); + + FontCachePurgePreventer font_cache_purge_preventer; { - ScriptForbiddenScope forbid_script; + base::AutoReset<bool> change_scheduling_enabled(&layout_scheduling_enabled_, + false); + nested_layout_count_++; - if (IsInPerformLayout() || ShouldThrottleRendering() || - !frame_->GetDocument()->IsActive()) - return; + // If the layout view was marked as needing layout after we added items in + // the subtree roots we need to clear the roots and do the layout from the + // layoutView. + if (GetLayoutView()->NeedsLayout()) + ClearLayoutSubtreeRootsAndMarkContainingBlocks(); + GetLayoutView()->ClearHitTestCache(); - TRACE_EVENT0("blink,benchmark", "LocalFrameView::layout"); - - RUNTIME_CALL_TIMER_SCOPE(V8PerIsolateData::MainThreadIsolate(), - RuntimeCallStats::CounterId::kUpdateLayout); - - // The actual call to UpdateGeometries is in PerformPostLayoutTasks. - SetNeedsUpdateGeometries(); - - if (auto_size_info_) - auto_size_info_->AutoSizeIfNeeded(); - - has_pending_layout_ = false; - - Document* document = frame_->GetDocument(); - TRACE_EVENT_BEGIN1("devtools.timeline", "Layout", "beginData", - inspector_layout_event::BeginData(this)); - probe::UpdateLayout probe(document); - - PerformPreLayoutTasks(); - - VisualViewport& visual_viewport = frame_->GetPage()->GetVisualViewport(); - DoubleSize viewport_size(visual_viewport.VisibleWidthCSSPx(), - visual_viewport.VisibleHeightCSSPx()); + bool in_subtree_layout = IsSubtreeLayout(); // TODO(crbug.com/460956): The notion of a single root for layout is no // longer applicable. Remove or update this code. - LayoutObject* root_for_this_layout = GetLayoutView(); + if (in_subtree_layout) + root_for_this_layout = layout_subtree_root_list_.RandomRoot(); - FontCachePurgePreventer font_cache_purge_preventer; - { - base::AutoReset<bool> change_scheduling_enabled( - &layout_scheduling_enabled_, false); - nested_layout_count_++; + if (!root_for_this_layout) { + // FIXME: Do we need to set m_size here? + NOTREACHED(); + return; + } - // If the layout view was marked as needing layout after we added items in - // the subtree roots we need to clear the roots and do the layout from the - // layoutView. - if (GetLayoutView()->NeedsLayout()) - ClearLayoutSubtreeRootsAndMarkContainingBlocks(); - GetLayoutView()->ClearHitTestCache(); - - bool in_subtree_layout = IsSubtreeLayout(); - - // TODO(crbug.com/460956): The notion of a single root for layout is no - // longer applicable. Remove or update this code. - if (in_subtree_layout) - root_for_this_layout = layout_subtree_root_list_.RandomRoot(); - - if (!root_for_this_layout) { - // FIXME: Do we need to set m_size here? - NOTREACHED(); - return; - } - - if (!in_subtree_layout) { - ClearLayoutSubtreeRootsAndMarkContainingBlocks(); - Node* body = document->body(); - if (body && body->GetLayoutObject()) { - if (IsHTMLFrameSetElement(*body)) { + if (!in_subtree_layout) { + ClearLayoutSubtreeRootsAndMarkContainingBlocks(); + Node* body = document->body(); + if (body && body->GetLayoutObject()) { + if (IsHTMLFrameSetElement(*body)) { + body->GetLayoutObject()->SetChildNeedsLayout(); + } else if (IsHTMLBodyElement(*body)) { + if (!first_layout_ && size_.Height() != GetLayoutSize().Height() && + body->GetLayoutObject()->EnclosingBox()->StretchesToViewport()) body->GetLayoutObject()->SetChildNeedsLayout(); - } else if (IsHTMLBodyElement(*body)) { - if (!first_layout_ && size_.Height() != GetLayoutSize().Height() && - body->GetLayoutObject()->EnclosingBox()->StretchesToViewport()) - body->GetLayoutObject()->SetChildNeedsLayout(); - } - } - - if (first_layout_) { - first_layout_ = false; - last_viewport_size_ = GetLayoutSize(); - last_zoom_factor_ = GetLayoutView()->StyleRef().Zoom(); - - ScrollbarMode h_mode; - ScrollbarMode v_mode; - GetLayoutView()->CalculateScrollbarModes(h_mode, v_mode); - if (v_mode == kScrollbarAuto) { - GetLayoutView() - ->GetScrollableArea() - ->ForceVerticalScrollbarForFirstLayout(); - } - } - - LayoutSize old_size = size_; - - size_ = LayoutSize(GetLayoutSize()); - - if (old_size != size_ && !first_layout_) { - LayoutBox* root_layout_object = - document->documentElement() - ? document->documentElement()->GetLayoutBox() - : nullptr; - LayoutBox* body_layout_object = root_layout_object && document->body() - ? document->body()->GetLayoutBox() - : nullptr; - if (body_layout_object && body_layout_object->StretchesToViewport()) - body_layout_object->SetChildNeedsLayout(); - else if (root_layout_object && - root_layout_object->StretchesToViewport()) - root_layout_object->SetChildNeedsLayout(); } } - TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("blink.debug.layout.trees"), "LayoutTree", - this, TracedLayoutObject::Create(*GetLayoutView(), false)); + if (first_layout_) { + first_layout_ = false; + last_viewport_size_ = GetLayoutSize(); + last_zoom_factor_ = GetLayoutView()->StyleRef().Zoom(); - IntSize old_size(Size()); - - PerformLayout(in_subtree_layout); - - IntSize new_size(Size()); - if (old_size != new_size) { - SetNeedsLayout(); - MarkViewportConstrainedObjectsForLayout( - old_size.Width() != new_size.Width(), - old_size.Height() != new_size.Height()); + ScrollbarMode h_mode; + ScrollbarMode v_mode; + GetLayoutView()->CalculateScrollbarModes(h_mode, v_mode); + if (v_mode == kScrollbarAuto) { + GetLayoutView() + ->GetScrollableArea() + ->ForceVerticalScrollbarForFirstLayout(); + } } - if (NeedsLayout()) { - base::AutoReset<bool> suppress(&suppress_adjust_view_size_, true); - UpdateLayout(); + LayoutSize old_size = size_; + + size_ = LayoutSize(GetLayoutSize()); + + if (old_size != size_ && !first_layout_) { + LayoutBox* root_layout_object = + document->documentElement() + ? document->documentElement()->GetLayoutBox() + : nullptr; + LayoutBox* body_layout_object = root_layout_object && document->body() + ? document->body()->GetLayoutBox() + : nullptr; + if (body_layout_object && body_layout_object->StretchesToViewport()) + body_layout_object->SetChildNeedsLayout(); + else if (root_layout_object && + root_layout_object->StretchesToViewport()) + root_layout_object->SetChildNeedsLayout(); } - - DCHECK(layout_subtree_root_list_.IsEmpty()); - } // Reset m_layoutSchedulingEnabled to its previous value. - CheckDoesNotNeedLayout(); - - DocumentLifecycle::Scope lifecycle_scope(Lifecycle(), - DocumentLifecycle::kLayoutClean); - - frame_timing_requests_dirty_ = true; - - // FIXME: Could find the common ancestor layer of all dirty subtrees and - // mark from there. crbug.com/462719 - GetLayoutView()->EnclosingLayer()->UpdateLayerPositionsAfterLayout(); + } TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( TRACE_DISABLED_BY_DEFAULT("blink.debug.layout.trees"), "LayoutTree", - this, TracedLayoutObject::Create(*GetLayoutView(), true)); + this, TracedLayoutObject::Create(*GetLayoutView(), false)); - GetLayoutView()->Compositor()->DidLayout(); - layout_count_for_testing_++; + IntSize old_size(Size()); - if (AXObjectCache* cache = document->ExistingAXObjectCache()) { - const KURL& url = document->Url(); - if (url.IsValid() && !url.IsAboutBlankURL()) { - cache->HandleLayoutComplete(document); - cache->ProcessUpdatesAfterLayout(*document); - } + PerformLayout(in_subtree_layout); + + IntSize new_size(Size()); + if (old_size != new_size) { + SetNeedsLayout(); + MarkViewportConstrainedObjectsForLayout( + old_size.Width() != new_size.Width(), + old_size.Height() != new_size.Height()); } - UpdateDocumentAnnotatedRegions(); + + if (NeedsLayout()) { + base::AutoReset<bool> suppress(&suppress_adjust_view_size_, true); + UpdateLayout(); + } + + DCHECK(layout_subtree_root_list_.IsEmpty()); + } // Reset m_layoutSchedulingEnabled to its previous value. + CheckDoesNotNeedLayout(); + + DocumentLifecycle::Scope lifecycle_scope(Lifecycle(), + DocumentLifecycle::kLayoutClean); + + frame_timing_requests_dirty_ = true; + + // FIXME: Could find the common ancestor layer of all dirty subtrees and + // mark from there. crbug.com/462719 + GetLayoutView()->EnclosingLayer()->UpdateLayerPositionsAfterLayout(); + + TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("blink.debug.layout.trees"), "LayoutTree", this, + TracedLayoutObject::Create(*GetLayoutView(), true)); + + GetLayoutView()->Compositor()->DidLayout(); + layout_count_for_testing_++; + + if (AXObjectCache* cache = document->ExistingAXObjectCache()) { + const KURL& url = document->Url(); + if (url.IsValid() && !url.IsAboutBlankURL()) { + cache->HandleLayoutComplete(document); + cache->ProcessUpdatesAfterLayout(*document); + } + } + UpdateDocumentAnnotatedRegions(); + CheckDoesNotNeedLayout(); + + if (nested_layout_count_ == 1) { + PerformPostLayoutTasks(); CheckDoesNotNeedLayout(); + } - if (nested_layout_count_ == 1) { - PerformPostLayoutTasks(); - CheckDoesNotNeedLayout(); - } + // FIXME: The notion of a single root for layout is no longer applicable. + // Remove or update this code. crbug.com/460596 + TRACE_EVENT_END1("devtools.timeline", "Layout", "endData", + inspector_layout_event::EndData(root_for_this_layout)); + probe::didChangeViewport(frame_.Get()); - // FIXME: The notion of a single root for layout is no longer applicable. - // Remove or update this code. crbug.com/460596 - TRACE_EVENT_END1("devtools.timeline", "Layout", "endData", - inspector_layout_event::EndData(root_for_this_layout)); - probe::didChangeViewport(frame_.Get()); - - nested_layout_count_--; - if (nested_layout_count_) - return; + nested_layout_count_--; + if (nested_layout_count_) + return; #if DCHECK_IS_ON() - // Post-layout assert that nobody was re-marked as needing layout during - // layout. - GetLayoutView()->AssertSubtreeIsLaidOut(); + // Post-layout assert that nobody was re-marked as needing layout during + // layout. + GetLayoutView()->AssertSubtreeIsLaidOut(); #endif - if (frame_->IsMainFrame()) { - // Scrollbars changing state can cause a visual viewport size change. - DoubleSize new_viewport_size(visual_viewport.VisibleWidthCSSPx(), - visual_viewport.VisibleHeightCSSPx()); - if (new_viewport_size != viewport_size) - frame_->GetDocument()->EnqueueVisualViewportResizeEvent(); - } - } // ScriptForbiddenScope + if (frame_->IsMainFrame()) { + // Scrollbars changing state can cause a visual viewport size change. + DoubleSize new_viewport_size(visual_viewport.VisibleWidthCSSPx(), + visual_viewport.VisibleHeightCSSPx()); + if (new_viewport_size != viewport_size) + frame_->GetDocument()->EnqueueVisualViewportResizeEvent(); + } GetFrame().GetDocument()->LayoutUpdated(); CheckDoesNotNeedLayout(); @@ -1349,22 +1347,8 @@ return fast_path_allowed; } -void LocalFrameView::ProcessUrlFragment(const KURL& url, - FragmentAnchor::Behavior behavior) { - fragment_anchor_ = FragmentAnchor::TryCreate(url, behavior, *frame_); - - // If rendering is blocked, we'll necessarily have a layout to invoke the - // anchor. - if (fragment_anchor_ && frame_->GetDocument()->IsRenderingReady()) { - frame_->GetDocument()->UpdateStyleAndLayoutTree(); - - // If layout is needed, we will scroll in performPostLayoutTasks. Otherwise, - // scroll and focus immediately. - if (NeedsLayout()) - UpdateLayout(); - else - InvokeFragmentAnchor(); - } +void LocalFrameView::ProcessUrlFragment(const KURL& url, bool should_scroll) { + fragment_anchor_ = FragmentAnchor::TryCreate(url, should_scroll, *frame_); } void LocalFrameView::SetLayoutSize(const IntSize& size) {
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index c29b40b..1b41b51 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -35,7 +35,6 @@ #include "third_party/blink/renderer/core/frame/frame_view.h" #include "third_party/blink/renderer/core/frame/layout_subtree_root_list.h" #include "third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.h" -#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h" #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h" #include "third_party/blink/renderer/core/paint/layout_object_counter.h" #include "third_party/blink/renderer/platform/geometry/int_rect.h" @@ -65,6 +64,7 @@ class ElementVisibilityObserver; class FloatRect; class FloatSize; +class FragmentAnchor; class Frame; class FrameViewAutoSizeInfo; class JSONObject; @@ -392,9 +392,7 @@ // still performing all related side-effects like setting :target (used for // e.g. in history restoration to override the scroll offset). The scroll // offset is maintained during the frame loading process. - void ProcessUrlFragment( - const KURL&, - FragmentAnchor::Behavior = FragmentAnchor::kBehaviorScroll); + void ProcessUrlFragment(const KURL&, bool should_scroll = true); FragmentAnchor* GetFragmentAnchor() { return fragment_anchor_; } void InvokeFragmentAnchor();
diff --git a/third_party/blink/renderer/core/frame/local_frame_view_test.cc b/third_party/blink/renderer/core/frame/local_frame_view_test.cc index 731bafc..028a3b7 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view_test.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view_test.cc
@@ -282,7 +282,7 @@ <link rel="stylesheet" type="text/css" href="sheet.css"> <a id="anchorlink" href="#bottom">Link to bottom of the page</a> <div style="height: 1000px;"></div> - <input id="bottom">Bottom of the page</a> + <input id="bottom">Bottom of the page</input> )HTML"); ScrollableArea* viewport = GetDocument().View()->LayoutViewport(); @@ -320,6 +320,7 @@ // fragment should be activated at that point. css_resource.Complete(""); RunPendingTasks(); + Compositor().BeginFrame(); ASSERT_TRUE(GetDocument().IsLoadCompleted()); EXPECT_EQ(GetDocument().getElementById("bottom"), GetDocument().ActiveElement())
diff --git a/third_party/blink/renderer/core/frame/location.cc b/third_party/blink/renderer/core/frame/location.cc index 6890c71..24cb53f 100644 --- a/third_party/blink/renderer/core/frame/location.cc +++ b/third_party/blink/renderer/core/frame/location.cc
@@ -118,19 +118,21 @@ return DOMURLUtilsReadOnly::hash(Url()); } -void Location::setHref(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const USVStringOrTrustedURL& stringOrUrl, +void Location::setHref(v8::Isolate* isolate, + const USVStringOrTrustedURL& string_or_url, ExceptionState& exception_state) { - String url = GetStringFromTrustedURL(stringOrUrl, current_window->document(), - exception_state); - if (!exception_state.HadException()) { - SetLocation(url, current_window, entered_window, &exception_state); - } + LocalDOMWindow* incumbent_window = IncumbentDOMWindow(isolate); + LocalDOMWindow* entered_window = EnteredDOMWindow(isolate); + + const String& url = GetStringFromTrustedURL( + string_or_url, incumbent_window->document(), exception_state); + if (exception_state.HadException()) + return; + + SetLocation(url, incumbent_window, entered_window, &exception_state); } -void Location::setProtocol(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, +void Location::setProtocol(v8::Isolate* isolate, const String& protocol, ExceptionState& exception_state) { KURL url = GetDocument()->Url(); @@ -140,62 +142,57 @@ "'" + protocol + "' is an invalid protocol."); return; } - SetLocation(url.GetString(), current_window, entered_window, - &exception_state); + + SetLocation(url.GetString(), IncumbentDOMWindow(isolate), + EnteredDOMWindow(isolate), &exception_state); } -void Location::setHost(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, +void Location::setHost(v8::Isolate* isolate, const String& host, ExceptionState& exception_state) { KURL url = GetDocument()->Url(); url.SetHostAndPort(host); - SetLocation(url.GetString(), current_window, entered_window, - &exception_state); + SetLocation(url.GetString(), IncumbentDOMWindow(isolate), + EnteredDOMWindow(isolate), &exception_state); } -void Location::setHostname(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, +void Location::setHostname(v8::Isolate* isolate, const String& hostname, ExceptionState& exception_state) { KURL url = GetDocument()->Url(); url.SetHost(hostname); - SetLocation(url.GetString(), current_window, entered_window, - &exception_state); + SetLocation(url.GetString(), IncumbentDOMWindow(isolate), + EnteredDOMWindow(isolate), &exception_state); } -void Location::setPort(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const String& port_string, +void Location::setPort(v8::Isolate* isolate, + const String& port, ExceptionState& exception_state) { KURL url = GetDocument()->Url(); - url.SetPort(port_string); - SetLocation(url.GetString(), current_window, entered_window, - &exception_state); + url.SetPort(port); + SetLocation(url.GetString(), IncumbentDOMWindow(isolate), + EnteredDOMWindow(isolate), &exception_state); } -void Location::setPathname(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, +void Location::setPathname(v8::Isolate* isolate, const String& pathname, ExceptionState& exception_state) { KURL url = GetDocument()->Url(); url.SetPath(pathname); - SetLocation(url.GetString(), current_window, entered_window, - &exception_state); + SetLocation(url.GetString(), IncumbentDOMWindow(isolate), + EnteredDOMWindow(isolate), &exception_state); } -void Location::setSearch(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, +void Location::setSearch(v8::Isolate* isolate, const String& search, ExceptionState& exception_state) { KURL url = GetDocument()->Url(); url.SetQuery(search); - SetLocation(url.GetString(), current_window, entered_window, - &exception_state); + SetLocation(url.GetString(), IncumbentDOMWindow(isolate), + EnteredDOMWindow(isolate), &exception_state); } -void Location::setHash(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, +void Location::setHash(v8::Isolate* isolate, const String& hash, ExceptionState& exception_state) { KURL url = GetDocument()->Url(); @@ -209,42 +206,40 @@ // cases where fragment identifiers are ignored or invalid. if (EqualIgnoringNullity(old_fragment_identifier, url.FragmentIdentifier())) return; - SetLocation(url.GetString(), current_window, entered_window, - &exception_state); + SetLocation(url.GetString(), IncumbentDOMWindow(isolate), + EnteredDOMWindow(isolate), &exception_state); } -void Location::assign(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const USVStringOrTrustedURL& stringOrUrl, +void Location::assign(v8::Isolate* isolate, + const USVStringOrTrustedURL& string_or_url, ExceptionState& exception_state) { - // TODO(yukishiino): Remove this check once we remove [CrossOrigin] from - // the |assign| DOM operation's definition in Location.idl. See the comment - // in Location.idl for details. - if (!BindingSecurity::ShouldAllowAccessTo(current_window, this, - exception_state)) { + LocalDOMWindow* incumbent_window = IncumbentDOMWindow(isolate); + LocalDOMWindow* entered_window = EnteredDOMWindow(isolate); + + const String& url = GetStringFromTrustedURL( + string_or_url, incumbent_window->document(), exception_state); + if (exception_state.HadException()) return; - } - String url = GetStringFromTrustedURL(stringOrUrl, current_window->document(), - exception_state); - if (!exception_state.HadException()) { - SetLocation(url, current_window, entered_window, &exception_state); - } + SetLocation(url, incumbent_window, entered_window, &exception_state); } -void Location::replace(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const USVStringOrTrustedURL& stringOrUrl, +void Location::replace(v8::Isolate* isolate, + const USVStringOrTrustedURL& string_or_url, ExceptionState& exception_state) { - String url = GetStringFromTrustedURL(stringOrUrl, current_window->document(), - exception_state); - if (!exception_state.HadException()) { - SetLocation(url, current_window, entered_window, &exception_state, - SetLocationPolicy::kReplaceThisFrame); - } + LocalDOMWindow* incumbent_window = IncumbentDOMWindow(isolate); + LocalDOMWindow* entered_window = EnteredDOMWindow(isolate); + + const String& url = GetStringFromTrustedURL( + string_or_url, incumbent_window->document(), exception_state); + if (exception_state.HadException()) + return; + + SetLocation(url, incumbent_window, entered_window, &exception_state, + SetLocationPolicy::kReplaceThisFrame); } -void Location::reload(LocalDOMWindow* current_window) { +void Location::reload() { if (!IsAttached()) return; if (GetDocument()->Url().ProtocolIsJavaScript())
diff --git a/third_party/blink/renderer/core/frame/location.h b/third_party/blink/renderer/core/frame/location.h index 18853be..67c5578 100644 --- a/third_party/blink/renderer/core/frame/location.h +++ b/third_party/blink/renderer/core/frame/location.h
@@ -61,56 +61,26 @@ DOMWindow* DomWindow() const { return dom_window_.Get(); } - void setHref(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const USVStringOrTrustedURL&, - ExceptionState&); + void setHref(v8::Isolate*, const USVStringOrTrustedURL&, ExceptionState&); void href(USVStringOrTrustedURL&) const; - void assign(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const USVStringOrTrustedURL&, - ExceptionState&); - void replace(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const USVStringOrTrustedURL&, - ExceptionState&); - void reload(LocalDOMWindow* current_window); + void assign(v8::Isolate*, const USVStringOrTrustedURL&, ExceptionState&); + void replace(v8::Isolate*, const USVStringOrTrustedURL&, ExceptionState&); + void reload(); - void setProtocol(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const String&, - ExceptionState&); + void setProtocol(v8::Isolate*, const String&, ExceptionState&); String protocol() const; - void setHost(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const String&, - ExceptionState&); + void setHost(v8::Isolate*, const String&, ExceptionState&); String host() const; - void setHostname(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const String&, - ExceptionState&); + void setHostname(v8::Isolate*, const String&, ExceptionState&); String hostname() const; - void setPort(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const String&, - ExceptionState&); + void setPort(v8::Isolate*, const String&, ExceptionState&); String port() const; - void setPathname(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const String&, - ExceptionState&); + void setPathname(v8::Isolate*, const String&, ExceptionState&); String pathname() const; - void setSearch(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const String&, - ExceptionState&); + void setSearch(v8::Isolate*, const String&, ExceptionState&); String search() const; - void setHash(LocalDOMWindow* current_window, - LocalDOMWindow* entered_window, - const String&, - ExceptionState&); + void setHash(v8::Isolate*, const String&, ExceptionState&); String hash() const; String origin() const;
diff --git a/third_party/blink/renderer/core/frame/location.idl b/third_party/blink/renderer/core/frame/location.idl index 59d42ced..ba5f568 100644 --- a/third_party/blink/renderer/core/frame/location.idl +++ b/third_party/blink/renderer/core/frame/location.idl
@@ -26,22 +26,13 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// https://html.spec.whatwg.org/multipage/browsers.html#location +// https://html.spec.whatwg.org/C/#the-location-interface [ CheckSecurity=Receiver, Exposed=Window ] interface Location { - // |assign| is *NOT* cross-origin accessible in the spec, but it needs - // the Incumbent realm when navigating the page. See the below link. - // https://html.spec.whatwg.org/multipage/browsers.html#location-object-navigate - // Unfortunately, Blink does not support the Incumbent realm so far, and - // we need a hack of assignOriginSafeMethodGetter to simulate the Incumbent - // realm. Thus, we have [CrossOrigin] here just for the hack although - // |assign| itself is not cross-origin accessible. - // TODO(yukishiino): Remove [CrossOrigin] once we support the Incumbent - // realm correctly. - [CallWith=(CurrentWindow,EnteredWindow), CrossOrigin, RaisesException, Unforgeable] void assign(URLString url); + [CallWith=Isolate, RaisesException, Unforgeable] void assign(URLString url); // |replace|, and *writing* |href| do not require a security check, as they // *change* the page, and thus these do not change any property of an @@ -49,24 +40,24 @@ // However, *reading* |href|, or accessing any component, is a security // problem, since that allows tracking navigation. // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginproperties-(-o-) - [CallWith=(CurrentWindow,EnteredWindow), CrossOrigin, RaisesException, Unforgeable] void replace(URLString url); - [CallWith=CurrentWindow, Unforgeable] void reload(); + [CallWith=Isolate, CrossOrigin, RaisesException, Unforgeable] void replace(URLString url); + [Unforgeable] void reload(); // TODO(foolip): |ancestorOrigins| should have [Unforgeable, SameObject]. [Unforgeable] readonly attribute DOMStringList ancestorOrigins; - [Affects=Nothing, SetterCallWith=(CurrentWindow,EnteredWindow), CrossOrigin=Setter, RaisesException=Setter, Unforgeable] attribute URLString href; + [Affects=Nothing, SetterCallWith=Isolate, CrossOrigin=Setter, RaisesException=Setter, Unforgeable] attribute URLString href; // TODO(yukishiino): Use [Unforgeable] stringifier instead of toString. [Unforgeable] DOMString toString(); [MeasureAs=LocationOrigin, Unforgeable] readonly attribute USVString origin; - [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString protocol; - [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString host; - [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString hostname; - [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString port; - [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString pathname; - [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString search; - [SetterCallWith=(CurrentWindow,EnteredWindow), RaisesException=Setter, Unforgeable] attribute USVString hash; + [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString protocol; + [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString host; + [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString hostname; + [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString port; + [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString pathname; + [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString search; + [SetterCallWith=Isolate, RaisesException=Setter, Unforgeable] attribute USVString hash; // TODO(foolip): Location does not have a valueOf() override in the spec. // See the comment in Location.h for the purpose of this.
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc index a6ac0dd..127d6fa 100644 --- a/third_party/blink/renderer/core/frame/remote_frame.cc +++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -94,9 +94,16 @@ Document* document = frame_request.OriginDocument(); bool is_opener_navigation = document && document->GetFrame() && document->GetFrame()->Client()->Opener() == this; + + bool prevent_sandboxed_download = + GetSecurityContext() && + GetSecurityContext()->IsSandboxed(kSandboxDownloads) && + RuntimeEnabledFeatures::BlockingDownloadsInSandboxEnabled(); + Client()->Navigate(frame_request.GetResourceRequest(), frame_load_type == WebFrameLoadType::kReplaceCurrentItem, - is_opener_navigation, frame_request.GetBlobURLToken()); + is_opener_navigation, prevent_sandboxed_download, + frame_request.GetBlobURLToken()); } void RemoteFrame::DetachImpl(FrameDetachType type) {
diff --git a/third_party/blink/renderer/core/frame/remote_frame_client.h b/third_party/blink/renderer/core/frame/remote_frame_client.h index f22a8176..b9c8598 100644 --- a/third_party/blink/renderer/core/frame/remote_frame_client.h +++ b/third_party/blink/renderer/core/frame/remote_frame_client.h
@@ -31,6 +31,7 @@ virtual void Navigate(const ResourceRequest&, bool should_replace_current_entry, bool is_opener_navigation, + bool prevent_sandboxed_download, mojom::blink::BlobURLTokenPtr) = 0; unsigned BackForwardLength() override = 0;
diff --git a/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc b/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc index fc52f11..ffb4e27b 100644 --- a/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc +++ b/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
@@ -112,11 +112,13 @@ const ResourceRequest& request, bool should_replace_current_entry, bool is_opener_navigation, + bool prevent_sandboxed_download, mojom::blink::BlobURLTokenPtr blob_url_token) { if (web_frame_->Client()) { web_frame_->Client()->Navigate( WrappedResourceRequest(request), should_replace_current_entry, - is_opener_navigation, blob_url_token.PassInterface().PassHandle()); + is_opener_navigation, prevent_sandboxed_download, + blob_url_token.PassInterface().PassHandle()); } }
diff --git a/third_party/blink/renderer/core/frame/remote_frame_client_impl.h b/third_party/blink/renderer/core/frame/remote_frame_client_impl.h index aa33cc9..06878012 100644 --- a/third_party/blink/renderer/core/frame/remote_frame_client_impl.h +++ b/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
@@ -38,6 +38,7 @@ void Navigate(const ResourceRequest&, bool should_replace_current_entry, bool is_opener_navigation, + bool prevent_sandboxed_download, mojom::blink::BlobURLTokenPtr) override; unsigned BackForwardLength() override; void CheckCompleted() override;
diff --git a/third_party/blink/renderer/core/frame/window.idl b/third_party/blink/renderer/core/frame/window.idl index eff2eaa..66b2317a 100644 --- a/third_party/blink/renderer/core/frame/window.idl +++ b/third_party/blink/renderer/core/frame/window.idl
@@ -181,13 +181,13 @@ // Non-standard APIs [MeasureAs=WindowClientInformation, Replaceable] readonly attribute Navigator clientInformation; [Replaceable, MeasureAs=WindowEvent, Custom=Getter, NotEnumerable] readonly attribute Event event; - [MeasureAs=WindowFind] boolean find([Default=Undefined] optional DOMString string, - [Default=Undefined] optional boolean caseSensitive, - [Default=Undefined] optional boolean backwards, - [Default=Undefined] optional boolean wrap, - [Default=Undefined] optional boolean wholeWord, - [Default=Undefined] optional boolean searchInFrames, - [Default=Undefined] optional boolean showDialog); + [MeasureAs=WindowFind] boolean find([DefaultValue=Undefined] optional DOMString string, + [DefaultValue=Undefined] optional boolean caseSensitive, + [DefaultValue=Undefined] optional boolean backwards, + [DefaultValue=Undefined] optional boolean wrap, + [DefaultValue=Undefined] optional boolean wholeWord, + [DefaultValue=Undefined] optional boolean searchInFrames, + [DefaultValue=Undefined] optional boolean showDialog); [MeasureAs=WindowOffscreenBuffering, Replaceable, NotEnumerable] readonly attribute boolean offscreenBuffering; [HighEntropy, MeasureAs=WindowScreenLeft, Replaceable] readonly attribute long screenLeft; [HighEntropy, MeasureAs=WindowScreenTop, Replaceable] readonly attribute long screenTop;
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics.cc b/third_party/blink/renderer/core/html/anchor_element_metrics.cc index 137e2ae31..4a1cc024b 100644 --- a/third_party/blink/renderer/core/html/anchor_element_metrics.cc +++ b/third_party/blink/renderer/core/html/anchor_element_metrics.cc
@@ -212,7 +212,7 @@ base::Optional<AnchorElementMetrics> AnchorElementMetrics::MaybeReportClickedMetricsOnClick( const HTMLAnchorElement* anchor_element) { - if (!base::FeatureList::IsEnabled(features::kRecordAnchorMetricsClicked) || + if (!base::FeatureList::IsEnabled(features::kNavigationPredictor) || !anchor_element->Href().ProtocolIsInHTTPFamily() || !GetRootDocument(*anchor_element)->Url().ProtocolIsInHTTPFamily() || !anchor_element->GetDocument().BaseURL().ProtocolIsInHTTPFamily()) { @@ -236,7 +236,7 @@ void AnchorElementMetrics::MaybeReportViewportMetricsOnLoad( Document& document) { DCHECK(document.GetFrame()); - if (!base::FeatureList::IsEnabled(features::kRecordAnchorMetricsVisible) || + if (!base::FeatureList::IsEnabled(features::kNavigationPredictor) || document.ParentDocument() || !document.View() || !document.Url().ProtocolIsInHTTPFamily() || !document.BaseURL().ProtocolIsInHTTPFamily()) {
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc b/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc index bfda5d5..2bf83494 100644 --- a/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc +++ b/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc
@@ -51,8 +51,7 @@ bool AnchorElementMetricsSender::HasAnchorElementMetricsSender( Document& document) { bool is_feature_enabled = - base::FeatureList::IsEnabled(features::kRecordAnchorMetricsClicked) || - base::FeatureList::IsEnabled(features::kRecordAnchorMetricsVisible); + base::FeatureList::IsEnabled(features::kNavigationPredictor); const KURL& url = document.BaseURL(); return is_feature_enabled && !document.ParentDocument() && url.IsValid() && url.ProtocolIsInHTTPFamily();
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc b/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc index 8c38c5c..ccd84087 100644 --- a/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc +++ b/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc
@@ -21,7 +21,7 @@ void SetUp() override { SimTest::SetUp(); - feature_list_.InitAndEnableFeature(features::kRecordAnchorMetricsClicked); + feature_list_.InitAndEnableFeature(features::kNavigationPredictor); } base::test::ScopedFeatureList feature_list_;
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc b/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc index 74aa566..f7cab0f 100644 --- a/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc +++ b/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc
@@ -47,7 +47,7 @@ SimTest::SetUp(); WebView().MainFrameWidget()->Resize( WebSize(kViewportWidth, kViewportHeight)); - feature_list_.InitAndEnableFeature(features::kRecordAnchorMetricsClicked); + feature_list_.InitAndEnableFeature(features::kNavigationPredictor); } base::test::ScopedFeatureList feature_list_; @@ -85,20 +85,18 @@ HTMLAnchorElement* anchor_element = ToHTMLAnchorElement(GetDocument().getElementById("anchor")); - // With feature kRecordAnchorMetricsClicked disabled, we should not see any + // With feature kNavigationPredictor disabled, we should not see any // count in histograms. base::test::ScopedFeatureList disabled_feature_list; - disabled_feature_list.InitAndDisableFeature( - features::kRecordAnchorMetricsClicked); + disabled_feature_list.InitAndDisableFeature(features::kNavigationPredictor); AnchorElementMetrics::MaybeReportClickedMetricsOnClick(anchor_element); histogram_tester.ExpectTotalCount("AnchorElementMetrics.Clicked.RatioArea", 0); - // If we enable feature kRecordAnchorMetricsClicked, we should see count is 1 + // If we enable feature kNavigationPredictor, we should see count is 1 // in histograms. base::test::ScopedFeatureList enabled_feature_list; - enabled_feature_list.InitAndEnableFeature( - features::kRecordAnchorMetricsClicked); + enabled_feature_list.InitAndEnableFeature(features::kNavigationPredictor); AnchorElementMetrics::MaybeReportClickedMetricsOnClick(anchor_element); histogram_tester.ExpectTotalCount("AnchorElementMetrics.Clicked.RatioArea", 1);
diff --git a/third_party/blink/renderer/core/html/forms/form_controller.h b/third_party/blink/renderer/core/html/forms/form_controller.h index b02828e9..b3a29fe 100644 --- a/third_party/blink/renderer/core/html/forms/form_controller.h +++ b/third_party/blink/renderer/core/html/forms/form_controller.h
@@ -24,6 +24,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_FORM_CONTROLLER_H_ #include <memory> +#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/forward.h" @@ -76,7 +77,8 @@ using SavedFormStateMap = HashMap<AtomicString, std::unique_ptr<SavedFormState>>; -class DocumentState final : public GarbageCollectedFinalized<DocumentState> { +class CORE_EXPORT DocumentState final + : public GarbageCollectedFinalized<DocumentState> { public: DocumentState(Document& document); void Trace(Visitor*); @@ -92,7 +94,8 @@ bool form_controls_dirty_ = true; }; -class FormController final : public GarbageCollectedFinalized<FormController> { +class CORE_EXPORT FormController final + : public GarbageCollectedFinalized<FormController> { public: FormController(Document& document); ~FormController();
diff --git a/third_party/blink/renderer/core/html/forms/form_controller_test.cc b/third_party/blink/renderer/core/html/forms/form_controller_test.cc new file mode 100644 index 0000000..bfd571e --- /dev/null +++ b/third_party/blink/renderer/core/html/forms/form_controller_test.cc
@@ -0,0 +1,31 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/html/forms/form_controller.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/dom/element.h" +#include "third_party/blink/renderer/core/html_names.h" + +namespace blink { + +TEST(DocumentStateTest, ToStateVectorConnected) { + Document& doc = *Document::CreateForTest(); + Element* html = doc.CreateRawElement(html_names::kHTMLTag); + doc.appendChild(html); + Node* body = html->appendChild(doc.CreateRawElement(html_names::kBodyTag)); + ToElement(body)->SetInnerHTMLFromString("<select form='ff'></select>"); + DocumentState* document_state = doc.GetFormController().FormElementsState(); + Vector<String> state1 = document_state->ToStateVector(); + // <signature>, <control-size>, <form-key>, <name>, <type>, <data-size(0)> + EXPECT_EQ(6u, state1.size()); + Node* select = body->firstChild(); + select->remove(); + // Success if the following ToStateVector() doesn't fail with a DCHECK. + Vector<String> state2 = document_state->ToStateVector(); + EXPECT_EQ(0u, state2.size()); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/listed_element.cc b/third_party/blink/renderer/core/html/forms/listed_element.cc index 14728f9..96f1bf4 100644 --- a/third_party/blink/renderer/core/html/forms/listed_element.cc +++ b/third_party/blink/renderer/core/html/forms/listed_element.cc
@@ -142,14 +142,14 @@ if (insertion_point.isConnected() && element->FastHasAttribute(kFormAttr)) { SetFormAttributeTargetObserver(nullptr); ResetFormOwner(); - return; + } else { + // If the form and element are both in the same tree, preserve the + // connection to the form. Otherwise, null out our form and remove + // ourselves from the form's list of elements. + if (form_ && NodeTraversal::HighestAncestorOrSelf(*element) != + NodeTraversal::HighestAncestorOrSelf(*form_.Get())) + ResetFormOwner(); } - // If the form and element are both in the same tree, preserve the connection - // to the form. Otherwise, null out our form and remove ourselves from the - // form's list of elements. - if (form_ && NodeTraversal::HighestAncestorOrSelf(*element) != - NodeTraversal::HighestAncestorOrSelf(*form_.Get())) - ResetFormOwner(); DisabledStateMightBeChanged();
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl index d46dfafd..9e2e769 100644 --- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl +++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -4053,8 +4053,6 @@ properties # Signed exchange request URL. string requestUrl - # Signed exchange request method. - string requestMethod # Signed exchange response code. integer responseCode # Signed exchange response headers.
diff --git a/third_party/blink/renderer/core/layout/jank_tracker.cc b/third_party/blink/renderer/core/layout/jank_tracker.cc index 81c4cb4..5a49700 100644 --- a/third_party/blink/renderer/core/layout/jank_tracker.cc +++ b/third_party/blink/renderer/core/layout/jank_tracker.cc
@@ -120,6 +120,12 @@ SmallerThanRegionGranularity(new_rect, scale)) return; + // Ignore layout objects that move (in the coordinate space of the paint + // invalidation container) on scroll. + // TODO(skobes): Find a way to detect when these objects jank. + if (source.IsFixedPositioned() || source.IsStickyPositioned()) + return; + const auto* local_xform = TransformNodeFor(painting_layer.GetLayoutObject()); const auto* root_xform = TransformNodeFor(*source.View());
diff --git a/third_party/blink/renderer/core/layout/jank_tracker_test.cc b/third_party/blink/renderer/core/layout/jank_tracker_test.cc index 312d5165..aa8e01e2 100644 --- a/third_party/blink/renderer/core/layout/jank_tracker_test.cc +++ b/third_party/blink/renderer/core/layout/jank_tracker_test.cc
@@ -202,4 +202,35 @@ UpdateAllLifecyclePhases(); } +TEST_F(JankTrackerTest, IgnoreFixedAndSticky) { + SetBodyInnerHTML(R"HTML( + <style> + body { height: 1000px; } + #f1, #f2 { + position: fixed; + width: 300px; + height: 100px; + left: 100px; + } + #f1 { top: 0; } + #f2 { top: 150px; will-change: transform; } + #s1 { + position: sticky; + width: 200px; + height: 100px; + left: 450px; + top: 0; + } + </style> + <div id='f1'>fixed</div> + <div id='f2'>fixed composited</div> + <div id='s1'>sticky</div> + normal + )HTML"); + + GetDocument().scrollingElement()->setScrollTop(50); + UpdateAllLifecyclePhases(); + EXPECT_FLOAT_EQ(0, GetJankTracker().Score()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_object.cc b/third_party/blink/renderer/core/layout/layout_embedded_object.cc index 9061a8c8..2291e0d 100644 --- a/third_party/blink/renderer/core/layout/layout_embedded_object.cc +++ b/third_party/blink/renderer/core/layout/layout_embedded_object.cc
@@ -99,6 +99,7 @@ if (!GetEmbeddedContentView() && GetFrameView()) GetFrameView()->AddPartToUpdate(*this); + ClearSelfNeedsLayoutOverflowRecalc(); ClearNeedsLayout(); }
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc index 67aa2a70..f17f377 100644 --- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc +++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -84,6 +84,8 @@ LayoutUnit min_preferred_logical_width; LayoutUnit max_preferred_logical_width; + if (child->NeedsPreferredWidthsRecalculation()) + child->SetPreferredLogicalWidthsDirty(); ComputeChildPreferredLogicalWidths(*child, min_preferred_logical_width, max_preferred_logical_width); DCHECK_GE(min_preferred_logical_width, LayoutUnit());
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc index fae0db0e..23fab7d45 100644 --- a/third_party/blink/renderer/core/layout/layout_image.cc +++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -71,11 +71,15 @@ // Render the image as a placeholder image if the document does not have the // 'unoptimized-images' feature enabled and the image is not // sufficiently-well-compressed. - if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() && - !document.IsFeatureEnabled( - mojom::FeaturePolicyFeature::kUnoptimizedImages)) { - if (!new_image->IsAcceptableCompressionRatio()) + if (!new_image->IsAcceptableCompressionRatio()) { + document.CountPotentialFeaturePolicyViolation( + mojom::FeaturePolicyFeature::kUnoptimizedImages); + if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() && + !document.IsFeatureEnabled( + mojom::FeaturePolicyFeature::kUnoptimizedImages, + ReportOptions::kReportOnFailure)) { return true; + } } return false; }
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index f1f4527..e2297e7 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -1974,17 +1974,29 @@ object = object->IsTableCell() || object->IsTableRow() ? object->Parent() : object->Container(); - if (object) + if (object) { object->SetChildNeedsLayoutOverflowRecalc(); + + if (object->HasLayer()) { + auto* box_model_object = ToLayoutBoxModelObject(object); + if (box_model_object->HasSelfPaintingLayer()) + box_model_object->Layer()->SetNeedsVisualOverflowRecalc(); + } + } + } while (object); } void LayoutObject::SetNeedsOverflowRecalc() { - bool needed_recalc = NeedsLayoutOverflowRecalc(); + bool needed_recalc = SelfNeedsLayoutOverflowRecalc(); SetSelfNeedsLayoutOverflowRecalc(); - if (auto* painting_layer = PaintingLayer()) - painting_layer->SetNeedsVisualOverflowRecalc(); SetShouldCheckForPaintInvalidation(); + + if (HasLayer()) { + auto* box_model_object = ToLayoutBoxModelObject(this); + if (box_model_object->HasSelfPaintingLayer()) + box_model_object->Layer()->SetNeedsVisualOverflowRecalc(); + } if (!needed_recalc) MarkContainerChainForOverflowRecalcIfNeeded(); }
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc index 8979ae371..a623bc9 100644 --- a/third_party/blink/renderer/core/layout/layout_text.cc +++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -1616,8 +1616,11 @@ // If we have only one line of text and "contain: layout size" we can avoid // doing a layout and only paint in the SetText() operation. return Parent()->IsLayoutBlockFlow() && - (Parent()->ShouldApplyLayoutContainment() && - Parent()->ShouldApplySizeContainment()) && + Parent()->ShouldApplyLayoutContainment() && + Parent()->ShouldApplySizeContainment() && + // If we have "text-overflow: ellipsis" we need to check if we need or + // not ellipsis in the new text and recompute its position. + !ToLayoutBlockFlow(Parent())->ShouldTruncateOverflowingText() && !PreviousSibling() && !NextSibling() && FirstTextBox() && FirstTextBox() == LastTextBox() && // If "line-height" is "normal" we might need to recompute the
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc index 3683cd9..f0d6208 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -1245,6 +1245,8 @@ !child_space.FloatsBfcBlockOffset(); bool is_empty_block = IsEmptyBlock(child_space, *layout_result); + bool has_clearance = layout_result->IsPushedByFloats(); + // A child may have aborted its layout if it resolved its BFC block offset. // If we don't have a BFC block offset yet, we need to propagate the abortion // up to our parent. @@ -1258,7 +1260,9 @@ DCHECK(child_bfc_block_offset); abort_when_bfc_block_offset_updated_ = true; ResolveBfcBlockOffset(previous_inflow_position, - child_bfc_block_offset.value()); + has_clearance + ? NextBorderEdge(*previous_inflow_position) + : child_bfc_block_offset.value()); return false; } @@ -1269,7 +1273,6 @@ // We try and position the child within the block formatting context. This // may cause our BFC block offset to be resolved, in which case we should // abort our layout if needed. - bool has_clearance = layout_result->IsPushedByFloats(); if (!child_bfc_block_offset) { if (!has_clearance && child_space.HasClearanceOffset() && child.Style().Clear() != EClear::kNone) { @@ -2217,6 +2220,10 @@ // Otherwise, we need to abort. LayoutUnit old_bfc_block_offset = ConstraintSpace().FloatsBfcBlockOffset().value(); + + // In order to determine if the two offsets are equal, we also need to adjust + // floats offset by the clearance offset. + ApplyClearance(ConstraintSpace(), &old_bfc_block_offset); return container_builder_.BfcBlockOffset().value() != old_bfc_block_offset; }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc index 1eb55b3..ff4165a 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
@@ -45,7 +45,7 @@ initial_break_before_(EBreakBetween::kAuto), final_break_after_(EBreakBetween::kAuto), has_forced_break_(false), - is_pushed_by_floats_(false), + is_pushed_by_floats_(builder->is_pushed_by_floats_), adjoining_floats_(kFloatTypeNone), has_orthogonal_flow_roots_(builder->has_orthogonal_flow_roots_), depends_on_percentage_block_size_(false),
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc index 2be25c90..7e4d148 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -210,6 +210,7 @@ } const auto& old_overflow_rect = VisualOverflowRect(); + ClearSelfNeedsLayoutOverflowRecalc(); ClearLayoutOverflow(); // The scale of one or more of the SVG elements may have changed, content
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc index 6dc21f5b..42eb744 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -297,6 +297,7 @@ DCHECK(!needs_transform_update_); DCHECK(!needs_text_metrics_update_); DCHECK(!needs_positioning_values_update_); + ClearSelfNeedsLayoutOverflowRecalc(); ClearNeedsLayout(); }
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h index 5e88291b4..55bde22 100644 --- a/third_party/blink/renderer/core/loader/empty_clients.h +++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -433,6 +433,7 @@ void Navigate(const ResourceRequest&, bool should_replace_current_entry, bool is_opener_navigation, + bool prevent_sandboxed_download, mojom::blink::BlobURLTokenPtr) override {} unsigned BackForwardLength() override { return 0; } void CheckCompleted() override {}
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc index 0c629ed..b6bdefc 100644 --- a/third_party/blink/renderer/core/loader/frame_loader.cc +++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -1483,9 +1483,7 @@ GetDocumentLoader()->GetHistoryItem()->ScrollRestorationType() == kScrollRestorationManual)); - view->ProcessUrlFragment(url, should_scroll_to_fragment - ? FragmentAnchor::kBehaviorScroll - : FragmentAnchor::kBehaviorDontScroll); + view->ProcessUrlFragment(url, should_scroll_to_fragment); if (boundary_frame && boundary_frame->IsLocalFrame()) ToLocalFrame(boundary_frame)
diff --git a/third_party/blink/renderer/core/loader/interactive_detector.cc b/third_party/blink/renderer/core/loader/interactive_detector.cc index bbd3bec..f55d34e 100644 --- a/third_party/blink/renderer/core/loader/interactive_detector.cc +++ b/third_party/blink/renderer/core/loader/interactive_detector.cc
@@ -22,9 +22,9 @@ // requests for this duration of time. constexpr int kNetworkQuietMaximumConnections = 2; -const char kHistogramInputDelay[] = "PageLoad.InteractiveTiming.InputDelay"; +const char kHistogramInputDelay[] = "PageLoad.InteractiveTiming.InputDelay2"; const char kHistogramInputTimestamp[] = - "PageLoad.InteractiveTiming.InputTimestamp"; + "PageLoad.InteractiveTiming.InputTimestamp2"; // static const char InteractiveDetector::kSupplementName[] = "InteractiveDetector"; @@ -184,6 +184,12 @@ pending_pointerdown_timestamp_ = event.TimeStamp(); return; } + if (event.GetType() == WebInputEvent::kPointerCancel || + event.GetType() == WebInputEvent::kPointerCausedUaAction) { + pending_pointerdown_delay_ = base::TimeDelta(); + pending_pointerdown_timestamp_ = base::TimeTicks(); + return; + } bool event_is_meaningful = event.GetType() == WebInputEvent::kMouseDown ||
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc index b4453d4..05d7b57 100644 --- a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc +++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
@@ -510,7 +510,12 @@ if (!pixels) return true; DCHECK(image_); - double resource_length = GetResponse().ExpectedContentLength(); + double resource_length = + static_cast<double>(GetResponse().ExpectedContentLength()); + if (resource_length <= 0 && GetImage() && GetImage()->Data()) { + // WPT and LayoutTests server returns -1 or 0 for the content length. + resource_length = static_cast<double>(GetImage()->Data()->size()); + } // Allow no more than 10 bits per compressed pixel return (resource_length - 1024) / pixels <= 0.5; }
diff --git a/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc b/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc index 763e75cb..380e397 100644 --- a/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc +++ b/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc
@@ -59,7 +59,7 @@ } // namespace FragmentAnchor* FragmentAnchor::TryCreate(const KURL& url, - Behavior behavior, + bool needs_invoke, LocalFrame& frame) { DCHECK(frame.GetDocument()); Document& doc = *frame.GetDocument(); @@ -103,32 +103,54 @@ if (target) target->DispatchActivateInvisibleEventIfNeeded(); - if (frame.GetDocument()->IsSVGDocument() && !frame.IsMainFrame()) + if (doc.IsSVGDocument() && !frame.IsMainFrame()) return nullptr; - if (!anchor_node || behavior == kBehaviorDontScroll) + if (!anchor_node || !needs_invoke) return nullptr; - return MakeGarbageCollected<FragmentAnchor>(*anchor_node, frame); + auto* anchor = MakeGarbageCollected<FragmentAnchor>(*anchor_node, frame); + + // If rendering isn't ready yet, we'll focus and scroll as part of the + // document lifecycle. + if (doc.IsRenderingReady()) { + anchor->ApplyFocusIfNeeded(); + + // Layout needs to be clean for scrolling but if layout is needed, we'll + // invoke after layout is completed so no need to do it here. Note, the + // view may have been detached by script run during focus() call. + if (frame.View() && !frame.View()->NeedsLayout()) + anchor->Invoke(); + } + + return anchor; } FragmentAnchor::FragmentAnchor(Node& anchor_node, LocalFrame& frame) : anchor_node_(&anchor_node), frame_(&frame), - needs_focus_(!anchor_node.IsDocumentNode()) {} + needs_focus_(!anchor_node.IsDocumentNode()) { + DCHECK(frame_->View()); +} bool FragmentAnchor::Invoke() { - if (!frame_ || !anchor_node_ || !needs_invoke_) + if (!frame_ || !anchor_node_) return false; - if (!frame_->GetDocument()->IsRenderingReady()) + // Don't remove the fragment anchor until focus has been applied. + if (!needs_invoke_) + return needs_focus_; + + Document& doc = *frame_->GetDocument(); + + if (!doc.IsRenderingReady() || !frame_->View()) return true; LayoutRect rect; - if (anchor_node_ != frame_->GetDocument()) { + if (anchor_node_ != &doc) { rect = anchor_node_->BoundingBoxForScrollIntoView(); } else { - if (Element* document_element = frame_->GetDocument()->documentElement()) + if (Element* document_element = doc.documentElement()) rect = document_element->BoundingBoxForScrollIntoView(); } @@ -143,7 +165,7 @@ Element* element_to_scroll = anchor_node_->IsElementNode() ? ToElement(anchor_node_) - : frame_->GetDocument()->documentElement(); + : doc.documentElement(); if (element_to_scroll) { ScrollIntoViewOptions* options = ScrollIntoViewOptions::Create(); options->setBlock("start"); @@ -157,26 +179,13 @@ ->SetSafeToPropagateScrollToParent(true); } - if (AXObjectCache* cache = frame_->GetDocument()->ExistingAXObjectCache()) + if (AXObjectCache* cache = doc.ExistingAXObjectCache()) cache->HandleScrolledToAnchor(anchor_node_); - // If the anchor accepts keyboard focus and fragment scrolling is allowed, - // move focus there to aid users relying on keyboard navigation. - // If anchorNode is not focusable or fragment scrolling is not allowed, - // clear focus, which matches the behavior of other browsers. - if (needs_focus_) { - if (anchor_node_->IsElementNode() && - ToElement(anchor_node_)->IsFocusable()) { - ToElement(anchor_node_)->focus(); - } else { - frame_->GetDocument()->SetSequentialFocusNavigationStartingPoint( - anchor_node_); - frame_->GetDocument()->ClearFocusedElement(); - } - needs_focus_ = false; - } + // Scroll into view above will cause us to clear needs_invoke_ via the + // DidScroll so recompute it here. + needs_invoke_ = !doc.IsLoadCompleted() || needs_focus_; - needs_invoke_ = !frame_->GetDocument()->IsLoadCompleted(); return needs_invoke_; } @@ -206,4 +215,36 @@ visitor->Trace(frame_); } +void FragmentAnchor::PerformPreRafActions() { + ApplyFocusIfNeeded(); +} + +void FragmentAnchor::ApplyFocusIfNeeded() { + // SVG images can load synchronously during style recalc but it's ok to focus + // since we disallow scripting. For everything else, focus() could run script + // so make sure we're at a valid point to do so. + DCHECK(frame_->GetDocument()->IsSVGDocument() || + !ScriptForbiddenScope::IsScriptForbidden()); + + if (!needs_focus_) + return; + + if (!frame_->GetDocument()->IsRenderingReady()) + return; + + // If the anchor accepts keyboard focus and fragment scrolling is allowed, + // move focus there to aid users relying on keyboard navigation. + // If anchorNode is not focusable or fragment scrolling is not allowed, + // clear focus, which matches the behavior of other browsers. + frame_->GetDocument()->UpdateStyleAndLayoutTree(); + if (anchor_node_->IsElementNode() && ToElement(anchor_node_)->IsFocusable()) { + ToElement(anchor_node_)->focus(); + } else { + frame_->GetDocument()->SetSequentialFocusNavigationStartingPoint( + anchor_node_); + frame_->GetDocument()->ClearFocusedElement(); + } + needs_focus_ = false; +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h b/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h index c7385f1c..32ee9d16 100644 --- a/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h +++ b/third_party/blink/renderer/core/page/scrolling/fragment_anchor.h
@@ -26,20 +26,17 @@ // should be handled by scroll-anchoring? class CORE_EXPORT FragmentAnchor : public GarbageCollected<FragmentAnchor> { public: - // In some cases, we want to change the fragment's behavior. E.g. If we're - // restoring the scroll position from history, we want to prevent scrolling - // the target into view but we still want to parse and set the :target on the - // document. - enum Behavior { kBehaviorScroll, kBehaviorDontScroll }; - // Parses the fragment string and tries to create a FragmentAnchor object. If // an appropriate target was found based on the given fragment, this method // will create and return a FragmentAnchor object that can be used to keep it // in view. Otherwise, this will return nullptr. In either case, // side-effects on the document will be performed, for example, - // setting/clearing :target and svgView(). + // setting/clearing :target and svgView(). If needs_invoke is false, only the + // side effects will be performed, the element won't be scrolled/focused and + // this method returns nullptr (e.g. used during history navigation where we + // don't want to clobber the history scroll restoration). static FragmentAnchor* TryCreate(const KURL& url, - Behavior behavior, + bool needs_invoke, LocalFrame& frame); FragmentAnchor(Node& anchor_node, LocalFrame& frame); @@ -56,11 +53,15 @@ // scrolls. void DidScroll(ScrollType type); + void PerformPreRafActions(); + void DidCompleteLoad(); void Trace(blink::Visitor*); private: + void ApplyFocusIfNeeded(); + WeakMember<Node> anchor_node_; Member<LocalFrame> frame_; bool needs_focus_;
diff --git a/third_party/blink/renderer/core/page/scrolling/fragment_anchor_test.cc b/third_party/blink/renderer/core/page/scrolling/fragment_anchor_test.cc new file mode 100644 index 0000000..022d8ba --- /dev/null +++ b/third_party/blink/renderer/core/page/scrolling/fragment_anchor_test.cc
@@ -0,0 +1,94 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/web/web_script_source.h" +#include "third_party/blink/renderer/core/css/css_style_declaration.h" +#include "third_party/blink/renderer/core/frame/local_frame_view.h" +#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" +#include "third_party/blink/renderer/core/html/html_anchor_element.h" +#include "third_party/blink/renderer/core/layout/layout_object.h" +#include "third_party/blink/renderer/core/page/focus_controller.h" +#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" +#include "third_party/blink/renderer/core/testing/sim/sim_request.h" +#include "third_party/blink/renderer/core/testing/sim/sim_test.h" +#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" + +namespace blink { + +namespace { + +using test::RunPendingTasks; + +class FragmentAnchorTest : public SimTest {}; + +// Ensure that the focus event handler is run before the rAF callback. We'll +// change the background color from a rAF set in the focus handler and make +// sure the computed background color of that frame was changed. See: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/5BJSTl-FMGY/JMtaKqGhBAAJ +TEST_F(FragmentAnchorTest, FocusHandlerRunBeforeRaf) { + SimRequest main_resource("https://example.com/test.html", "text/html"); + SimSubresourceRequest css_resource("https://example.com/sheet.css", + "text/css"); + LoadURL("https://example.com/test.html"); + + main_resource.Complete(R"HTML( + <!DOCTYPE html> + <style> + body { + background-color: red; + } + </style> + <link rel="stylesheet" type="text/css" href="sheet.css"> + <a id="anchorlink" href="#bottom">Link to bottom of the page</a> + <div style="height: 1000px;"></div> + <input id="bottom">Bottom of the page</input> + )HTML"); + + MainFrame().ExecuteScript(WebScriptSource(R"HTML( + document.getElementById("bottom").addEventListener('focus', () => { + requestAnimationFrame(() => { + document.body.style.backgroundColor = '#00FF00'; + }); + }); + )HTML")); + + // Focus handlers aren't run unless the page is focused. + GetDocument().GetPage()->GetFocusController().SetFocused(true); + + // We're still waiting on the stylesheet to load so the load event shouldn't + // yet dispatch and rendering is deferred. + ASSERT_FALSE(GetDocument().IsRenderingReady()); + ASSERT_FALSE(GetDocument().IsLoadCompleted()); + + // Click on the anchor element. This will cause a synchronous same-document + // navigation. + HTMLAnchorElement* anchor = + ToHTMLAnchorElement(GetDocument().getElementById("anchorlink")); + anchor->click(); + ASSERT_EQ(GetDocument().body(), GetDocument().ActiveElement()) + << "Active element changed while rendering is blocked"; + + // Complete the CSS stylesheet load so the document can finish loading. The + // fragment should be activated at that point. + css_resource.Complete(""); + Compositor().BeginFrame(); + + ASSERT_FALSE(GetDocument().IsLoadCompleted()); + ASSERT_TRUE(GetDocument().IsRenderingReady()); + ASSERT_EQ(GetDocument().getElementById("bottom"), + GetDocument().ActiveElement()) + << "Active element wasn't changed after rendering was unblocked."; + EXPECT_EQ(GetDocument() + .body() + ->GetLayoutObject() + ->Style() + ->VisitedDependentColor(GetCSSPropertyBackgroundColor()) + .NameForLayoutTreeAsText(), + Color(0, 255, 0).NameForLayoutTreeAsText()); +} + +} // namespace + +} // namespace blink
diff --git a/third_party/blink/renderer/core/page/validation_message_client_impl.cc b/third_party/blink/renderer/core/page/validation_message_client_impl.cc index 81f5bbe..801a952 100644 --- a/third_party/blink/renderer/core/page/validation_message_client_impl.cc +++ b/third_party/blink/renderer/core/page/validation_message_client_impl.cc
@@ -32,6 +32,7 @@ #include "cc/layers/picture_layer.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/web/web_text_direction.h" +#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" @@ -88,6 +89,8 @@ overlay_ = FrameOverlay::Create(target_frame, std::move(delegate)); bool success = target_frame->View()->UpdateLifecycleToCompositingCleanPlusScrolling(); + ValidationMessageVisibilityChanged(anchor); + // The lifecycle update should always succeed, because this is not inside // of a throttling scope. DCHECK(success); @@ -99,8 +102,12 @@ HideValidationMessageImmediately(anchor); return; } - if (!current_anchor_ || !IsValidationMessageVisible(anchor)) + if (!current_anchor_ || !IsValidationMessageVisible(anchor) || + overlay_delegate_->IsHiding()) { + // Do not continue if already hiding, otherwise timer will never complete + // and Reset() is never called. return; + } DCHECK(overlay_); overlay_delegate_->StartToHide(); timer_ = std::make_unique<TaskRunnerTimer<ValidationMessageClientImpl>>( @@ -120,6 +127,8 @@ } void ValidationMessageClientImpl::Reset(TimerBase*) { + const Element& anchor = *current_anchor_; + timer_ = nullptr; current_anchor_ = nullptr; message_ = String(); @@ -127,6 +136,14 @@ overlay_ = nullptr; overlay_delegate_ = nullptr; page_->GetChromeClient().UnregisterPopupOpeningObserver(this); + ValidationMessageVisibilityChanged(anchor); +} + +void ValidationMessageClientImpl::ValidationMessageVisibilityChanged( + const Element& element) { + Document& document = element.GetDocument(); + if (AXObjectCache* cache = document.ExistingAXObjectCache()) + cache->HandleValidationMessageVisibilityChanged(&element); } bool ValidationMessageClientImpl::IsValidationMessageVisible(
diff --git a/third_party/blink/renderer/core/page/validation_message_client_impl.h b/third_party/blink/renderer/core/page/validation_message_client_impl.h index 4c39879..276a2ca 100644 --- a/third_party/blink/renderer/core/page/validation_message_client_impl.h +++ b/third_party/blink/renderer/core/page/validation_message_client_impl.h
@@ -59,6 +59,7 @@ LocalFrameView* CurrentView(); void HideValidationMessageImmediately(const Element& anchor); void Reset(TimerBase*); + void ValidationMessageVisibilityChanged(const Element& anchor); void ShowValidationMessage(const Element& anchor, const String& message,
diff --git a/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h b/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h index 3442dfde..f741cff 100644 --- a/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h +++ b/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h
@@ -38,6 +38,7 @@ GraphicsContext&, const IntSize& view_size) const override; void StartToHide(); + bool IsHiding() const; private: ValidationMessageOverlayDelegate(Page&, @@ -52,7 +53,6 @@ void WriteDocument(SharedBuffer*); Element& GetElementById(const AtomicString&) const; void AdjustBubblePosition(const IntSize& view_size); - bool IsHiding() const; // An internal Page and a ChromeClient for it. Persistent<Page> page_;
diff --git a/third_party/blink/renderer/core/paint/document_marker_painter.cc b/third_party/blink/renderer/core/paint/document_marker_painter.cc index 40063a37..4c4954f8 100644 --- a/third_party/blink/renderer/core/paint/document_marker_painter.cc +++ b/third_party/blink/renderer/core/paint/document_marker_painter.cc
@@ -60,6 +60,8 @@ static const float kMarkerWidth = 4; static const float kMarkerHeight = 3; +// Spacing between two dots. +static const float kMarkerSpacing = 1; sk_sp<PaintRecord> RecordMarker(Color blink_color) { const SkColor color = blink_color.Rgb(); @@ -116,10 +118,8 @@ #if defined(OS_MACOSX) // Make sure to draw only complete dots, and finish inside the marked text. - width -= fmodf(width, kMarkerWidth * zoom); -#else - // Offset it vertically by 1 so that there's some space under the text. - origin_y += 1; + float spacing = kMarkerSpacing * zoom; + width -= fmodf(width + spacing, kMarkerWidth * zoom) - spacing; #endif const auto rect = SkRect::MakeWH(width, kMarkerHeight * zoom); @@ -164,19 +164,20 @@ start += 1; width -= 2; - // Thick marked text underlines are 2px thick as long as there is room for the - // 2px line under the baseline. All other marked text underlines are 1px - // thick. If there's not enough space the underline will touch or overlap - // characters. - int line_thickness = 1; + // Thick marked text underlines are 2px (before zoom) thick as long as there + // is room for the 2px line under the baseline. All other marked text + // underlines are 1px (before zoom) thick. If there's not enough space the + // underline will touch or overlap characters. Line thickness should change + // with zoom. + int line_thickness = 1 * style.EffectiveZoom(); const SimpleFontData* font_data = style.GetFont().PrimaryFont(); DCHECK(font_data); int baseline = font_data ? font_data->GetFontMetrics().Ascent() : 0; - if (marker.HasThicknessThick() && logical_height.ToInt() - baseline >= 2) - line_thickness = 2; - - // Line thickness should change with zoom. - line_thickness *= style.EffectiveZoom(); + if (marker.HasThicknessThick()) { + int thick_line_thickness = 2 * style.EffectiveZoom(); + if (logical_height.ToInt() - baseline >= thick_line_thickness) + line_thickness = thick_line_thickness; + } Color marker_color = marker.UseTextColor() @@ -192,8 +193,6 @@ width); } -static const int kMisspellingLineThickness = 3; - void DocumentMarkerPainter::PaintDocumentMarker( GraphicsContext& context, const LayoutPoint& box_origin, @@ -208,26 +207,28 @@ // actually the most useful, and matches what AppKit does. So, we generally // place the underline at the bottom of the text, but in larger fonts that's // not so good so we pin to two pixels under the baseline. - int line_thickness = kMisspellingLineThickness; + float zoom = style.EffectiveZoom(); + int line_thickness = kMarkerHeight * zoom; const SimpleFontData* font_data = style.GetFont().PrimaryFont(); DCHECK(font_data); int baseline = font_data->GetFontMetrics().Ascent(); - int descent = (local_rect.Height() - baseline).ToInt(); + int available_height = (local_rect.Height() - baseline).ToInt(); int underline_offset; - if (descent <= (line_thickness + 2)) { + if (available_height <= line_thickness + 2 * zoom) { // Place the underline at the very bottom of the text in small/medium fonts. + // The underline will overlap with the bottom of the text if + // available_height is smaller than line_thickness. underline_offset = (local_rect.Height() - line_thickness).ToInt(); } else { // In larger fonts, though, place the underline up near the baseline to // prevent a big gap. - underline_offset = baseline + 2; + underline_offset = baseline + 2 * zoom; } DrawDocumentMarker(context, FloatPoint((box_origin.X() + local_rect.X()).ToFloat(), (box_origin.Y() + underline_offset).ToFloat()), - local_rect.Width().ToFloat(), marker_type, - style.EffectiveZoom()); + local_rect.Width().ToFloat(), marker_type, zoom); } TextPaintStyle DocumentMarkerPainter::ComputeTextPaintStyleFrom(
diff --git a/third_party/blink/renderer/core/paint/image_painter.cc b/third_party/blink/renderer/core/paint/image_painter.cc index e8182e36..9f5ba5f 100644 --- a/third_party/blink/renderer/core/paint/image_painter.cc +++ b/third_party/blink/renderer/core/paint/image_painter.cc
@@ -204,7 +204,8 @@ SkBlendMode::kSrcOver, LayoutObject::ShouldRespectImageOrientation(&layout_image_)); if (origin_trials::ElementTimingEnabled(&layout_image_.GetDocument()) && - IsHTMLImageElement(node) && !context.ContextDisabled()) { + IsHTMLImageElement(node) && !context.ContextDisabled() && + layout_image_.CachedImage() && layout_image_.CachedImage()->IsLoaded()) { LocalDOMWindow* window = layout_image_.GetDocument().domWindow(); DCHECK(window); ImageElementTiming::From(*window).NotifyImagePainted(
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/third_party/blink/renderer/core/paint/link_highlight_impl.cc index 93b5985..392fc38 100644 --- a/third_party/blink/renderer/core/paint/link_highlight_impl.cc +++ b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
@@ -273,6 +273,10 @@ layer_->SetElementId(element_id); } +LinkHighlightImpl::LinkHighlightFragment::~LinkHighlightFragment() { + layer_->ClearClient(); +} + gfx::Rect LinkHighlightImpl::LinkHighlightFragment::PaintableRegion() { return gfx::Rect(layer_->bounds()); }
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl.h b/third_party/blink/renderer/core/paint/link_highlight_impl.h index 94e4099..1de5890 100644 --- a/third_party/blink/renderer/core/paint/link_highlight_impl.h +++ b/third_party/blink/renderer/core/paint/link_highlight_impl.h
@@ -114,6 +114,7 @@ class LinkHighlightFragment : private cc::ContentLayerClient { public: LinkHighlightFragment(CompositorElementId); + ~LinkHighlightFragment() override; cc::PictureLayer* Layer() const { return layer_.get(); } const Path& GetPath() const { return path_; }
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc index aa8f95f..990a8582 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -804,6 +804,17 @@ paint_info.phase != PaintPhase::kMask) return; + // Note: To paint selection for <br>, we don't check intersection with + // fragment paint rect and cull rect since computing selection rect is + // expensive. + if (!text_fragment.Size().IsEmpty()) { + LayoutRect physical_visual_overflow = text_fragment.SelfInkOverflow(); + physical_visual_overflow.MoveBy(text_fragment.Offset().ToLayoutPoint()); + physical_visual_overflow.MoveBy(paint_offset); + if (!paint_info.GetCullRect().Intersects(physical_visual_overflow)) + return; + } + // The text clip phase already has a DrawingRecorder. Text clips are initiated // only in BoxPainterBase::PaintFillLayer, which is already within a // DrawingRecorder.
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc index 6d53b8fb..c5a561b 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -80,6 +80,7 @@ #include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/core/page/focus_controller.h" #include "third_party/blink/renderer/core/page/page.h" +#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h" #include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h" #include "third_party/blink/renderer/core/page/scrolling/root_scroller_util.h" #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
diff --git a/third_party/blink/renderer/core/streams/underlying_source_base.idl b/third_party/blink/renderer/core/streams/underlying_source_base.idl index 8e61f0aa..d943658b 100644 --- a/third_party/blink/renderer/core/streams/underlying_source_base.idl +++ b/third_party/blink/renderer/core/streams/underlying_source_base.idl
@@ -14,7 +14,7 @@ interface UnderlyingSourceBase { [CallWith=ScriptState, ImplementedAs=startWrapper] Promise<void> start(any stream); [CallWith=ScriptState] Promise<void> pull(); - [CallWith=ScriptState, ImplementedAs=cancelWrapper] Promise<void> cancel([Default=Undefined] optional any reason); + [CallWith=ScriptState, ImplementedAs=cancelWrapper] Promise<void> cancel([DefaultValue=Undefined] optional any reason); // This only exists to prevent Object.prototype.type being accessed. [CallWith=ScriptState] readonly attribute any type;
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index 5af5ed71..02ee116 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -84,12 +84,30 @@ // Since different compilers/architectures pack ComputedStyle differently, // re-create the same structure for an accurate size comparison. -struct SameSizeAsComputedStyle : public RefCounted<SameSizeAsComputedStyle> { - struct ComputedStyleBase { - void* data_refs[7]; - unsigned bitfields_[4]; - } base_; +// +// Keep a separate struct for ComputedStyleBase so that we can recreate the +// inheritance structure. Make sure the fields have the same access specifiers +// as in the "real" class since it can affect the layout. Reference the fields +// so that they are not seen as unused (-Wunused-private-field). +struct SameSizeAsComputedStyleBase { + SameSizeAsComputedStyleBase() { + base::debug::Alias(&data_refs); + base::debug::Alias(&bitfields); + } + private: + void* data_refs[7]; + unsigned bitfields[4]; +}; + +struct SameSizeAsComputedStyle : public SameSizeAsComputedStyleBase, + public RefCounted<SameSizeAsComputedStyle> { + SameSizeAsComputedStyle() { + base::debug::Alias(&own_ptrs); + base::debug::Alias(&data_ref_svg_style); + } + + private: void* own_ptrs[1]; void* data_ref_svg_style; };
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc index 4d8ccaa9..ef6e451 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc +++ b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
@@ -135,4 +135,9 @@ WorkerGlobalScope::Trace(visitor); } +mojom::RequestContextType +DedicatedWorkerGlobalScope::GetDestinationForMainScript() { + return mojom::RequestContextType::WORKER; +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h index 10687a3..4b36b39 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h +++ b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
@@ -86,6 +86,8 @@ DedicatedWorkerObjectProxy& WorkerObjectProxy() const; private: + mojom::RequestContextType GetDestinationForMainScript() override; + const String name_; };
diff --git a/third_party/blink/renderer/core/workers/experimental/thread_pool_thread.cc b/third_party/blink/renderer/core/workers/experimental/thread_pool_thread.cc index aebbb91..b7c67ece 100644 --- a/third_party/blink/renderer/core/workers/experimental/thread_pool_thread.cc +++ b/third_party/blink/renderer/core/workers/experimental/thread_pool_thread.cc
@@ -45,6 +45,11 @@ } void ExceptionThrown(ErrorEvent*) override {} + + mojom::RequestContextType GetDestinationForMainScript() override { + // TODO(nhiroki): Return an appropriate destination. + return mojom::RequestContextType::WORKER; + } }; } // anonymous namespace
diff --git a/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc b/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc index f529c61..3dfd2d9 100644 --- a/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc +++ b/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc
@@ -94,4 +94,9 @@ WorkerGlobalScope::Trace(visitor); } +mojom::RequestContextType +SharedWorkerGlobalScope::GetDestinationForMainScript() { + return mojom::RequestContextType::SHARED_WORKER; +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/workers/shared_worker_global_scope.h b/third_party/blink/renderer/core/workers/shared_worker_global_scope.h index 649150d..4f37a3d 100644 --- a/third_party/blink/renderer/core/workers/shared_worker_global_scope.h +++ b/third_party/blink/renderer/core/workers/shared_worker_global_scope.h
@@ -73,6 +73,7 @@ private: void ExceptionThrown(ErrorEvent*) override; + mojom::RequestContextType GetDestinationForMainScript() override; const String name_; };
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.cc b/third_party/blink/renderer/core/workers/worker_global_scope.cc index 64448f5..fa257ad7 100644 --- a/third_party/blink/renderer/core/workers/worker_global_scope.cc +++ b/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -366,8 +366,8 @@ // Step 12. "Fetch a classic worker script given url, outside settings, // destination, and inside settings." - // TODO(nhiroki): Load a main script using |outside_settings_object|. - // (https://crbug.com/835717, https://crbug.com/880027) + mojom::RequestContextType destination = GetDestinationForMainScript(); + DCHECK_EQ(mojom::RequestContextType::WORKER, destination); // Step 12.1. "Set request's reserved client to inside settings." // The browesr process takes care of this. @@ -379,8 +379,7 @@ MakeGarbageCollected<WorkerClassicScriptLoader>(); classic_script_loader->LoadTopLevelScriptAsynchronously( *execution_context, CreateOutsideSettingsFetcher(outside_settings_object), - script_url, mojom::RequestContextType::WORKER, - network::mojom::FetchRequestMode::kSameOrigin, + script_url, destination, network::mojom::FetchRequestMode::kSameOrigin, network::mojom::FetchCredentialsMode::kSameOrigin, GetSecurityContext().AddressSpace(), WTF::Bind(&WorkerGlobalScope::DidReceiveResponseForClassicScript,
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h index edfea63..ae3878af 100644 --- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h +++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
@@ -138,6 +138,8 @@ void TasksWerePaused() override; void TasksWereUnpaused() override; + virtual mojom::RequestContextType GetDestinationForMainScript() = 0; + private: void InitializeWebFetchContextIfNeeded(); ResourceFetcher* CreateFetcherInternal(FetchClientSettingsObject*);
diff --git a/third_party/blink/renderer/core/workers/worker_thread_test_helper.h b/third_party/blink/renderer/core/workers/worker_thread_test_helper.h index 9eae2789..05ecd5f 100644 --- a/third_party/blink/renderer/core/workers/worker_thread_test_helper.h +++ b/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
@@ -65,6 +65,10 @@ } void ExceptionThrown(ErrorEvent*) override {} + + mojom::RequestContextType GetDestinationForMainScript() override { + return mojom::RequestContextType::WORKER; + } }; class WorkerThreadForTest : public WorkerThread {
diff --git a/third_party/blink/renderer/core/workers/worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worklet_global_scope.cc index 88da265..0256de0 100644 --- a/third_party/blink/renderer/core/workers/worklet_global_scope.cc +++ b/third_party/blink/renderer/core/workers/worklet_global_scope.cc
@@ -209,11 +209,8 @@ MakeGarbageCollected<WorkletModuleTreeClient>( modulator, std::move(outside_settings_task_runner), pending_tasks); - // TODO(nhiroki): Specify an appropriate destination defined in each worklet - // spec (e.g., "paint worklet", "audio worklet"). - mojom::RequestContextType destination = mojom::RequestContextType::SCRIPT; - FetchModuleScript(module_url_record, outside_settings_object, destination, - credentials_mode, + FetchModuleScript(module_url_record, outside_settings_object, + GetDestinationForMainScript(), credentials_mode, ModuleScriptCustomFetchType::kWorkletAddModule, client); } @@ -241,6 +238,13 @@ GetContentSecurityPolicy()->SetupSelf(*document_security_origin_); } +mojom::RequestContextType WorkletGlobalScope::GetDestinationForMainScript() { + // TODO(nhiroki): Return an appropriate destination defined in each worklet + // spec (e.g., "paint worklet", "audio worklet") (https://crbug.com/843980, + // https://crbug.com/843982) + return mojom::RequestContextType::SCRIPT; +} + void WorkletGlobalScope::Trace(blink::Visitor* visitor) { visitor->Trace(frame_); WorkerOrWorkletGlobalScope::Trace(visitor);
diff --git a/third_party/blink/renderer/core/workers/worklet_global_scope.h b/third_party/blink/renderer/core/workers/worklet_global_scope.h index 2b748a3..62b75e95 100644 --- a/third_party/blink/renderer/core/workers/worklet_global_scope.h +++ b/third_party/blink/renderer/core/workers/worklet_global_scope.h
@@ -157,6 +157,8 @@ void BindContentSecurityPolicyToExecutionContext() override; + mojom::RequestContextType GetDestinationForMainScript() override; + // The |url_| and |user_agent_| are inherited from the parent Document. const KURL url_; const String user_agent_;
diff --git a/third_party/blink/renderer/core/xml/xpath_ns_resolver.idl b/third_party/blink/renderer/core/xml/xpath_ns_resolver.idl index cb45d03..5d2a030e 100644 --- a/third_party/blink/renderer/core/xml/xpath_ns_resolver.idl +++ b/third_party/blink/renderer/core/xml/xpath_ns_resolver.idl
@@ -28,5 +28,5 @@ [ NoInterfaceObject ] interface XPathNSResolver { - DOMString? lookupNamespaceURI([Default=Undefined] optional DOMString prefix); + DOMString? lookupNamespaceURI([DefaultValue=Undefined] optional DOMString prefix); };
diff --git a/third_party/blink/renderer/devtools/front_end/accessibility/AXBreadcrumbsPane.js b/third_party/blink/renderer/devtools/front_end/accessibility/AXBreadcrumbsPane.js index 34708e0c..9075c5e 100644 --- a/third_party/blink/renderer/devtools/front_end/accessibility/AXBreadcrumbsPane.js +++ b/third_party/blink/renderer/devtools/front_end/accessibility/AXBreadcrumbsPane.js
@@ -112,7 +112,7 @@ _onKeyDown(event) { if (!this._preselectedBreadcrumb) return; - if (!event.path.some(element => element === this._preselectedBreadcrumb.element())) + if (!event.composedPath().some(element => element === this._preselectedBreadcrumb.element())) return; if (event.shiftKey || event.metaKey || event.ctrlKey) return;
diff --git a/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityNodeView.js b/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityNodeView.js index 0706be5..f7776e3e 100644 --- a/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityNodeView.js +++ b/third_party/blink/renderer/devtools/front_end/accessibility/AccessibilityNodeView.js
@@ -151,7 +151,7 @@ * @return {!Element} */ static createExclamationMark(tooltip) { - const exclamationElement = createElement('label', 'dt-icon-label'); + const exclamationElement = createElement('span', 'dt-icon-label'); exclamationElement.type = 'smallicon-warning'; exclamationElement.title = tooltip; return exclamationElement;
diff --git a/third_party/blink/renderer/devtools/front_end/accessibility/accessibilityNode.css b/third_party/blink/renderer/devtools/front_end/accessibility/accessibilityNode.css index a6e59ca..7b624a9e 100644 --- a/third_party/blink/renderer/devtools/front_end/accessibility/accessibilityNode.css +++ b/third_party/blink/renderer/devtools/front_end/accessibility/accessibilityNode.css
@@ -47,7 +47,7 @@ padding-left: 4px; } -.tree-outline label[is=dt-icon-label] { +.tree-outline span[is=dt-icon-label] { position: relative; left: -11px; } @@ -74,7 +74,7 @@ left: -2px; } -.tree-outline label[is=dt-icon-label] + .ax-name { +.tree-outline span[is=dt-icon-label] + .ax-name { margin-left: -11px; }
diff --git a/third_party/blink/renderer/devtools/front_end/changes/changesView.css b/third_party/blink/renderer/devtools/front_end/changes/changesView.css index 8d3ad90..552e9ec 100644 --- a/third_party/blink/renderer/devtools/front_end/changes/changesView.css +++ b/third_party/blink/renderer/devtools/front_end/changes/changesView.css
@@ -3,14 +3,15 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -.insertion-point-main{ +[slot=insertion-point-main]{ flex-direction: column; display: flex; } -.insertion-point-sidebar { +[slot=insertion-point-sidebar] { overflow: auto; } + .editor-container{ flex: 1; }
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js index c1c8050e..5279e4e 100644 --- a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js +++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
@@ -1328,7 +1328,7 @@ return; if (!this._repeatCountElement) { - this._repeatCountElement = createElementWithClass('label', 'console-message-repeat-count', 'dt-small-bubble'); + this._repeatCountElement = createElementWithClass('span', 'console-message-repeat-count', 'dt-small-bubble'); switch (this._message.level) { case SDK.ConsoleMessage.MessageLevel.Warning: this._repeatCountElement.type = 'warning';
diff --git a/third_party/blink/renderer/devtools/front_end/console_counters/WarningErrorCounter.js b/third_party/blink/renderer/devtools/front_end/console_counters/WarningErrorCounter.js index b51e2ef..b17e8ae 100644 --- a/third_party/blink/renderer/devtools/front_end/console_counters/WarningErrorCounter.js +++ b/third_party/blink/renderer/devtools/front_end/console_counters/WarningErrorCounter.js
@@ -39,7 +39,7 @@ */ _createItem(shadowRoot, iconType) { const item = createElementWithClass('span', 'counter-item'); - const icon = item.createChild('label', '', 'dt-icon-label'); + const icon = item.createChild('span', '', 'dt-icon-label'); icon.type = iconType; const text = icon.createChild('span'); shadowRoot.appendChild(item);
diff --git a/third_party/blink/renderer/devtools/front_end/console_counters/errorWarningCounter.css b/third_party/blink/renderer/devtools/front_end/console_counters/errorWarningCounter.css index d6ad447d..ee6de7a 100644 --- a/third_party/blink/renderer/devtools/front_end/console_counters/errorWarningCounter.css +++ b/third_party/blink/renderer/devtools/front_end/console_counters/errorWarningCounter.css
@@ -18,10 +18,6 @@ margin-left: 6px; } -.counter-item label { - cursor: inherit; -} - .counter-item.counter-item-first { margin-left: 0; }
diff --git a/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js b/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js index 95253a4..708adc2d 100644 --- a/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js +++ b/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js
@@ -270,10 +270,12 @@ */ Node.prototype.hasSelection = function() { // TODO(luoe): use contains(node, {includeShadow: true}) when it is fixed for shadow dom. - const contents = this.querySelectorAll('content'); - for (const content of contents) { - if (Array.prototype.some.call(content.getDistributedNodes(), node => node.hasSelection())) - return true; + if (this instanceof Element) { + const slots = this.querySelectorAll('slot'); + for (const slot of slots) { + if (Array.prototype.some.call(slot.assignedNodes(), node => node.hasSelection())) + return true; + } } const selection = this.getComponentSelection(); @@ -299,10 +301,11 @@ * @param {string} tagName * @param {string=} customElementType * @return {!Element} + * @suppress {checkTypes} * @suppressGlobalPropertiesCheck */ function createElement(tagName, customElementType) { - return document.createElement(tagName, customElementType || ''); + return document.createElement(tagName, {is: customElementType}); } /** @@ -318,10 +321,11 @@ * @param {string} elementName * @param {string=} className * @param {string=} customElementType + * @suppress {checkTypes} * @return {!Element} */ Document.prototype.createElementWithClass = function(elementName, className, customElementType) { - const element = this.createElement(elementName, customElementType || ''); + const element = this.createElement(elementName, {is: customElementType}); if (className) element.className = className; return element; @@ -651,7 +655,7 @@ if (this.shadowRoot) return this.shadowRoot; - const distributedNodes = this.getDistributedNodes ? this.getDistributedNodes() : []; + const distributedNodes = this instanceof HTMLSlotElement ? this.assignedNodes() : []; if (distributedNodes.length) return distributedNodes[0]; @@ -668,7 +672,7 @@ if (sibling) return sibling; - node = insertionPoint(node) || node.parentNodeOrShadowHost(); + node = node.assignedSlot || node.parentNodeOrShadowHost(); } /** @@ -676,10 +680,9 @@ * @return {?Node} */ function nextSibling(node) { - const parent = insertionPoint(node); - if (!parent) + if (!node.assignedSlot) return node.nextSibling; - const distributedNodes = parent.getDistributedNodes ? parent.getDistributedNodes() : []; + const distributedNodes = node.assignedSlot.assignedNodes(); const position = Array.prototype.indexOf.call(distributedNodes, node); if (position + 1 < distributedNodes.length) @@ -687,15 +690,6 @@ return null; } - /** - * @param {!Node} node - * @return {?Node} - */ - function insertionPoint(node) { - const insertionPoints = node.getDestinationInsertionPoints ? node.getDestinationInsertionPoints() : []; - return insertionPoints.length > 0 ? insertionPoints[insertionPoints.length - 1] : null; - } - return null; };
diff --git a/third_party/blink/renderer/devtools/front_end/elements/ElementsSidebarPane.js b/third_party/blink/renderer/devtools/front_end/elements/ElementsSidebarPane.js index 5676b094..1f76f3d 100644 --- a/third_party/blink/renderer/devtools/front_end/elements/ElementsSidebarPane.js +++ b/third_party/blink/renderer/devtools/front_end/elements/ElementsSidebarPane.js
@@ -5,8 +5,11 @@ * @unrestricted */ Elements.ElementsSidebarPane = class extends UI.VBox { - constructor() { - super(true); + /** + * @param {boolean=} delegatesFocus + */ + constructor(delegatesFocus) { + super(true, delegatesFocus); this.element.classList.add('flex-none'); this._computedStyleModel = new Elements.ComputedStyleModel(); this._computedStyleModel.addEventListener(
diff --git a/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js b/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js index ee5ff65..9198aa85 100644 --- a/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js +++ b/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js
@@ -29,10 +29,9 @@ Elements.StylesSidebarPane = class extends Elements.ElementsSidebarPane { constructor() { - super(); + super(true /* delegatesFocus */); this.setMinimumSize(96, 26); this.registerRequiredCSS('elements/stylesSidebarPane.css'); - this.element.tabIndex = -1; Common.moduleSetting('colorFormat').addChangeListener(this.update.bind(this)); Common.moduleSetting('textEditorIndent').addChangeListener(this.update.bind(this)); @@ -95,7 +94,7 @@ * @return {!Element} */ static createExclamationMark(property) { - const exclamationElement = createElement('label', 'dt-icon-label'); + const exclamationElement = createElement('span', 'dt-icon-label'); exclamationElement.className = 'exclamation-mark'; if (!Elements.StylesSidebarPane.ignoreErrorsForProperty(property)) exclamationElement.type = 'smallicon-warning';
diff --git a/third_party/blink/renderer/devtools/front_end/elements/classesPaneWidget.css b/third_party/blink/renderer/devtools/front_end/elements/classesPaneWidget.css index ee810fe..01aec13 100644 --- a/third_party/blink/renderer/devtools/front_end/elements/classesPaneWidget.css +++ b/third_party/blink/renderer/devtools/front_end/elements/classesPaneWidget.css
@@ -16,7 +16,7 @@ justify-content: flex-start; } -.styles-element-classes-pane label { +.styles-element-classes-pane [is=dt-checkbox] { margin-right: 15px; }
diff --git a/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js b/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js index e77cf26..144a61b 100644 --- a/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js +++ b/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js
@@ -74,7 +74,7 @@ this._bottomResizerElement.title = Common.UIString('Double-click for full height'); this._pageArea = this._screenArea.createChild('div', 'device-mode-page-area'); - this._pageArea.createChild('content'); + this._pageArea.createChild('slot'); } _populatePresetsContainer() {
diff --git a/third_party/blink/renderer/devtools/front_end/emulation/sensors.css b/third_party/blink/renderer/devtools/front_end/emulation/sensors.css index e7177d9..acac8d9f 100644 --- a/third_party/blink/renderer/devtools/front_end/emulation/sensors.css +++ b/third_party/blink/renderer/devtools/front_end/emulation/sensors.css
@@ -9,10 +9,6 @@ display: block; } -.sensors-view label { - margin-bottom: 10px; -} - .sensors-view input { width: 100%; max-width: 100px;
diff --git a/third_party/blink/renderer/devtools/front_end/inline_editor/CSSShadowEditor.js b/third_party/blink/renderer/devtools/front_end/inline_editor/CSSShadowEditor.js index 5bf765f..07ef71f 100644 --- a/third_party/blink/renderer/devtools/front_end/inline_editor/CSSShadowEditor.js +++ b/third_party/blink/renderer/devtools/front_end/inline_editor/CSSShadowEditor.js
@@ -68,7 +68,7 @@ * @return {!Element} */ _createSlider(field) { - const slider = UI.createSliderLabel(0, InlineEditor.CSSShadowEditor.maxRange, -1); + const slider = UI.createSlider(0, InlineEditor.CSSShadowEditor.maxRange, -1); slider.addEventListener('input', this._onSliderInput.bind(this), false); field.appendChild(slider); return slider;
diff --git a/third_party/blink/renderer/devtools/front_end/inline_editor/ColorSwatch.js b/third_party/blink/renderer/devtools/front_end/inline_editor/ColorSwatch.js index 5f5eb0bc..2dfc68ab 100644 --- a/third_party/blink/renderer/devtools/front_end/inline_editor/ColorSwatch.js +++ b/third_party/blink/renderer/devtools/front_end/inline_editor/ColorSwatch.js
@@ -7,6 +7,17 @@ InlineEditor.ColorSwatch = class extends HTMLSpanElement { constructor() { super(); + const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/colorSwatch.css'); + + this._iconElement = root.createChild('span', 'color-swatch'); + this._iconElement.title = Common.UIString('Shift-click to change color format'); + this._swatchInner = this._iconElement.createChild('span', 'color-swatch-inner'); + this._swatchInner.addEventListener('dblclick', e => e.consume(), false); + this._swatchInner.addEventListener('mousedown', e => e.consume(), false); + this._swatchInner.addEventListener('click', this._handleClick.bind(this), true); + + root.createChild('slot'); + this._colorValueElement = this.createChild('span'); } /** @@ -15,11 +26,11 @@ static create() { if (!InlineEditor.ColorSwatch._constructor) { InlineEditor.ColorSwatch._constructor = - UI.registerCustomElement('span', 'color-swatch', InlineEditor.ColorSwatch.prototype); + UI.registerCustomElement('span', 'color-swatch', InlineEditor.ColorSwatch); } - return /** @type {!InlineEditor.ColorSwatch} */ (new InlineEditor.ColorSwatch._constructor()); + return /** @type {!InlineEditor.ColorSwatch} */ (InlineEditor.ColorSwatch._constructor()); } /** @@ -134,23 +145,6 @@ } /** - * @override - */ - createdCallback() { - const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/colorSwatch.css'); - - this._iconElement = root.createChild('span', 'color-swatch'); - this._iconElement.title = Common.UIString('Shift-click to change color format'); - this._swatchInner = this._iconElement.createChild('span', 'color-swatch-inner'); - this._swatchInner.addEventListener('dblclick', e => e.consume(), false); - this._swatchInner.addEventListener('mousedown', e => e.consume(), false); - this._swatchInner.addEventListener('click', this._handleClick.bind(this), true); - - root.createChild('content'); - this._colorValueElement = this.createChild('span'); - } - - /** * @param {!Event} event */ _handleClick(event) { @@ -168,6 +162,11 @@ InlineEditor.BezierSwatch = class extends HTMLSpanElement { constructor() { super(); + const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/bezierSwatch.css'); + this._iconElement = UI.Icon.create('smallicon-bezier', 'bezier-swatch-icon'); + root.appendChild(this._iconElement); + this._textElement = this.createChild('span'); + root.createChild('slot'); } /** @@ -176,11 +175,11 @@ static create() { if (!InlineEditor.BezierSwatch._constructor) { InlineEditor.BezierSwatch._constructor = - UI.registerCustomElement('span', 'bezier-swatch', InlineEditor.BezierSwatch.prototype); + UI.registerCustomElement('span', 'bezier-swatch', InlineEditor.BezierSwatch); } - return /** @type {!InlineEditor.BezierSwatch} */ (new InlineEditor.BezierSwatch._constructor()); + return /** @type {!InlineEditor.BezierSwatch} */ (InlineEditor.BezierSwatch._constructor()); } /** @@ -210,17 +209,6 @@ iconElement() { return this._iconElement; } - - /** - * @override - */ - createdCallback() { - const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/bezierSwatch.css'); - this._iconElement = UI.Icon.create('smallicon-bezier', 'bezier-swatch-icon'); - root.appendChild(this._iconElement); - this._textElement = this.createChild('span'); - root.createChild('content'); - } }; /** @@ -229,6 +217,11 @@ InlineEditor.CSSShadowSwatch = class extends HTMLSpanElement { constructor() { super(); + const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/cssShadowSwatch.css'); + this._iconElement = UI.Icon.create('smallicon-shadow', 'shadow-swatch-icon'); + root.appendChild(this._iconElement); + root.createChild('slot'); + this._contentElement = this.createChild('span'); } /** @@ -237,10 +230,10 @@ static create() { if (!InlineEditor.CSSShadowSwatch._constructor) { InlineEditor.CSSShadowSwatch._constructor = - UI.registerCustomElement('span', 'css-shadow-swatch', InlineEditor.CSSShadowSwatch.prototype); + UI.registerCustomElement('span', 'css-shadow-swatch', InlineEditor.CSSShadowSwatch); } - return /** @type {!InlineEditor.CSSShadowSwatch} */ (new InlineEditor.CSSShadowSwatch._constructor()); + return /** @type {!InlineEditor.CSSShadowSwatch} */ (InlineEditor.CSSShadowSwatch._constructor()); } /** @@ -290,15 +283,4 @@ colorSwatch() { return this._colorSwatch; } - - /** - * @override - */ - createdCallback() { - const root = UI.createShadowRootWithCoreStyles(this, 'inline_editor/cssShadowSwatch.css'); - this._iconElement = UI.Icon.create('smallicon-shadow', 'shadow-swatch-icon'); - root.appendChild(this._iconElement); - root.createChild('content'); - this._contentElement = this.createChild('span'); - } };
diff --git a/third_party/blink/renderer/devtools/front_end/inspector_main/renderingOptions.css b/third_party/blink/renderer/devtools/front_end/inspector_main/renderingOptions.css index 77eeb51..b478b44 100644 --- a/third_party/blink/renderer/devtools/front_end/inspector_main/renderingOptions.css +++ b/third_party/blink/renderer/devtools/front_end/inspector_main/renderingOptions.css
@@ -8,7 +8,7 @@ padding: 12px; } -label { +[is=dt-checkbox] { margin: 0px 0px 10px 0px; flex: none; }
diff --git a/third_party/blink/renderer/devtools/front_end/layers_test_runner/LayersTestRunner.js b/third_party/blink/renderer/devtools/front_end/layers_test_runner/LayersTestRunner.js index d5c69d7..20e51c3d 100644 --- a/third_party/blink/renderer/devtools/front_end/layers_test_runner/LayersTestRunner.js +++ b/third_party/blink/renderer/devtools/front_end/layers_test_runner/LayersTestRunner.js
@@ -106,7 +106,8 @@ screenY: totalOffset.top - element.scrollTop + offsetY, clientX: totalOffset.left + offsetX, clientY: totalOffset.top + offsetY, - button: button + button: button, + composed: true }; if (eventType === 'mouseout') {
diff --git a/third_party/blink/renderer/devtools/front_end/network/RequestHeadersView.js b/third_party/blink/renderer/devtools/front_end/network/RequestHeadersView.js index b69345c7..03f76686 100644 --- a/third_party/blink/renderer/devtools/front_end/network/RequestHeadersView.js +++ b/third_party/blink/renderer/devtools/front_end/network/RequestHeadersView.js
@@ -379,7 +379,7 @@ statusCodeFragment.createChild('div', 'header-name').textContent = Common.UIString('Status Code') + ': '; statusCodeFragment.createChild('span', 'header-separator'); - const statusCodeImage = statusCodeFragment.createChild('label', 'resource-status-image', 'dt-icon-label'); + const statusCodeImage = statusCodeFragment.createChild('span', 'resource-status-image', 'dt-icon-label'); statusCodeImage.title = this._request.statusCode + ' ' + this._request.statusText; if (this._request.statusCode < 300 || this._request.statusCode === 304) @@ -442,7 +442,7 @@ if (provisionalHeaders) { const cautionText = Common.UIString('Provisional headers are shown'); const cautionFragment = createDocumentFragment(); - cautionFragment.createChild('label', '', 'dt-icon-label').type = 'smallicon-warning'; + cautionFragment.createChild('span', '', 'dt-icon-label').type = 'smallicon-warning'; cautionFragment.createChild('div', 'caution').textContent = cautionText; const cautionTreeElement = new UI.TreeElement(cautionFragment); cautionTreeElement.selectable = false;
diff --git a/third_party/blink/renderer/devtools/front_end/network/SignedExchangeInfoView.js b/third_party/blink/renderer/devtools/front_end/network/SignedExchangeInfoView.js index 9de4834..dfd8daef 100644 --- a/third_party/blink/renderer/devtools/front_end/network/SignedExchangeInfoView.js +++ b/third_party/blink/renderer/devtools/front_end/network/SignedExchangeInfoView.js
@@ -59,7 +59,6 @@ requestURLElement.appendChild(viewRequestLink); } headerCategory.createLeaf(requestURLElement); - headerCategory.createLeaf(this._formatHeader(Common.UIString('Request method'), header.requestMethod)); headerCategory.createLeaf(this._formatHeader(Common.UIString('Response code'), header.responseCode + '')); this._responseHeadersItem =
diff --git a/third_party/blink/renderer/devtools/front_end/network/networkConfigView.css b/third_party/blink/renderer/devtools/front_end/network/networkConfigView.css index 6c5ede0d..df86aa2 100644 --- a/third_party/blink/renderer/devtools/front_end/network/networkConfigView.css +++ b/third_party/blink/renderer/devtools/front_end/network/networkConfigView.css
@@ -57,11 +57,11 @@ line-height: 20px; } -.network-config-ua label[is="dt-radio"].checked > * { +.network-config-ua span[is="dt-radio"].checked > * { display: none } -.network-config-ua input:not(.dt-radio-button) { +.network-config-ua input { display: block; width: calc(100% - 20px); } @@ -79,7 +79,7 @@ max-width: 250px; } -.network-config-ua label[is="dt-radio"] { +.network-config-ua span[is="dt-radio"] { display: block; }
diff --git a/third_party/blink/renderer/devtools/front_end/network/networkLogView.css b/third_party/blink/renderer/devtools/front_end/network/networkLogView.css index 2a1d831..eaeb07a4 100644 --- a/third_party/blink/renderer/devtools/front_end/network/networkLogView.css +++ b/third_party/blink/renderer/devtools/front_end/network/networkLogView.css
@@ -44,7 +44,7 @@ overflow: hidden; } -.network-summary-bar label[is=dt-icon-label] { +.network-summary-bar span[is=dt-icon-label] { margin-right: 6px; }
diff --git a/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js b/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js index 37c4edb..0f5acb8 100644 --- a/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js +++ b/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js
@@ -432,7 +432,7 @@ * @param {!Array.<!SDK.RemoteObjectProperty>=} extraProperties */ constructor(object, linkifier, emptyPlaceholder, ignoreHasOwnProperty, extraProperties) { - const contentElement = createElement('content'); + const contentElement = createElement('slot'); super(contentElement); this._object = object;
diff --git a/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css b/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css index c6bf2e4..89892c7 100644 --- a/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css +++ b/third_party/blink/renderer/devtools/front_end/object_ui/objectPropertiesSection.css
@@ -70,7 +70,7 @@ background: none; } -.tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] ::content > *, +.tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] ::slotted(*), .tree-outline.hide-selection-when-blurred .selected:focus[data-keyboard-focus="true"] .name-and-value { background: var(--focus-bg-color); border-radius: 2px;
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/profilesPanel.css b/third_party/blink/renderer/devtools/front_end/profiler/profilesPanel.css index a44bd156..4849d7b 100644 --- a/third_party/blink/renderer/devtools/front_end/profiler/profilesPanel.css +++ b/third_party/blink/renderer/devtools/front_end/profiler/profilesPanel.css
@@ -128,7 +128,7 @@ margin: 0 0 5px 0; } -.profile-launcher-view-content label { +.profile-launcher-view-content [is=dt-radio] { font-size: 13px; } @@ -165,7 +165,7 @@ margin-left: 22px; } -.profile-launcher-view-content p label { +.profile-launcher-view-content p [is=dt-checkbox] { display: flex; } @@ -190,7 +190,7 @@ to { background-color: rgba(255, 255, 120, 0); } } -.profile-canvas-decoration label[is=dt-icon-label] { +.profile-canvas-decoration span[is=dt-icon-label] { margin-right: 4px; }
diff --git a/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheItemsView.js b/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheItemsView.js index 9bee1db..f83a6b6 100644 --- a/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheItemsView.js +++ b/third_party/blink/renderer/devtools/front_end/resources/ApplicationCacheItemsView.js
@@ -38,9 +38,9 @@ this._deleteButton.setVisible(false); this._deleteButton.addEventListener(UI.ToolbarButton.Events.Click, this._deleteButtonClicked, this); - this._connectivityIcon = createElement('label', 'dt-icon-label'); + this._connectivityIcon = createElement('span', 'dt-icon-label'); this._connectivityIcon.style.margin = '0 2px 0 5px'; - this._statusIcon = createElement('label', 'dt-icon-label'); + this._statusIcon = createElement('span', 'dt-icon-label'); this._statusIcon.style.margin = '0 2px 0 5px'; this._frameId = frameId;
diff --git a/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js b/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js index 7318c75..7306cf3 100644 --- a/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js +++ b/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js
@@ -79,7 +79,7 @@ return text; } - const highlightedUrl = createElement('span', 'url-text'); + const highlightedUrl = createElement('span'); const scheme = url.substr(0, index); const content = url.substr(index + schemeSeparator.length);
diff --git a/third_party/blink/renderer/devtools/front_end/settings/settingsScreen.css b/third_party/blink/renderer/devtools/front_end/settings/settingsScreen.css index 47c80a7..9989041 100644 --- a/third_party/blink/renderer/devtools/front_end/settings/settingsScreen.css +++ b/third_party/blink/renderer/devtools/front_end/settings/settingsScreen.css
@@ -211,15 +211,11 @@ margin-left: 10px; } -.settings-indent-labels label { - padding-left: 10px; -} - .settings-experiment-hidden { display: none; } -.settings-experiment-hidden label { +.settings-experiment-hidden [is=dt-checkbox] { background-color: #ddd; }
diff --git a/third_party/blink/renderer/devtools/front_end/sources/UISourceCodeFrame.js b/third_party/blink/renderer/devtools/front_end/sources/UISourceCodeFrame.js index 47cb6bc73..0801439 100644 --- a/third_party/blink/renderer/devtools/front_end/sources/UISourceCodeFrame.js +++ b/third_party/blink/renderer/devtools/front_end/sources/UISourceCodeFrame.js
@@ -584,7 +584,7 @@ this._icon = this.element.createChild('label', '', 'dt-icon-label'); this._icon.type = Sources.UISourceCodeFrame._iconClassPerLevel[message.level()]; this._repeatCountElement = - this.element.createChild('label', 'text-editor-row-message-repeat-count hidden', 'dt-small-bubble'); + this.element.createChild('span', 'text-editor-row-message-repeat-count hidden', 'dt-small-bubble'); this._repeatCountElement.type = Sources.UISourceCodeFrame._bubbleTypePerLevel[message.level()]; const linesContainer = this.element.createChild('div'); const lines = this._message.text().split('\n'); @@ -636,7 +636,7 @@ this._decoration = createElementWithClass('div', 'text-editor-line-decoration'); this._decoration._messageBucket = this; this._wave = this._decoration.createChild('div', 'text-editor-line-decoration-wave'); - this._icon = this._wave.createChild('label', 'text-editor-line-decoration-icon', 'dt-icon-label'); + this._icon = this._wave.createChild('span', 'text-editor-line-decoration-icon', 'dt-icon-label'); /** @type {?number} */ this._decorationStartColumn = null;
diff --git a/third_party/blink/renderer/devtools/front_end/sources/sourcesPanel.css b/third_party/blink/renderer/devtools/front_end/sources/sourcesPanel.css index 4b49787..17d4d4a 100644 --- a/third_party/blink/renderer/devtools/front_end/sources/sourcesPanel.css +++ b/third_party/blink/renderer/devtools/front_end/sources/sourcesPanel.css
@@ -50,7 +50,7 @@ margin-top: 0; } -.scripts-debug-toolbar-drawer > label { +.scripts-debug-toolbar-drawer > [is=dt-checkbox] { display: flex; padding-left: 3px; height: 28px;
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/TimelineHistoryManager.js b/third_party/blink/renderer/devtools/front_end/timeline/TimelineHistoryManager.js index 7bd3fc0..ecd5308 100644 --- a/third_party/blink/renderer/devtools/front_end/timeline/TimelineHistoryManager.js +++ b/third_party/blink/renderer/devtools/front_end/timeline/TimelineHistoryManager.js
@@ -426,12 +426,11 @@ * @param {!UI.Action} action */ constructor(action) { - super(createElementWithClass('button', 'dropdown-button')); - const shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'timeline/historyToolbarButton.css'); - - this._contentElement = shadowRoot.createChild('span', 'content'); + super(createElementWithClass('button', 'history-dropdown-button')); + UI.appendStyle(this.element, 'timeline/historyToolbarButton.css'); + this._contentElement = this.element.createChild('span', 'content'); const dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down'); - shadowRoot.appendChild(dropdownArrowIcon); + this.element.appendChild(dropdownArrowIcon); this.element.addEventListener('click', () => void action.execute(), false); this.setEnabled(action.enabled()); action.addEventListener(UI.Action.Events.Enabled, event => this.setEnabled(/** @type {boolean} */ (event.data)));
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/historyToolbarButton.css b/third_party/blink/renderer/devtools/front_end/timeline/historyToolbarButton.css index f66188b..0259abf 100644 --- a/third_party/blink/renderer/devtools/front_end/timeline/historyToolbarButton.css +++ b/third_party/blink/renderer/devtools/front_end/timeline/historyToolbarButton.css
@@ -4,18 +4,18 @@ * found in the LICENSE file. */ -:host { +.history-dropdown-button { width: 160px; height: 26px; text-align: left; display: flex; } -:host([disabled]) { +.history-dropdown-button[disabled] { opacity: .5; } -.content { +.history-dropdown-button > .content { padding-right: 5px; overflow: hidden; text-overflow: ellipsis;
diff --git a/third_party/blink/renderer/devtools/front_end/ui/HistoryInput.js b/third_party/blink/renderer/devtools/front_end/ui/HistoryInput.js index b5cefa74..81784fc 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/HistoryInput.js +++ b/third_party/blink/renderer/devtools/front_end/ui/HistoryInput.js
@@ -5,24 +5,21 @@ * @unrestricted */ UI.HistoryInput = class extends HTMLInputElement { + constructor() { + super(); + this._history = ['']; + this._historyPosition = 0; + this.addEventListener('keydown', this._onKeyDown.bind(this), false); + this.addEventListener('input', this._onInput.bind(this), false); + } /** * @return {!UI.HistoryInput} */ static create() { if (!UI.HistoryInput._constructor) - UI.HistoryInput._constructor = UI.registerCustomElement('input', 'history-input', UI.HistoryInput.prototype); + UI.HistoryInput._constructor = UI.registerCustomElement('input', 'history-input', UI.HistoryInput); - return /** @type {!UI.HistoryInput} */ (new UI.HistoryInput._constructor()); - } - - /** - * @override - */ - createdCallback() { - this._history = ['']; - this._historyPosition = 0; - this.addEventListener('keydown', this._onKeyDown.bind(this), false); - this.addEventListener('input', this._onInput.bind(this), false); + return /** @type {!UI.HistoryInput} */ (UI.HistoryInput._constructor()); } /**
diff --git a/third_party/blink/renderer/devtools/front_end/ui/Icon.js b/third_party/blink/renderer/devtools/front_end/ui/Icon.js index 11b6d98..9d1fd5e 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/Icon.js +++ b/third_party/blink/renderer/devtools/front_end/ui/Icon.js
@@ -2,14 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/** - * @constructor - * @extends {HTMLSpanElement} - */ UI.Icon = class extends HTMLSpanElement { constructor() { super(); - throw new Error('icon must be created via factory method.'); + /** @type {?UI.Icon.Descriptor} */ + this._descriptor = null; + /** @type {?UI.Icon.SpriteSheet} */ + this._spriteSheet = null; + /** @type {string} */ + this._iconType = ''; } /** @@ -19,9 +20,9 @@ */ static create(iconType, className) { if (!UI.Icon._constructor) - UI.Icon._constructor = UI.registerCustomElement('span', 'ui-icon', UI.Icon.prototype); + UI.Icon._constructor = UI.registerCustomElement('span', 'ui-icon', UI.Icon); - const icon = /** @type {!UI.Icon} */ (new UI.Icon._constructor()); + const icon = /** @type {!UI.Icon} */ (UI.Icon._constructor()); if (className) icon.className = className; if (iconType) @@ -30,18 +31,6 @@ } /** - * @override - */ - createdCallback() { - /** @type {?UI.Icon.Descriptor} */ - this._descriptor = null; - /** @type {?UI.Icon.SpriteSheet} */ - this._spriteSheet = null; - /** @type {string} */ - this._iconType = ''; - } - - /** * @param {string} iconType */ setIconType(iconType) {
diff --git a/third_party/blink/renderer/devtools/front_end/ui/ListWidget.js b/third_party/blink/renderer/devtools/front_end/ui/ListWidget.js index c11ae3a..0ba4777 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/ListWidget.js +++ b/third_party/blink/renderer/devtools/front_end/ui/ListWidget.js
@@ -9,12 +9,11 @@ * @param {!UI.ListWidget.Delegate<T>} delegate */ constructor(delegate) { - super(true); + super(true, true /* delegatesFocus */); this.registerRequiredCSS('ui/listWidget.css'); this._delegate = delegate; this._list = this.contentElement.createChild('div', 'list'); - this.element.tabIndex = -1; this._lastSeparator = false; /** @type {?UI.ElementFocusRestorer} */
diff --git a/third_party/blink/renderer/devtools/front_end/ui/SearchableView.js b/third_party/blink/renderer/devtools/front_end/ui/SearchableView.js index a0fa78f..f03af0f 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/SearchableView.js +++ b/third_party/blink/renderer/devtools/front_end/ui/SearchableView.js
@@ -46,7 +46,7 @@ this._setting = settingName ? Common.settings.createSetting(settingName, {}) : null; this._replaceable = false; - this.contentElement.createChild('content'); + this.contentElement.createChild('slot'); this._footerElementContainer = this.contentElement.createChild('div', 'search-bar hidden'); this._footerElementContainer.style.order = 100; this._footerElement = this._footerElementContainer.createChild('div', 'toolbar-search');
diff --git a/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js b/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js index 88e8e97f..6d21c347 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js +++ b/third_party/blink/renderer/devtools/front_end/ui/SoftDropDown.js
@@ -16,10 +16,10 @@ this._model = model; this.element = createElementWithClass('button', 'soft-dropdown'); - const shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/softDropDownButton.css'); - this._titleElement = shadowRoot.createChild('span', 'title'); + UI.appendStyle(this.element, 'ui/softDropDownButton.css'); + this._titleElement = this.element.createChild('span', 'title'); const dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down'); - shadowRoot.appendChild(dropdownArrowIcon); + this.element.appendChild(dropdownArrowIcon); this._glassPane = new UI.GlassPane(); this._glassPane.setMarginBehavior(UI.GlassPane.MarginBehavior.NoMargin);
diff --git a/third_party/blink/renderer/devtools/front_end/ui/SplitWidget.js b/third_party/blink/renderer/devtools/front_end/ui/SplitWidget.js index f0b55ed6..950b230 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/SplitWidget.js +++ b/third_party/blink/renderer/devtools/front_end/ui/SplitWidget.js
@@ -46,10 +46,10 @@ this.contentElement.classList.add('shadow-split-widget'); this._mainElement = this.contentElement.createChild('div', 'shadow-split-widget-contents shadow-split-widget-main vbox'); - this._mainElement.createChild('content').select = '.insertion-point-main'; + this._mainElement.createChild('slot').name = 'insertion-point-main'; this._sidebarElement = this.contentElement.createChild('div', 'shadow-split-widget-contents shadow-split-widget-sidebar vbox'); - this._sidebarElement.createChild('content').select = '.insertion-point-sidebar'; + this._sidebarElement.createChild('slot').name = 'insertion-point-sidebar'; this._resizerElement = this.contentElement.createChild('div', 'shadow-split-widget-resizer'); this._resizerElementSize = null; @@ -165,8 +165,7 @@ this._mainWidget.detach(); this._mainWidget = widget; if (widget) { - widget.element.classList.add('insertion-point-main'); - widget.element.classList.remove('insertion-point-sidebar'); + widget.element.slot = 'insertion-point-main'; if (this._showMode === UI.SplitWidget.ShowMode.OnlyMain || this._showMode === UI.SplitWidget.ShowMode.Both) widget.show(this.element); } @@ -184,8 +183,7 @@ this._sidebarWidget.detach(); this._sidebarWidget = widget; if (widget) { - widget.element.classList.add('insertion-point-sidebar'); - widget.element.classList.remove('insertion-point-main'); + widget.element.slot = 'insertion-point-sidebar'; if (this._showMode === UI.SplitWidget.ShowMode.OnlySidebar || this._showMode === UI.SplitWidget.ShowMode.Both) widget.show(this.element); }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/TabbedPane.js b/third_party/blink/renderer/devtools/front_end/ui/TabbedPane.js index 3a64985..f51f82d6 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/TabbedPane.js +++ b/third_party/blink/renderer/devtools/front_end/ui/TabbedPane.js
@@ -46,7 +46,7 @@ this._tabsElement.addEventListener('keydown', this._keyDown.bind(this), false); this._contentElement = this.contentElement.createChild('div', 'tabbed-pane-content'); this._contentElement.setAttribute('role', 'tabpanel'); - this._contentElement.createChild('content'); + this._contentElement.createChild('slot'); /** @type {!Array.<!UI.TabbedPaneTab>} */ this._tabs = []; /** @type {!Array.<!UI.TabbedPaneTab>} */
diff --git a/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js b/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js index bd54790..3495310 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js +++ b/third_party/blink/renderer/devtools/front_end/ui/Toolbar.js
@@ -45,7 +45,7 @@ this._enabled = true; this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/toolbar.css'); this._contentElement = this._shadowRoot.createChild('div', 'toolbar-shadow'); - this._insertionPoint = this._contentElement.createChild('content'); + this._insertionPoint = this._contentElement.createChild('slot'); } /** @@ -277,7 +277,7 @@ delete item._toolbar; this._items = []; this._contentElement.removeChildren(); - this._insertionPoint = this._contentElement.createChild('content'); + this._insertionPoint = this._contentElement.createChild('slot'); } /**
diff --git a/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js b/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js index a8034a0..253f22f 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js +++ b/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js
@@ -54,7 +54,7 @@ */ _mouseMove(event) { const mouseEvent = /** @type {!MouseEvent} */ (event); - const path = mouseEvent.path; + const path = mouseEvent.composedPath(); if (!path || mouseEvent.buttons !== 0 || (mouseEvent.movementX === 0 && mouseEvent.movementY === 0)) return; @@ -63,7 +63,8 @@ for (const element of path) { // The offsetParent is null when the element or an ancestor has 'display: none'. - if (element === this._anchorElement || (element.nodeName !== 'CONTENT' && element.offsetParent === null)) { + if (!(element instanceof Element) || element === this._anchorElement || + (element.nodeName !== 'SLOT' && element.offsetParent === null)) { return; } else if (element[UI.Tooltip._symbol]) { this._show(element, mouseEvent);
diff --git a/third_party/blink/renderer/devtools/front_end/ui/UIUtils.js b/third_party/blink/renderer/devtools/front_end/ui/UIUtils.js index 45d2074..9820f1e 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/UIUtils.js +++ b/third_party/blink/renderer/devtools/front_end/ui/UIUtils.js
@@ -702,10 +702,11 @@ /** * @param {!Element} element * @param {string=} cssFile + * @param {boolean=} delegatesFocus * @return {!DocumentFragment} */ -UI.createShadowRootWithCoreStyles = function(element, cssFile) { - const shadowRoot = element.createShadowRoot(); +UI.createShadowRootWithCoreStyles = function(element, cssFile, delegatesFocus) { + const shadowRoot = element.attachShadow({mode: 'open', delegatesFocus}); UI._injectCoreStyles(shadowRoot); if (cssFile) UI.appendStyle(shadowRoot, cssFile); @@ -1172,13 +1173,19 @@ /** * @param {string} localName * @param {string} typeExtension - * @param {!Object} prototype + * @param {function(new:HTMLElement, *)} definition * @return {function()} * @suppressGlobalPropertiesCheck - * @template T */ -UI.registerCustomElement = function(localName, typeExtension, prototype) { - return document.registerElement(typeExtension, {prototype: Object.create(prototype), extends: localName}); +UI.registerCustomElement = function(localName, typeExtension, definition) { + self.customElements.define(typeExtension, class extends definition { + constructor() { + super(); + // TODO(einbinder) convert to classes and custom element tags + this.setAttribute('is', typeExtension); + } + }, {extends: localName}); + return () => createElement(localName, typeExtension); }; /** @@ -1221,10 +1228,10 @@ * @return {!Element} */ UI.createRadioLabel = function(name, title, checked) { - const element = createElement('label', 'dt-radio'); + const element = createElement('span', 'dt-radio'); element.radioElement.name = name; element.radioElement.checked = !!checked; - element.createTextChild(title); + element.labelElement.createTextChild(title); return element; }; @@ -1234,7 +1241,7 @@ * @return {!Element} */ UI.createLabel = function(title, iconClass) { - const element = createElement('label', 'dt-icon-label'); + const element = createElement('span', 'dt-icon-label'); element.createChild('span').textContent = title; element.type = iconClass; return element; @@ -1246,8 +1253,8 @@ * @param {number} max * @param {number} tabIndex */ -UI.createSliderLabel = function(min, max, tabIndex) { - const element = createElement('label', 'dt-slider'); +UI.createSlider = function(min, max, tabIndex) { + const element = createElement('span', 'dt-slider'); element.sliderElement.min = min; element.sliderElement.max = max; element.sliderElement.step = 1; @@ -1278,10 +1285,7 @@ } }; -/** - * @extends {HTMLLabelElement} - */ -UI.CheckboxLabel = class extends HTMLLabelElement { +UI.CheckboxLabel = class extends HTMLSpanElement { constructor() { super(); /** @type {!DocumentFragment} */ @@ -1290,13 +1294,6 @@ this.checkboxElement; /** @type {!Element} */ this.textElement; - throw new Error('Checkbox must be created via factory method.'); - } - - /** - * @override - */ - createdCallback() { UI.CheckboxLabel._lastId = (UI.CheckboxLabel._lastId || 0) + 1; const id = 'ui-checkbox-label' + UI.CheckboxLabel._lastId; this._shadowRoot = UI.createShadowRootWithCoreStyles(this, 'ui/checkboxTextLabel.css'); @@ -1305,7 +1302,7 @@ this.checkboxElement.setAttribute('id', id); this.textElement = this._shadowRoot.createChild('label', 'dt-checkbox-text'); this.textElement.setAttribute('for', id); - this._shadowRoot.createChild('content'); + this._shadowRoot.createChild('slot'); } /** @@ -1316,8 +1313,8 @@ */ static create(title, checked, subtitle) { if (!UI.CheckboxLabel._constructor) - UI.CheckboxLabel._constructor = UI.registerCustomElement('label', 'dt-checkbox', UI.CheckboxLabel.prototype); - const element = /** @type {!UI.CheckboxLabel} */ (new UI.CheckboxLabel._constructor()); + UI.CheckboxLabel._constructor = UI.registerCustomElement('span', 'dt-checkbox', UI.CheckboxLabel); + const element = /** @type {!UI.CheckboxLabel} */ (UI.CheckboxLabel._constructor()); element.checkboxElement.checked = !!checked; if (title !== undefined) { element.textElement.textContent = title; @@ -1358,139 +1355,124 @@ }; (function() { - UI.registerCustomElement('label', 'dt-radio', { - /** - * @this {Element} - */ - createdCallback: function() { - this.radioElement = this.createChild('input', 'dt-radio-button'); - this.radioElement.type = 'radio'; - const root = UI.createShadowRootWithCoreStyles(this, 'ui/radioButton.css'); - root.createChild('content').select = '.dt-radio-button'; - root.createChild('content'); - this.addEventListener('click', radioClickHandler, false); - }, +let labelId = 0; +UI.registerCustomElement('span', 'dt-radio', class extends HTMLSpanElement { + constructor() { + super(); + this.radioElement = this.createChild('input', 'dt-radio-button'); + this.labelElement = this.createChild('label'); - __proto__: HTMLLabelElement.prototype - }); + const id = 'dt-radio-button-id' + (++labelId); + this.radioElement.id = id; + this.radioElement.type = 'radio'; + this.labelElement.htmlFor = id; + const root = UI.createShadowRootWithCoreStyles(this, 'ui/radioButton.css'); + root.createChild('slot'); + this.addEventListener('click', radioClickHandler, false); + } +}); - /** +/** * @param {!Event} event * @suppressReceiverCheck * @this {Element} */ - function radioClickHandler(event) { - if (this.radioElement.checked || this.radioElement.disabled) - return; - this.radioElement.checked = true; - this.radioElement.dispatchEvent(new Event('change')); +function radioClickHandler(event) { + if (this.radioElement.checked || this.radioElement.disabled) + return; + this.radioElement.checked = true; + this.radioElement.dispatchEvent(new Event('change')); +} + +UI.registerCustomElement('span', 'dt-icon-label', class extends HTMLSpanElement { + constructor() { + super(); + const root = UI.createShadowRootWithCoreStyles(this); + this._iconElement = UI.Icon.create(); + this._iconElement.style.setProperty('margin-right', '4px'); + root.appendChild(this._iconElement); + root.createChild('slot'); } - UI.registerCustomElement('label', 'dt-icon-label', { - /** - * @this {Element} - */ - createdCallback: function() { - const root = UI.createShadowRootWithCoreStyles(this); - this._iconElement = UI.Icon.create(); - this._iconElement.style.setProperty('margin-right', '4px'); - root.appendChild(this._iconElement); - root.createChild('content'); - }, - - /** + /** * @param {string} type * @this {Element} */ - set type(type) { - this._iconElement.setIconType(type); - }, + set type(type) { + this._iconElement.setIconType(type); + } +}); - __proto__: HTMLLabelElement.prototype - }); +UI.registerCustomElement('span', 'dt-slider', class extends HTMLSpanElement { + constructor() { + super(); + const root = UI.createShadowRootWithCoreStyles(this, 'ui/slider.css'); + this.sliderElement = createElementWithClass('input', 'dt-range-input'); + this.sliderElement.type = 'range'; + root.appendChild(this.sliderElement); + } - UI.registerCustomElement('label', 'dt-slider', { - /** - * @this {Element} - */ - createdCallback: function() { - const root = UI.createShadowRootWithCoreStyles(this, 'ui/slider.css'); - this.sliderElement = createElementWithClass('input', 'dt-range-input'); - this.sliderElement.type = 'range'; - root.appendChild(this.sliderElement); - }, - - /** + /** * @param {number} amount * @this {Element} */ - set value(amount) { - this.sliderElement.value = amount; - }, + set value(amount) { + this.sliderElement.value = amount; + } - /** + /** * @this {Element} */ - get value() { - return this.sliderElement.value; - }, + get value() { + return this.sliderElement.value; + } +}); - __proto__: HTMLLabelElement.prototype - }); +UI.registerCustomElement('span', 'dt-small-bubble', class extends HTMLSpanElement { + constructor() { + super(); + const root = UI.createShadowRootWithCoreStyles(this, 'ui/smallBubble.css'); + this._textElement = root.createChild('div'); + this._textElement.className = 'info'; + this._textElement.createChild('slot'); + } - UI.registerCustomElement('label', 'dt-small-bubble', { - /** - * @this {Element} - */ - createdCallback: function() { - const root = UI.createShadowRootWithCoreStyles(this, 'ui/smallBubble.css'); - this._textElement = root.createChild('div'); - this._textElement.className = 'info'; - this._textElement.createChild('content'); - }, - - /** + /** * @param {string} type * @this {Element} */ - set type(type) { - this._textElement.className = type; - }, + set type(type) { + this._textElement.className = type; + } +}); - __proto__: HTMLLabelElement.prototype - }); +UI.registerCustomElement('div', 'dt-close-button', class extends HTMLDivElement { + constructor() { + super(); + const root = UI.createShadowRootWithCoreStyles(this, 'ui/closeButton.css'); + this._buttonElement = root.createChild('div', 'close-button'); + const regularIcon = UI.Icon.create('smallicon-cross', 'default-icon'); + this._hoverIcon = UI.Icon.create('mediumicon-red-cross-hover', 'hover-icon'); + this._activeIcon = UI.Icon.create('mediumicon-red-cross-active', 'active-icon'); + this._buttonElement.appendChild(regularIcon); + this._buttonElement.appendChild(this._hoverIcon); + this._buttonElement.appendChild(this._activeIcon); + } - UI.registerCustomElement('div', 'dt-close-button', { - /** - * @this {Element} - */ - createdCallback: function() { - const root = UI.createShadowRootWithCoreStyles(this, 'ui/closeButton.css'); - this._buttonElement = root.createChild('div', 'close-button'); - const regularIcon = UI.Icon.create('smallicon-cross', 'default-icon'); - this._hoverIcon = UI.Icon.create('mediumicon-red-cross-hover', 'hover-icon'); - this._activeIcon = UI.Icon.create('mediumicon-red-cross-active', 'active-icon'); - this._buttonElement.appendChild(regularIcon); - this._buttonElement.appendChild(this._hoverIcon); - this._buttonElement.appendChild(this._activeIcon); - }, - - /** + /** * @param {boolean} gray * @this {Element} */ - set gray(gray) { - if (gray) { - this._hoverIcon.setIconType('mediumicon-gray-cross-hover'); - this._activeIcon.setIconType('mediumicon-gray-cross-active'); - } else { - this._hoverIcon.setIconType('mediumicon-red-cross-hover'); - this._activeIcon.setIconType('mediumicon-red-cross-active'); - } - }, - - __proto__: HTMLDivElement.prototype - }); + set gray(gray) { + if (gray) { + this._hoverIcon.setIconType('mediumicon-gray-cross-hover'); + this._activeIcon.setIconType('mediumicon-gray-cross-active'); + } else { + this._hoverIcon.setIconType('mediumicon-red-cross-hover'); + this._activeIcon.setIconType('mediumicon-red-cross-active'); + } + } +}); })(); /**
diff --git a/third_party/blink/renderer/devtools/front_end/ui/View.js b/third_party/blink/renderer/devtools/front_end/ui/View.js index 222b8b7b..0cf76ee 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/View.js +++ b/third_party/blink/renderer/devtools/front_end/ui/View.js
@@ -506,7 +506,7 @@ this._titleElement.addEventListener('keydown', this._onTitleKeyDown.bind(this), false); this.contentElement.insertBefore(this._titleElement, this.contentElement.firstChild); - this.contentElement.createChild('content'); + this.contentElement.createChild('slot'); this._view = view; view[UI.ViewManager._ExpandableContainerWidget._symbol] = this; }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/Widget.js b/third_party/blink/renderer/devtools/front_end/ui/Widget.js index 861f157..611890d 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/Widget.js +++ b/third_party/blink/renderer/devtools/front_end/ui/Widget.js
@@ -30,13 +30,14 @@ UI.Widget = class extends Common.Object { /** * @param {boolean=} isWebComponent + * @param {boolean=} delegatesFocus */ - constructor(isWebComponent) { + constructor(isWebComponent, delegatesFocus) { super(); this.contentElement = createElementWithClass('div', 'widget'); if (isWebComponent) { this.element = createElementWithClass('div', 'vbox flex-auto'); - this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element); + this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, undefined, delegatesFocus); this._shadowRoot.appendChild(this.contentElement); } else { this.element = this.contentElement; @@ -599,9 +600,10 @@ UI.VBox = class extends UI.Widget { /** * @param {boolean=} isWebComponent + * @param {boolean=} delegatesFocus */ - constructor(isWebComponent) { - super(isWebComponent); + constructor(isWebComponent, delegatesFocus) { + super(isWebComponent, delegatesFocus); this.contentElement.classList.add('vbox'); }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/filter.css b/third_party/blink/renderer/devtools/front_end/ui/filter.css index 025789e..b09df818 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/filter.css +++ b/third_party/blink/renderer/devtools/front_end/ui/filter.css
@@ -46,10 +46,6 @@ align-items: center; } -.filter-text-filter label { - margin: auto 0; -} - .filter-bitset-filter { padding: 2px; display: inline-flex; @@ -116,7 +112,7 @@ position: relative; } -.filter-checkbox-filter > label { +.filter-checkbox-filter > [is=dt-checkbox] { display: flex; margin: auto 0; }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css b/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css index e5fd320..365d09a 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css +++ b/third_party/blink/renderer/devtools/front_end/ui/inspectorCommon.css
@@ -310,7 +310,7 @@ white-space: nowrap; } -label[is=dt-icon-label] { +span[is=dt-icon-label] { flex: none; }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/radioButton.css b/third_party/blink/renderer/devtools/front_end/ui/radioButton.css index 47f4775b..cadf3a7 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/radioButton.css +++ b/third_party/blink/renderer/devtools/front_end/ui/radioButton.css
@@ -4,7 +4,7 @@ * found in the LICENSE file. */ -::content .dt-radio-button { +::slotted(input.dt-radio-button) { height: 17px; width: 17px; min-width: 17px; @@ -16,16 +16,16 @@ margin: 0 5px 5px 0; } -::content .dt-radio-button:active:not(:disabled) { +::slotted(input.dt-radio-button:active:not(:disabled)) { background-image: linear-gradient(to bottom, rgb(194, 194, 194), rgb(239, 239, 239)); } -::content .dt-radio-button:checked { +::slotted(input.dt-radio-button:checked) { background: url(Images/radioDot.png) center no-repeat, linear-gradient(to bottom, rgb(252, 252, 252), rgb(223, 223, 223)); } -::content .dt-radio-button:checked:active { +::slotted(input.dt-radio-button:checked:active) { background: url(Images/radioDot.png) center no-repeat, linear-gradient(to bottom, rgb(194, 194, 194), rgb(239, 239, 239)); }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/softDropDownButton.css b/third_party/blink/renderer/devtools/front_end/ui/softDropDownButton.css index 3812ef154..2270d27 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/softDropDownButton.css +++ b/third_party/blink/renderer/devtools/front_end/ui/softDropDownButton.css
@@ -3,7 +3,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -:host { +button.soft-dropdown { height: 26px; text-align: left; position: relative; @@ -11,18 +11,18 @@ background: none; } -:host([disabled]) { +button.soft-dropdown[disabled] { opacity: .5; } -:host .title { +button.soft-dropdown > .title { padding-right: 5px; width: 120px; overflow: hidden; text-overflow: ellipsis; } -:host([data-keyboard-focus="true"]:focus)::before { +button.soft-dropdown[data-keyboard-focus="true"]:focus::before { content: ""; position: absolute; top: 2px;
diff --git a/third_party/blink/renderer/modules/accessibility/BUILD.gn b/third_party/blink/renderer/modules/accessibility/BUILD.gn index c4478a9..ae01f5a 100644 --- a/third_party/blink/renderer/modules/accessibility/BUILD.gn +++ b/third_party/blink/renderer/modules/accessibility/BUILD.gn
@@ -54,6 +54,8 @@ "ax_sparse_attribute_setter.h", "ax_svg_root.cc", "ax_svg_root.h", + "ax_validation_message.cc", + "ax_validation_message.h", "ax_virtual_object.cc", "ax_virtual_object.h", "inspector_accessibility_agent.cc",
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc index e973564..8d0e93e 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -2091,6 +2091,7 @@ AddRemoteSVGChildren(); AddTableChildren(); AddInlineTextBoxChildren(false); + AddValidationMessageChild(); AddAccessibleNodeChildren(); for (const auto& child : children_) { @@ -2781,6 +2782,30 @@ } } +void AXLayoutObject::AddValidationMessageChild() { + if (!IsWebArea()) + return; + AXObject* ax_object = AXObjectCache().ValidationMessageObjectIfVisible(); + if (ax_object) + children_.push_back(ax_object); +} + +AXObject* AXLayoutObject::ErrorMessage() const { + // Check for aria-errormessage. + Element* existing_error_message = + GetAOMPropertyOrARIAAttribute(AOMRelationProperty::kErrorMessage); + if (existing_error_message) + return AXObjectCache().GetOrCreate(existing_error_message); + + // Check for visible validationMessage. This can only be visible for a focused + // control. Corollary: if there is a visible validationMessage alert box, then + // it is related to the current focus. + if (this != AXObjectCache().FocusedObject()) + return nullptr; + + return AXObjectCache().ValidationMessageObjectIfVisible(); +} + void AXLayoutObject::LineBreaks(Vector<int>& line_breaks) const { if (!IsTextControl()) return;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h index 9e1d6adb..cf75d73c 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h +++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
@@ -207,6 +207,10 @@ // For a table row or column. AXObject* HeaderObject() const override; + // The aria-errormessage object or native object from a validationMessage + // alert. + AXObject* ErrorMessage() const override; + private: bool IsTabItemSelected() const; bool IsValidSelectionBound(const AXObject*) const; @@ -224,6 +228,7 @@ void AddRemoteSVGChildren(); void AddTableChildren(); void AddInlineTextBoxChildren(bool force); + void AddValidationMessageChild(); ax::mojom::Role DetermineTableCellRole() const; ax::mojom::Role DetermineTableRowRole() const; bool FindAllTableCellsWithRole(ax::mojom::Role, AXObjectVector&) const;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc b/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc index 43d264e3..dd9627cf 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc
@@ -58,11 +58,6 @@ case kMediaSlider: return AccessibilityMediaTimeline::Create(layout_object, ax_object_cache); - case kMediaCurrentTimeDisplay: - case kMediaTimeRemainingDisplay: - return AccessibilityMediaTimeDisplay::Create(layout_object, - ax_object_cache); - case kMediaControlsPanel: return AXMediaControlsContainer::Create(layout_object, ax_object_cache); @@ -119,10 +114,6 @@ AXRelatedObjectVector* related_objects, NameSources* name_sources) const { switch (ControlType()) { - case kMediaCurrentTimeDisplay: - return QueryString(WebLocalizedString::kAXMediaCurrentTimeDisplay); - case kMediaTimeRemainingDisplay: - return QueryString(WebLocalizedString::kAXMediaTimeRemainingDisplay); case kMediaCastOffButton: case kMediaOverlayCastOffButton: return QueryString(WebLocalizedString::kAXMediaCastOffButton); @@ -159,10 +150,6 @@ ax::mojom::DescriptionFrom& description_from, AXObjectVector* description_objects) const { switch (ControlType()) { - case kMediaCurrentTimeDisplay: - return QueryString(WebLocalizedString::kAXMediaCurrentTimeDisplayHelp); - case kMediaTimeRemainingDisplay: - return QueryString(WebLocalizedString::kAXMediaTimeRemainingDisplayHelp); case kMediaOverflowButton: return QueryString(WebLocalizedString::kAXMediaOverflowButtonHelp); // The following descriptions are repeats of their respective titles. When @@ -220,8 +207,6 @@ return ax::mojom::Role::kGroup; case kMediaControlsPanel: - case kMediaCurrentTimeDisplay: - case kMediaTimeRemainingDisplay: case kMediaSliderThumb: case kMediaTrackSelectionCheckmark: case kMediaScrubbingMessage: @@ -282,12 +267,6 @@ // // AccessibilityMediaTimeline -static String LocalizedMediaTimeDescription(float /*time*/) { - // FIXME: To be fixed. See - // http://trac.webkit.org/browser/trunk/Source/WebCore/platform/LocalizedStrings.cpp#L928 - return String(); -} - AccessibilityMediaTimeline::AccessibilityMediaTimeline( LayoutObject* layout_object, AXObjectCacheImpl& ax_object_cache) @@ -309,53 +288,4 @@ : WebLocalizedString::kAXMediaAudioSliderHelp); } -// -// AccessibilityMediaTimeDisplay - -AccessibilityMediaTimeDisplay::AccessibilityMediaTimeDisplay( - LayoutObject* layout_object, - AXObjectCacheImpl& ax_object_cache) - : AccessibilityMediaControl(layout_object, ax_object_cache) {} - -AXObject* AccessibilityMediaTimeDisplay::Create( - LayoutObject* layout_object, - AXObjectCacheImpl& ax_object_cache) { - return MakeGarbageCollected<AccessibilityMediaTimeDisplay>(layout_object, - ax_object_cache); -} - -bool AccessibilityMediaTimeDisplay::ComputeAccessibilityIsIgnored( - IgnoredReasons* ignored_reasons) const { - if (!layout_object_ || !layout_object_->Style() || - layout_object_->Style()->Visibility() != EVisibility::kVisible) - return true; - - if (!layout_object_->Style()->Width().Value()) - return true; - - return AccessibilityIsIgnoredByDefault(ignored_reasons); -} - -String AccessibilityMediaTimeDisplay::TextAlternative( - bool recursive, - bool in_aria_labelled_by_traversal, - AXObjectSet& visited, - ax::mojom::NameFrom& name_from, - AXRelatedObjectVector* related_objects, - NameSources* name_sources) const { - if (ControlType() == kMediaCurrentTimeDisplay) - return QueryString(WebLocalizedString::kAXMediaCurrentTimeDisplay); - return QueryString(WebLocalizedString::kAXMediaTimeRemainingDisplay); -} - -String AccessibilityMediaTimeDisplay::StringValue() const { - if (!layout_object_ || !layout_object_->GetNode()) - return String(); - - MediaControlTimeDisplayElement* element = - static_cast<MediaControlTimeDisplayElement*>(layout_object_->GetNode()); - float time = element->CurrentValue(); - return LocalizedMediaTimeDescription(fabsf(time)); -} - } // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.h b/third_party/blink/renderer/modules/accessibility/ax_object.h index 4810b8f..7d11bb3 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.h +++ b/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -528,6 +528,7 @@ virtual bool IsTextControl() const { return false; } bool IsTextObject() const; bool IsTree() const { return RoleValue() == ax::mojom::Role::kTree; } + virtual bool IsValidationMessage() const { return false; } virtual bool IsVirtualObject() const { return false; } bool IsWebArea() const { return RoleValue() == ax::mojom::Role::kRootWebArea; @@ -744,6 +745,7 @@ virtual String AriaAutoComplete() const { return String(); } virtual void AriaOwnsElements(AXObjectVector& owns) const {} virtual void AriaDescribedbyElements(AXObjectVector&) const {} + virtual AXObject* ErrorMessage() const { return nullptr; } virtual ax::mojom::HasPopup HasPopup() const { return ax::mojom::HasPopup::kFalse; }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 10605382..1606304 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -45,6 +45,7 @@ #include "third_party/blink/renderer/core/html/forms/html_label_element.h" #include "third_party/blink/renderer/core/html/forms/html_option_element.h" #include "third_party/blink/renderer/core/html/forms/html_select_element.h" +#include "third_party/blink/renderer/core/html/forms/listed_element.h" #include "third_party/blink/renderer/core/html/html_area_element.h" #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" #include "third_party/blink/renderer/core/html/html_image_element.h" @@ -81,6 +82,7 @@ #include "third_party/blink/renderer/modules/accessibility/ax_relation_cache.h" #include "third_party/blink/renderer/modules/accessibility/ax_slider.h" #include "third_party/blink/renderer/modules/accessibility/ax_svg_root.h" +#include "third_party/blink/renderer/modules/accessibility/ax_validation_message.h" #include "third_party/blink/renderer/modules/accessibility/ax_virtual_object.h" #include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h" #include "third_party/blink/renderer/modules/permissions/permission_utils.h" @@ -98,6 +100,7 @@ : AXObjectCacheBase(document), document_(document), modification_count_(0), + validation_message_axid_(0), relation_cache_(new AXRelationCache(this)), notification_post_timer_( document.GetTaskRunner(TaskType::kInternalDefault), @@ -1111,6 +1114,8 @@ ChildrenChanged(element->parentNode()); else if (attr_name == kAriaInvalidAttr) PostNotification(element, ax::mojom::Event::kInvalidStatusChanged); + else if (attr_name == kAriaErrormessageAttr) + MarkElementDirty(element, false); else if (attr_name == kAriaOwnsAttr) ChildrenChanged(element); else @@ -1123,6 +1128,68 @@ obj->HandleAutofillStateChanged(is_available); } +AXObject* AXObjectCacheImpl::GetOrCreateValidationMessageObject() { + AXObject* message_ax_object = nullptr; + // Create only if it does not already exist. + if (validation_message_axid_) { + message_ax_object = ObjectFromAXID(validation_message_axid_); + } + if (!message_ax_object) { + message_ax_object = AXValidationMessage::Create(*this); + DCHECK(message_ax_object); + // Cache the validation message container for reuse. + validation_message_axid_ = GetOrCreateAXID(message_ax_object); + message_ax_object->Init(); + } + return message_ax_object; +} + +AXObject* AXObjectCacheImpl::ValidationMessageObjectIfVisible() { + Element* focused_element = document_->FocusedElement(); + if (!focused_element) + return nullptr; + ListedElement* form_control = ListedElement::From(*focused_element); + if (!form_control || !form_control->IsValidationMessageVisible()) + return nullptr; + + AXObject* focused_object = this->FocusedObject(); + DCHECK(focused_object); + + // Return as long as the focused form control isn't overriding with a + // different message via aria-errormessage. + bool override_native_validation_message = + focused_object->GetAOMPropertyOrARIAAttribute( + AOMRelationProperty::kErrorMessage); + if (override_native_validation_message) + return nullptr; + + return GetOrCreateValidationMessageObject(); +} + +// Native validation error popup for focused form control in current document. +void AXObjectCacheImpl::HandleValidationMessageVisibilityChanged( + const Element* form_control) { + AXObject* message_ax_object = ValidationMessageObjectIfVisible(); + if (!message_ax_object && validation_message_axid_) { + // Remove when it becomes hidden, so that a new object is created the next + // time the message becomes visible. It's not possible to reuse the same + // alert, because the event generator will not generate an alert event if + // the same object is hidden and made visible quickly, which occurs if the + // user submits the form when an alert is already visible. + Remove(validation_message_axid_); + validation_message_axid_ = 0; + } + + // Form control will now have an error message relation to message container. + MarkElementDirty(form_control, false); + + // Validation message alert object is a child of the document, as not all form + // controls can have a child. Also, there are form controls such as listbox + // that technically can have children, but they are probably not expected to + // have alerts within AT client code. + ChildrenChanged(document_); +} + void AXObjectCacheImpl::LabelChanged(Element* element) { TextChanged(ToHTMLLabelElement(element)->control()); } @@ -1235,6 +1302,11 @@ webframe->Client()->MarkWebAXObjectDirty(WebAXObject(obj), subtree); } +void AXObjectCacheImpl::MarkElementDirty(const Element* element, bool subtree) { + if (AXObject* obj = Get(element)) + MarkAXObjectDirty(obj, subtree); +} + void AXObjectCacheImpl::HandleFocusedUIElementChanged(Node* old_focused_node, Node* new_focused_node) { if (!new_focused_node)
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h index a76e0d7..684b1f4 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -107,6 +107,8 @@ void HandleAttributeChanged(const QualifiedName& attr_name, Element*) override; void HandleAutofillStateChanged(Element*, bool) override; + void HandleValidationMessageVisibilityChanged( + const Element* form_control) override; void HandleFocusedUIElementChanged(Node* old_focused_node, Node* new_focused_node) override; void HandleInitialFocus() override; @@ -193,6 +195,7 @@ void PostNotification(Node*, ax::mojom::Event); void PostNotification(AXObject*, ax::mojom::Event); void MarkAXObjectDirty(AXObject*, bool subtree); + void MarkElementDirty(const Element*, bool subtree); // // Aria-owns support. @@ -228,6 +231,9 @@ // granted, it only applies to the next event received. void RequestAOMEventListenerPermission(); + // For built-in HTML form validation messages. + AXObject* ValidationMessageObjectIfVisible(); + protected: void PostPlatformNotification(AXObject*, ax::mojom::Event); void LabelChanged(Element*); @@ -249,6 +255,12 @@ HashSet<AXID> ids_in_use_; + // Used for a mock AXObject representing the message displayed in the + // validation message bubble. + // There can be only one of these per document with invalid form controls, + // and it will always be related to the currently focused control. + AXID validation_message_axid_; + std::unique_ptr<AXRelationCache> relation_cache_; #if DCHECK_IS_ON() @@ -289,6 +301,9 @@ // Must be called an entire subtree of accessible objects are no longer valid. void InvalidateTableSubtree(AXObject* subtree); + // Object for HTML validation alerts. Created at most once per object cache. + AXObject* GetOrCreateValidationMessageObject(); + // Whether the user has granted permission for the user to install event // listeners for accessibility events using the AOM. mojom::PermissionStatus accessibility_event_permission_;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc b/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc new file mode 100644 index 0000000..7e391f3 --- /dev/null +++ b/third_party/blink/renderer/modules/accessibility/ax_validation_message.cc
@@ -0,0 +1,134 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/accessibility/ax_validation_message.h" + +#include "SkMatrix44.h" +#include "third_party/blink/renderer/core/html/forms/listed_element.h" +#include "third_party/blink/renderer/core/html/html_element.h" +#include "third_party/blink/renderer/core/layout/layout_object.h" +#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h" + +namespace blink { + +AXValidationMessage::AXValidationMessage(AXObjectCacheImpl& ax_object_cache) + : AXMockObject(ax_object_cache) {} + +AXValidationMessage::~AXValidationMessage() {} + +AXObject* AXValidationMessage::ComputeParent() const { + return AXObjectCache().Root(); +} + +bool AXValidationMessage::ComputeAccessibilityIsIgnored( + IgnoredReasons* ignored_reasons) const { + return false; +} + +// TODO(accessibility) Currently we return the bounds of the focused form +// control. If this becomes an issue, return the bounds of the alert itself. +void AXValidationMessage::GetRelativeBounds(AXObject** out_container, + FloatRect& out_bounds_in_container, + SkMatrix44& out_container_transform, + bool* clips_children) const { + DCHECK(out_container); + *out_container = nullptr; + out_bounds_in_container = FloatRect(); + out_container_transform.setIdentity(); + if (clips_children) + *clips_children = false; + + ListedElement* listed_element = RelatedFormControlIfVisible(); + if (!listed_element) + return; + + HTMLElement* form_control = ToHTMLElement(listed_element); + if (!form_control || !form_control->GetLayoutObject()) + return; + + *out_container = ParentObject(); + + if (form_control->GetLayoutObject()) { + out_bounds_in_container = + FloatRect(form_control->GetLayoutObject()->AbsoluteBoundingBoxRect()); + } +} + +bool AXValidationMessage::IsOffScreen() const { + return false; +} + +bool AXValidationMessage::IsVisible() const { + return RelatedFormControlIfVisible(); +} + +const AtomicString& AXValidationMessage::LiveRegionStatus() const { + DEFINE_STATIC_LOCAL(const AtomicString, live_region_status_assertive, + ("assertive")); + return live_region_status_assertive; +} + +const AtomicString& AXValidationMessage::LiveRegionRelevant() const { + DEFINE_STATIC_LOCAL(const AtomicString, live_region_relevant_additions, + ("additions")); + return live_region_relevant_additions; +} + +ax::mojom::Role AXValidationMessage::RoleValue() const { + return ax::mojom::Role::kAlert; +} + +ListedElement* AXValidationMessage::RelatedFormControlIfVisible() const { + AXObject* focused_object = AXObjectCache().FocusedObject(); + if (!focused_object) + return nullptr; + + Element* element = focused_object->GetElement(); + if (!element) + return nullptr; + + ListedElement* form_control = ListedElement::From(*element); + if (!form_control || !form_control->IsValidationMessageVisible()) + return nullptr; + + // The method IsValidationMessageVisible() is a superset of + // IsNotCandidateOrValid(), but has the benefit of not being true until user + // has tried to submit data. Waiting until the error message is visible + // before presenting to screen reader is preferable over hearing about the + // error while the user is still attempting to input data in the first place. + return form_control->IsValidationMessageVisible() ? form_control : nullptr; +} + +String AXValidationMessage::TextAlternative( + bool recursive, + bool in_aria_labelled_by_traversal, + AXObjectSet& visited, + ax::mojom::NameFrom& name_from, + AXRelatedObjectVector* related_objects, + NameSources* name_sources) const { + // If nameSources is non-null, relatedObjects is used in filling it in, so it + // must be non-null as well. + if (name_sources) + DCHECK(related_objects); + + ListedElement* form_control_element = RelatedFormControlIfVisible(); + if (!form_control_element) + return String(); + + String message = form_control_element->validationMessage(); + if (form_control_element->ValidationSubMessage()) { + message.append(' '); + message.append(form_control_element->ValidationSubMessage()); + } + + if (name_sources) { + name_sources->push_back(NameSource(true)); + name_sources->back().type = ax::mojom::NameFrom::kContents; + name_sources->back().text = message; + } + + return message; +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_validation_message.h b/third_party/blink/renderer/modules/accessibility/ax_validation_message.h new file mode 100644 index 0000000..55fc5ed --- /dev/null +++ b/third_party/blink/renderer/modules/accessibility/ax_validation_message.h
@@ -0,0 +1,60 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_VALIDATION_MESSAGE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_VALIDATION_MESSAGE_H_ + +#include "base/macros.h" +#include "third_party/blink/renderer/modules/accessibility/ax_mock_object.h" + +namespace blink { + +class AXObjectCacheImpl; +class ListedElement; + +// The AXValidationMessage is a mock object that exposes an alert for a native +// error message popup for an invalid HTML control, aka a validation message. +// The alert is exposed with a name containing the text of the popup.. + +class AXValidationMessage final : public AXMockObject { + public: + static AXValidationMessage* Create(AXObjectCacheImpl& ax_object_cache) { + return MakeGarbageCollected<AXValidationMessage>(ax_object_cache); + } + + explicit AXValidationMessage(AXObjectCacheImpl&); + ~AXValidationMessage() override; + + private: + // AXObject: + bool CanHaveChildren() const override { return false; } + bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override; + AXObject* ComputeParent() const override; + void GetRelativeBounds(AXObject** out_container, + FloatRect& out_bounds_in_container, + SkMatrix44& out_container_transform, + bool* clips_children) const override; + const AtomicString& LiveRegionStatus() const override; + const AtomicString& LiveRegionRelevant() const override; + bool IsOffScreen() const override; + bool IsValidationMessage() const override { return true; } + bool IsVisible() const override; + String TextAlternative(bool recursive, + bool in_aria_labelled_by_traversal, + AXObjectSet& visited, + ax::mojom::NameFrom&, + AXRelatedObjectVector*, + NameSources*) const override; + ax::mojom::Role RoleValue() const override; + + ListedElement* RelatedFormControlIfVisible() const; + + DISALLOW_COPY_AND_ASSIGN(AXValidationMessage); +}; + +DEFINE_AX_OBJECT_TYPE_CASTS(AXValidationMessage, IsValidationMessage()); + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_VALIDATION_MESSAGE_H_
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl index 0fcd2ab..81799c8a 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl
@@ -15,6 +15,6 @@ void bezierCurveTo(unrestricted float cp1x, unrestricted float cp1y, unrestricted float cp2x, unrestricted float cp2y, unrestricted float x, unrestricted float y); [RaisesException] void arcTo(unrestricted float x1, unrestricted float y1, unrestricted float x2, unrestricted float y2, unrestricted float radius); void rect(unrestricted float x, unrestricted float y, unrestricted float width, unrestricted float height); - [RaisesException] void arc(unrestricted float x, unrestricted float y, unrestricted float radius, unrestricted float startAngle, unrestricted float endAngle, [Default=Undefined] optional boolean anticlockwise); - [RaisesException] void ellipse(unrestricted float x, unrestricted float y, unrestricted float radiusX, unrestricted float radiusY, unrestricted float rotation, unrestricted float startAngle, unrestricted float endAngle, [Default=Undefined] optional boolean anticlockwise); + [RaisesException] void arc(unrestricted float x, unrestricted float y, unrestricted float radius, unrestricted float startAngle, unrestricted float endAngle, [DefaultValue=Undefined] optional boolean anticlockwise); + [RaisesException] void ellipse(unrestricted float x, unrestricted float y, unrestricted float radiusX, unrestricted float radiusY, unrestricted float rotation, unrestricted float startAngle, unrestricted float endAngle, [DefaultValue=Undefined] optional boolean anticlockwise); };
diff --git a/third_party/blink/renderer/modules/contacts_picker/BUILD.gn b/third_party/blink/renderer/modules/contacts_picker/BUILD.gn index d16f3e4..7a543ada 100644 --- a/third_party/blink/renderer/modules/contacts_picker/BUILD.gn +++ b/third_party/blink/renderer/modules/contacts_picker/BUILD.gn
@@ -6,8 +6,6 @@ blink_modules_sources("contacts_picker") { sources = [ - "contact_info.cc", - "contact_info.h", "contacts_manager.cc", "contacts_manager.h", "navigator_contacts.cc",
diff --git a/third_party/blink/renderer/modules/contacts_picker/contact_info.cc b/third_party/blink/renderer/modules/contacts_picker/contact_info.cc deleted file mode 100644 index d1ea4c2..0000000 --- a/third_party/blink/renderer/modules/contacts_picker/contact_info.cc +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/modules/contacts_picker/contact_info.h" - -namespace blink { - -ContactInfo::ContactInfo(base::Optional<Vector<String>> name, - base::Optional<Vector<String>> email, - base::Optional<Vector<String>> tel) - : name_(std::move(name)), email_(std::move(email)), tel_(std::move(tel)) {} - -ContactInfo::~ContactInfo() = default; - -const Vector<String> ContactInfo::name(bool& is_null) const { - is_null = !name_.has_value(); - return is_null ? Vector<String>() : name_.value(); -} - -const Vector<String> ContactInfo::email(bool& is_null) const { - is_null = !email_.has_value(); - return is_null ? Vector<String>() : email_.value(); -} - -const Vector<String> ContactInfo::tel(bool& is_null) const { - is_null = !tel_.has_value(); - return is_null ? Vector<String>() : tel_.value(); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/modules/contacts_picker/contact_info.h b/third_party/blink/renderer/modules/contacts_picker/contact_info.h deleted file mode 100644 index 69fc3615..0000000 --- a/third_party/blink/renderer/modules/contacts_picker/contact_info.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CONTACTS_PICKER_CONTACT_INFO_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_CONTACTS_PICKER_CONTACT_INFO_H_ - -#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" -#include "third_party/blink/renderer/platform/heap/thread_state.h" -#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" -#include "third_party/blink/renderer/platform/wtf/vector.h" - -namespace blink { - -// Represents an individual Contact in the Contacts Picker. -class ContactInfo final : public ScriptWrappable { - DEFINE_WRAPPERTYPEINFO(); - - public: - ContactInfo(base::Optional<Vector<String>> name, - base::Optional<Vector<String>> email, - base::Optional<Vector<String>> tel); - ~ContactInfo() override; - - // Web-exposed attributes defined in the IDL file. - const Vector<String> name(bool& is_null) const; - const Vector<String> email(bool& is_null) const; - const Vector<String> tel(bool& is_null) const; - - private: - base::Optional<Vector<String>> name_; - base::Optional<Vector<String>> email_; - base::Optional<Vector<String>> tel_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CONTACTS_PICKER_CONTACT_INFO_H_
diff --git a/third_party/blink/renderer/modules/contacts_picker/contact_info.idl b/third_party/blink/renderer/modules/contacts_picker/contact_info.idl index b9a5c45c..82f06c5 100644 --- a/third_party/blink/renderer/modules/contacts_picker/contact_info.idl +++ b/third_party/blink/renderer/modules/contacts_picker/contact_info.idl
@@ -4,12 +4,8 @@ // https://github.com/beverloo/contact-api -[ - SecureContext, - Exposed=Window, - RuntimeEnabled=ContactsManager -] interface ContactInfo { - readonly attribute FrozenArray<DOMString>? name; - readonly attribute FrozenArray<DOMString>? email; - readonly attribute FrozenArray<DOMString>? tel; +dictionary ContactInfo { + sequence<USVString> name; + sequence<USVString> email; + sequence<USVString> tel; };
diff --git a/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc b/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc index c0c2855..2512851 100644 --- a/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc +++ b/third_party/blink/renderer/modules/contacts_picker/contacts_manager.cc
@@ -8,8 +8,10 @@ #include "mojo/public/cpp/bindings/interface_request.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/modules/contacts_picker/contact_info.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/heap/visitor.h" @@ -26,25 +28,39 @@ blink::ContactInfo* TypeConverter<blink::ContactInfo*, blink::mojom::blink::ContactInfoPtr>:: Convert(const blink::mojom::blink::ContactInfoPtr& contact) { - Vector<String> names; - Vector<String> emails; - Vector<String> numbers; + blink::ContactInfo* contact_info = blink::ContactInfo::Create(); + if (contact->name.has_value()) { - for (const auto& name : *contact->name) + Vector<String> names; + names.ReserveInitialCapacity(contact->name->size()); + + for (const String& name : *contact->name) names.push_back(name); + + contact_info->setName(names); } + if (contact->email.has_value()) { - for (const auto& email : *contact->email) + Vector<String> emails; + emails.ReserveInitialCapacity(contact->email->size()); + + for (const String& email : *contact->email) emails.push_back(email); + + contact_info->setEmail(emails); } + if (contact->tel.has_value()) { - for (const auto& number : *contact->tel) + Vector<String> numbers; + numbers.ReserveInitialCapacity(contact->tel->size()); + + for (const String& number : *contact->tel) numbers.push_back(number); + + contact_info->setTel(numbers); } - return blink::MakeGarbageCollected<blink::ContactInfo>( - names.IsEmpty() ? base::Optional<Vector<String>>() : names, - emails.IsEmpty() ? base::Optional<Vector<String>>() : emails, - numbers.IsEmpty() ? base::Optional<Vector<String>>() : numbers); + + return contact_info; } } // namespace mojo @@ -66,53 +82,58 @@ ScriptPromise ContactsManager::select(ScriptState* script_state, ContactsSelectOptions* options) { + Document* document = To<Document>(ExecutionContext::From(script_state)); + if (!LocalFrame::HasTransientUserActivation(document ? document->GetFrame() + : nullptr)) { + return ScriptPromise::Reject( + script_state, V8ThrowException::CreateTypeError( + script_state->GetIsolate(), + "A user gesture is required to call this method")); + } + + if (!options->hasProperties() || !options->properties().size()) { + return ScriptPromise::Reject(script_state, + V8ThrowException::CreateTypeError( + script_state->GetIsolate(), + "At least one property must be provided")); + } + ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); - if (!options->hasProperties()) { - resolver->Reject(DOMException::Create( - DOMExceptionCode::kAbortError, "Dictionary must contain 'properties'")); - return promise; - } + bool include_names = false; + bool include_emails = false; + bool include_tel = false; - bool names = false; - bool emails = false; - bool tel = false; for (const String& property : options->properties()) { if (property == "name") - names = true; + include_names = true; else if (property == "email") - emails = true; + include_emails = true; else if (property == "tel") - tel = true; + include_tel = true; } - if (!names && !emails && !tel) { - resolver->Reject( - DOMException::Create(DOMExceptionCode::kAbortError, - "'properties' must contain at least one entry")); - return promise; - } - - // TODO(finnur): Figure out empty-array vs null. GetContactsManager(script_state) - ->Select(options->multiple(), names, emails, tel, + ->Select(options->multiple(), include_names, include_emails, include_tel, WTF::Bind(&ContactsManager::OnContactsSelected, WrapPersistent(this), WrapPersistent(resolver))); + return promise; } void ContactsManager::OnContactsSelected( ScriptPromiseResolver* resolver, base::Optional<Vector<mojom::blink::ContactInfoPtr>> contacts) { + ScriptState* script_state = resolver->GetScriptState(); + ScriptState::Scope scope(script_state); + if (!contacts.has_value()) { - resolver->Reject(DOMException::Create(DOMExceptionCode::kAbortError, - "Unable to open a contact selector")); + resolver->Reject(V8ThrowException::CreateTypeError( + script_state->GetIsolate(), "Unable to open a contact selector")); return; } - ScriptState::Scope scope(resolver->GetScriptState()); - HeapVector<Member<ContactInfo>> contacts_list; for (const auto& contact : *contacts) contacts_list.push_back(contact.To<blink::ContactInfo*>());
diff --git a/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl b/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl index 06c67e7..73ac590 100644 --- a/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl +++ b/third_party/blink/renderer/modules/contacts_picker/contacts_manager.idl
@@ -9,5 +9,5 @@ SecureContext, RuntimeEnabled=ContactsManager ] interface ContactsManager { - [CallWith=ScriptState] Promise<FrozenArray<ContactInfo>> select(ContactsSelectOptions options); + [CallWith=ScriptState] Promise<sequence<ContactInfo>> select(ContactsSelectOptions options); };
diff --git a/third_party/blink/renderer/modules/exported/web_ax_object.cc b/third_party/blink/renderer/modules/exported/web_ax_object.cc index a693295..ef79de3 100644 --- a/third_party/blink/renderer/modules/exported/web_ax_object.cc +++ b/third_party/blink/renderer/modules/exported/web_ax_object.cc
@@ -427,6 +427,13 @@ return WebAXObject(private_->ActiveDescendant()); } +WebAXObject WebAXObject::ErrorMessage() const { + if (IsDetached()) + return WebAXObject(); + + return WebAXObject(private_->ErrorMessage()); +} + ax::mojom::HasPopup WebAXObject::HasPopup() const { if (IsDetached()) return ax::mojom::HasPopup::kFalse;
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_list.idl b/third_party/blink/renderer/modules/gamepad/gamepad_list.idl index de8254c..1d280b28 100644 --- a/third_party/blink/renderer/modules/gamepad/gamepad_list.idl +++ b/third_party/blink/renderer/modules/gamepad/gamepad_list.idl
@@ -27,5 +27,5 @@ NoInterfaceObject ] interface GamepadList { readonly attribute unsigned long length; - getter Gamepad item([Default=Undefined] optional unsigned long index); + getter Gamepad item([DefaultValue=Undefined] optional unsigned long index); };
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl b/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl index b5d5b638..aa1ce76 100644 --- a/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl +++ b/third_party/blink/renderer/modules/indexeddb/idb_cursor.idl
@@ -43,7 +43,7 @@ [CallWith=ScriptState, CachedAttribute=isPrimaryKeyDirty] readonly attribute any primaryKey; [RaisesException] void advance([EnforceRange] unsigned long count); - [CallWith=ScriptState, ImplementedAs=Continue, RaisesException] void continue([Default=Undefined] optional any key); + [CallWith=ScriptState, ImplementedAs=Continue, RaisesException] void continue([DefaultValue=Undefined] optional any key); [CallWith=ScriptState, RaisesException] void continuePrimaryKey(any key, any primaryKey); [NewObject, CallWith=ScriptState, RaisesException] IDBRequest update(any value);
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_index.idl b/third_party/blink/renderer/modules/indexeddb/idb_index.idl index 84eca6d..cc8becb 100644 --- a/third_party/blink/renderer/modules/indexeddb/idb_index.idl +++ b/third_party/blink/renderer/modules/indexeddb/idb_index.idl
@@ -36,14 +36,14 @@ [NewObject, CallWith=ScriptState, RaisesException] IDBRequest get(any key); [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getKey(any key); - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAll([Default=Undefined] optional any query, + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAll([DefaultValue=Undefined] optional any query, optional [EnforceRange] unsigned long count); - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAllKeys([Default=Undefined] optional any query, + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAllKeys([DefaultValue=Undefined] optional any query, optional [EnforceRange] unsigned long count); - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest count([Default=Undefined] optional any key); + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest count([DefaultValue=Undefined] optional any key); - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openCursor([Default=Undefined] optional any range, + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openCursor([DefaultValue=Undefined] optional any range, optional IDBCursorDirection direction = "next"); - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openKeyCursor([Default=Undefined] optional any range, + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openKeyCursor([DefaultValue=Undefined] optional any range, optional IDBCursorDirection direction = "next"); };
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl b/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl index 24c6371..c113f5f 100644 --- a/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl +++ b/third_party/blink/renderer/modules/indexeddb/idb_object_store.idl
@@ -34,21 +34,21 @@ [SameObject] readonly attribute IDBTransaction transaction; readonly attribute boolean autoIncrement; - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest put(any value, [Default=Undefined] optional any key); - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest add(any value, [Default=Undefined] optional any key); + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest put(any value, [DefaultValue=Undefined] optional any key); + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest add(any value, [DefaultValue=Undefined] optional any key); [NewObject, CallWith=ScriptState, ImplementedAs=Delete, RaisesException] IDBRequest delete(any key); [NewObject, CallWith=ScriptState, RaisesException] IDBRequest clear(); [NewObject, CallWith=ScriptState, RaisesException] IDBRequest get(any key); [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getKey(any key); - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAll([Default=Undefined] optional any query, + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAll([DefaultValue=Undefined] optional any query, optional [EnforceRange] unsigned long count); - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAllKeys([Default=Undefined] optional any query, + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest getAllKeys([DefaultValue=Undefined] optional any query, optional [EnforceRange] unsigned long count); - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest count([Default=Undefined] optional any key); + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest count([DefaultValue=Undefined] optional any key); - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openCursor([Default=Undefined] optional any range, + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openCursor([DefaultValue=Undefined] optional any range, optional IDBCursorDirection direction = "next"); - [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openKeyCursor([Default=Undefined] optional any range, + [NewObject, CallWith=ScriptState, RaisesException] IDBRequest openKeyCursor([DefaultValue=Undefined] optional any range, optional IDBCursorDirection direction = "next"); [RaisesException] IDBIndex index(DOMString name);
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.cc index 034ce03c..92d077b7 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.cc +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.cc
@@ -10,7 +10,9 @@ MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement( MediaControlsImpl& media_controls) - : MediaControlTimeDisplayElement(media_controls, kMediaCurrentTimeDisplay) { + : MediaControlTimeDisplayElement( + media_controls, + WebLocalizedString::kAXMediaCurrentTimeDisplay) { SetShadowPseudoId( AtomicString("-webkit-media-controls-current-time-display")); }
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h index 1ada7173..6115905 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h
@@ -13,8 +13,6 @@ kMediaSliderThumb, kMediaTextTrackList, kMediaTimelineContainer, - kMediaCurrentTimeDisplay, - kMediaTimeRemainingDisplay, kMediaTrackSelectionCheckmark, kMediaControlsPanel, kMediaCastOffButton,
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.cc index 4f7db11..1622c84 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.cc +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_remaining_time_display_element.cc
@@ -18,8 +18,9 @@ MediaControlRemainingTimeDisplayElement:: MediaControlRemainingTimeDisplayElement(MediaControlsImpl& media_controls) - : MediaControlTimeDisplayElement(media_controls, - kMediaTimeRemainingDisplay) { + : MediaControlTimeDisplayElement( + media_controls, + WebLocalizedString::kAXMediaTimeRemainingDisplay) { SetShadowPseudoId( AtomicString("-webkit-media-controls-time-remaining-display")); }
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.cc index 9000462..b6dbc098 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.cc +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.cc
@@ -8,6 +8,7 @@ #include "third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h" #include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/text/platform_locale.h" namespace { @@ -23,11 +24,15 @@ MediaControlTimeDisplayElement::MediaControlTimeDisplayElement( MediaControlsImpl& media_controls, - MediaControlElementType display_type) - : MediaControlDivElement(media_controls, display_type) {} + blink::WebLocalizedString::Name localized_label) + : MediaControlDivElement(media_controls, kMediaIgnore), + localized_label_(localized_label) { + SetAriaLabel(); +} void MediaControlTimeDisplayElement::SetCurrentValue(double time) { current_value_ = time; + SetAriaLabel(); setInnerText(FormatTime(), ASSERT_NO_EXCEPTION); } @@ -74,4 +79,9 @@ return String::Format("%s%d:%02d", negative_sign, minutes, seconds); } +void MediaControlTimeDisplayElement::SetAriaLabel() { + String aria_label = GetLocale().QueryString(localized_label_, FormatTime()); + setAttribute(html_names::kAriaLabelAttr, AtomicString(aria_label)); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.h index b3c1395..2176a860 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.h +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_time_display_element.h
@@ -16,20 +16,23 @@ public: // Exported to be used in unit tests. MODULES_EXPORT void SetCurrentValue(double); - // Exported to be used by modules/accessibility. MODULES_EXPORT double CurrentValue() const; WebSize GetSizeOrDefault() const override; protected: - MediaControlTimeDisplayElement(MediaControlsImpl&, MediaControlElementType); + MediaControlTimeDisplayElement(MediaControlsImpl&, + blink::WebLocalizedString::Name); virtual int EstimateElementWidth() const; virtual String FormatTime() const; private: + void SetAriaLabel(); + double current_value_ = 0; + blink::WebLocalizedString::Name localized_label_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index 5f86c8df..adf9e515 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -96,7 +96,6 @@ "canvas/imagebitmap/image_bitmap_rendering_context.idl", "canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl", "clipboard/clipboard.idl", - "contacts_picker/contact_info.idl", "contacts_picker/contacts_manager.idl", "cookie_store/cookie_change_event.idl", "cookie_store/cookie_store.idl", @@ -504,6 +503,7 @@ "canvas/canvas2d/canvas_rendering_context_2d_settings.idl", "canvas/canvas2d/hit_region_options.idl", "canvas/htmlcanvas/canvas_context_creation_attributes_module.idl", + "contacts_picker/contact_info.idl", "contacts_picker/contacts_select_options.idl", "cookie_store/cookie_change_event_init.idl", "cookie_store/cookie_list_item.idl", @@ -643,6 +643,7 @@ "peerconnection/rtc_quic_stream_event_init.idl", "peerconnection/rtc_quic_stream_read_result.idl", "peerconnection/rtc_quic_stream_write_parameters.idl", + "peerconnection/rtc_quic_transport_stats.idl", "peerconnection/rtc_rtcp_parameters.idl", "peerconnection/rtc_rtp_capabilities.idl", "peerconnection/rtc_rtp_codec_capability.idl",
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc index de2399b..a7622f3 100644 --- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc +++ b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc
@@ -6,6 +6,7 @@ #include "net/quic/quic_chromium_connection_helper.h" #include "net/third_party/quic/core/crypto/quic_random.h" #include "net/third_party/quic/core/quic_config.h" +#include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/core/tls_client_handshaker.h" #include "net/third_party/quic/core/tls_server_handshaker.h" #include "net/third_party/quic/tools/quic_simple_crypto_server_stream_helper.h" @@ -157,9 +158,16 @@ quic::QuicIpAddress ip; ip.FromString("0.0.0.0"); quic::QuicSocketAddress dummy_address(ip, 0 /* Port */); + quic::QuicConnectionId dummy_connection_id; + if (GetQuicRestartFlag(quic_variable_length_connection_ids_client)) { + char connection_id_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + dummy_connection_id = quic::QuicConnectionId(connection_id_bytes, + sizeof(connection_id_bytes)); + } else { + dummy_connection_id = quic::EmptyQuicConnectionId(); + } return std::make_unique<quic::QuicConnection>( - quic::EmptyQuicConnectionId() /* dummy ID */, dummy_address, helper, - alarm_factory, packet_writer, + dummy_connection_id, dummy_address, helper, alarm_factory, packet_writer, /* owns_writer */ true, perspective, quic::CurrentSupportedVersions()); } @@ -174,7 +182,7 @@ quic::QuicConnectionId GenerateConnectionIdForReject( quic::QuicConnectionId connection_id) const override { - return quic::QuicConnectionIdFromUInt64(random_->RandUint64()); + return quic::QuicUtils::CreateRandomConnectionId(random_); } bool CanAcceptClientHello(const quic::CryptoHandshakeMessage& message,
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc index 1307fd1d..d112cdc7 100644 --- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc +++ b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc
@@ -80,6 +80,15 @@ std::make_pair(stream_host.get(), std::move(stream_host))); } +void QuicTransportHost::GetStats(uint32_t request_id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + P2PQuicTransportStats stats = quic_transport_->GetStats(); + PostCrossThreadTask( + *proxy_thread(), FROM_HERE, + CrossThreadBind(&QuicTransportProxy::OnStats, proxy_, request_id, stats)); +} + void QuicTransportHost::OnRemoveStream(QuicStreamHost* stream_host_to_remove) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h index 80ee6109..53548d6 100644 --- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h +++ b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h
@@ -61,6 +61,8 @@ void CreateStream(std::unique_ptr<QuicStreamHost> stream_host); + void GetStats(uint32_t request_id); + // QuicStreamHost callbacks. void OnRemoveStream(QuicStreamHost* stream_host_to_remove);
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc index 3eca098e..cbc29fe 100644 --- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc +++ b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
@@ -106,6 +106,15 @@ return stream_proxy_ptr; } +void QuicTransportProxy::GetStats(uint32_t request_id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + PostCrossThreadTask( + *host_thread(), FROM_HERE, + CrossThreadBind(&QuicTransportHost::GetStats, + CrossThreadUnretained(host_.get()), request_id)); +} + void QuicTransportProxy::OnRemoveStream( QuicStreamProxy* stream_proxy_to_remove) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -145,4 +154,11 @@ delegate_->OnStream(stream_proxy_ptr); } +void QuicTransportProxy::OnStats(uint32_t request_id, + const P2PQuicTransportStats& stats) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + delegate_->OnStats(request_id, stats); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h index 23f4948..d04dec77 100644 --- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h +++ b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h
@@ -13,6 +13,7 @@ #include "base/single_thread_task_runner.h" #include "base/threading/thread_checker.h" #include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h" +#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h" #include "third_party/webrtc/api/scoped_refptr.h" namespace blink { @@ -48,6 +49,11 @@ bool from_remote) {} // Called when the remote side has created a new stream. virtual void OnStream(QuicStreamProxy* stream_proxy) {} + + // Called after the stats have been gathered on the host thread. The + // |request_id| maps to |request_id| used in GetStats(). + virtual void OnStats(uint32_t request_id, + const P2PQuicTransportStats& stats) {} }; // Construct a Proxy with the underlying QUIC implementation running on the @@ -72,6 +78,11 @@ QuicStreamProxy* CreateStream(); + // Gathers stats on the host thread, then returns them asynchronously with + // Delegate::OnStats. The |request_id| is used to map the GetStats call to the + // returned stats. + void GetStats(uint32_t request_id); + // QuicStreamProxy callbacks. void OnRemoveStream(QuicStreamProxy* stream_proxy); @@ -82,6 +93,7 @@ void OnRemoteStopped(); void OnConnectionFailed(const std::string& error_details, bool from_remote); void OnStream(std::unique_ptr<QuicStreamProxy> stream_proxy); + void OnStats(uint32_t request_id, const P2PQuicTransportStats& stats); // Since the Host is deleted on the host thread (Via OnTaskRunnerDeleter), as // long as this is alive it is safe to post tasks to it (using unretained).
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h b/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h index fd84712..caf51a8 100644 --- a/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h +++ b/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h
@@ -117,6 +117,12 @@ } }; +template <> +struct CrossThreadCopier<P2PQuicTransportStats> + : public CrossThreadCopierPassThrough<P2PQuicTransportStats> { + STATIC_ONLY(CrossThreadCopier); +}; + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_WEB_RTC_CROSS_THREAD_COPIER_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl index 76656b1..dffd338 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl +++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.idl
@@ -33,7 +33,8 @@ Constructor(), ConstructorCallWith=ExecutionContext, Exposed=Window, - RuntimeEnabled=RTCIceTransportExtension + OriginTrialEnabled=RTCIceTransportExtension, + SecureContext ] interface RTCIceTransport : EventTarget { // TODO(github.com/w3c/webrtc-ice/issues/4): role is non-null in the // WebRTC-PC specification.
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl index a8f80e0..ae0e640a 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl +++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl
@@ -14,7 +14,8 @@ // https://w3c.github.io/webrtc-quic/#quicstream* [ Exposed=Window, - RuntimeEnabled=RTCQuicTransport + OriginTrialEnabled=RTCQuicTransport, + SecureContext ] interface RTCQuicStream : EventTarget { readonly attribute RTCQuicTransport transport; readonly attribute RTCQuicStreamState state;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl index ced237c..d3770982 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl +++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl
@@ -4,7 +4,7 @@ // https://w3c.github.io/webrtc-quic/#rtcquicstreamevent [ - RuntimeEnabled=RTCQuicTransport, + OriginTrialEnabled=RTCQuicTransport, Constructor(DOMString type, optional RTCQuicStreamEventInit eventInitDict), Exposed=Window ] interface RTCQuicStreamEvent : Event {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc index c45baa4..b0eb464 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
@@ -8,6 +8,7 @@ #include "net/third_party/quic/platform/impl/quic_chromium_clock.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h" #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" @@ -16,6 +17,7 @@ #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.h" namespace blink { namespace { @@ -338,6 +340,26 @@ return AddStream(proxy_->CreateStream()); } +ScriptPromise RTCQuicTransport::getStats(ScriptState* script_state, + ExceptionState& exception_state) { + // TODO(https://crbug.com/874296): If a shutdown procedure is implemented, we + // can cache the stats before the underlying transport is torn down. This + // would allow getting stats after your transport has closed. + if (state_ != RTCQuicTransportState::kConnected && + state_ != RTCQuicTransportState::kConnecting) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "The RTCQuicTransport's state is not 'connecting' or 'connected'."); + return ScriptPromise(); + } + ScriptPromiseResolver* promise_resolver = + ScriptPromiseResolver::Create(script_state); + uint32_t request_id = ++get_stats_id_counter_; + stats_promise_map_.Set(request_id, promise_resolver); + proxy_->GetStats(request_id); + return promise_resolver->Promise(); +} + RTCQuicStream* RTCQuicTransport::AddStream(QuicStreamProxy* stream_proxy) { auto* stream = MakeGarbageCollected<RTCQuicStream>(GetExecutionContext(), this, stream_proxy); @@ -372,6 +394,48 @@ DispatchEvent(*RTCQuicStreamEvent::Create(stream)); } +static RTCQuicTransportStats* CreateRTCQuicTransportStats( + const P2PQuicTransportStats& p2p_stats) { + RTCQuicTransportStats* rtc_stats = RTCQuicTransportStats::Create(); + rtc_stats->setTimestamp( + ConvertTimeTicksToDOMHighResTimeStamp(p2p_stats.timestamp)); + rtc_stats->setBytesSent(p2p_stats.bytes_sent); + rtc_stats->setPacketsSent(p2p_stats.packets_sent); + rtc_stats->setStreamBytesSent(p2p_stats.stream_bytes_sent); + rtc_stats->setStreamBytesReceived(p2p_stats.stream_bytes_received); + rtc_stats->setNumOutgoingStreamsCreated( + p2p_stats.num_outgoing_streams_created); + rtc_stats->setNumIncomingStreamsCreated( + p2p_stats.num_incoming_streams_created); + rtc_stats->setBytesReceived(p2p_stats.bytes_received); + rtc_stats->setPacketsReceived(p2p_stats.packets_received); + rtc_stats->setPacketsProcessed(p2p_stats.packets_processed); + rtc_stats->setBytesRetransmitted(p2p_stats.bytes_retransmitted); + rtc_stats->setPacketsRetransmitted(p2p_stats.packets_retransmitted); + rtc_stats->setPacketsLost(p2p_stats.packets_lost); + rtc_stats->setPacketsDropped(p2p_stats.packets_dropped); + rtc_stats->setCryptoRetransmitCount(p2p_stats.crypto_retransmit_count); + rtc_stats->setMinRttUs(p2p_stats.min_rtt_us); + rtc_stats->setSmoothedRttUs(p2p_stats.srtt_us); + rtc_stats->setMaxPacketSize(p2p_stats.max_packet_size); + rtc_stats->setMaxReceivedPacketSize(p2p_stats.max_received_packet_size); + rtc_stats->setEstimatedBandwidthBps(p2p_stats.estimated_bandwidth_bps); + rtc_stats->setPacketsReordered(p2p_stats.packets_reordered); + rtc_stats->setBlockedFramesReceived(p2p_stats.blocked_frames_received); + rtc_stats->setBlockedFramesSent(p2p_stats.blocked_frames_sent); + rtc_stats->setConnectivityProbingPacketsReceived( + p2p_stats.connectivity_probing_packets_received); + return rtc_stats; +} + +void RTCQuicTransport::OnStats(uint32_t request_id, + const P2PQuicTransportStats& stats) { + auto it = stats_promise_map_.find(request_id); + DCHECK(it != stats_promise_map_.end()); + it->value->Resolve(CreateRTCQuicTransportStats(stats)); + stats_promise_map_.erase(it); +} + void RTCQuicTransport::OnIceTransportClosed( RTCIceTransport::CloseReason reason) { if (reason == RTCIceTransport::CloseReason::kContextDestroyed) { @@ -419,6 +483,11 @@ break; } + if (reason != CloseReason::kContextDestroyed) { + // Cannot reject/resolve promises when ExecutionContext is being destroyed. + RejectPendingStatsPromises(); + } + DCHECK(!proxy_); DCHECK(IsDisposed()); } @@ -457,6 +526,19 @@ return false; } +void RTCQuicTransport::RejectPendingStatsPromises() { + for (ScriptPromiseResolver* promise_resolver : stats_promise_map_.Values()) { + ScriptState::Scope scope(promise_resolver->GetScriptState()); + ExceptionState exception_state( + promise_resolver->GetScriptState()->GetIsolate(), + ExceptionState::kExecutionContext, "RTCQuicStream", "getStats"); + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "The RTCQuicTransport is closed."); + promise_resolver->Reject(exception_state); + } + stats_promise_map_.clear(); +} + const AtomicString& RTCQuicTransport::InterfaceName() const { return event_target_names::kRTCQuicTransport; } @@ -472,6 +554,7 @@ visitor->Trace(remote_parameters_); visitor->Trace(streams_); visitor->Trace(key_); + visitor->Trace(stats_promise_map_); EventTargetWithInlineData::Trace(visitor); ContextClient::Trace(visitor); }
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h index 27d3361..3093e455 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h
@@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_H_ +#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h" #include "third_party/blink/renderer/modules/event_target_modules.h" @@ -123,6 +124,9 @@ void stop(); RTCQuicStream* createStream(ExceptionState& exception_state); + // Resolves the promise with an RTCQuicTransportStats dictionary. + ScriptPromise getStats(ScriptState* script_state, + ExceptionState& exception_state); DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange, kStatechange); DEFINE_ATTRIBUTE_EVENT_LISTENER(error, kError); DEFINE_ATTRIBUTE_EVENT_LISTENER(quicstream, kQuicstream); @@ -153,6 +157,8 @@ bool from_remote) override; void OnRemoteStopped() override; void OnStream(QuicStreamProxy* stream_proxy) override; + void OnStats(uint32_t request_id, + const P2PQuicTransportStats& stats) override; // Starts the underlying QUIC connection, by creating the underlying QUIC // transport objects and starting the QUIC handshake. @@ -174,6 +180,7 @@ } bool RaiseExceptionIfClosed(ExceptionState& exception_state) const; bool RaiseExceptionIfStarted(ExceptionState& exception_state) const; + void RejectPendingStatsPromises(); Member<RTCIceTransport> transport_; RTCQuicTransportState state_ = RTCQuicTransportState::kNew; @@ -189,6 +196,9 @@ std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory_; std::unique_ptr<QuicTransportProxy> proxy_; HeapHashSet<Member<RTCQuicStream>> streams_; + // Maps from the ID of the stats request to the promise to be resolved. + HeapHashMap<uint32_t, Member<ScriptPromiseResolver>> stats_promise_map_; + uint32_t get_stats_id_counter_ = 0; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl index 16c5c92..3712261 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl +++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl
@@ -17,7 +17,8 @@ ConstructorCallWith=ExecutionContext, RaisesException=Constructor, Exposed=Window, - RuntimeEnabled=RTCQuicTransport + OriginTrialEnabled=RTCQuicTransport, + SecureContext ] interface RTCQuicTransport : EventTarget { readonly attribute RTCIceTransport transport; readonly attribute RTCQuicTransportState state; @@ -26,6 +27,8 @@ [RaisesException] void listen(BufferSource remote_key); void stop(); [RaisesException] RTCQuicStream createStream(); + [CallWith=ScriptState, RaisesException] + Promise<RTCQuicTransportStats> getStats(); attribute EventHandler onstatechange; attribute EventHandler onerror; attribute EventHandler onquicstream;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.idl new file mode 100644 index 0000000..aa8e830 --- /dev/null +++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.idl
@@ -0,0 +1,30 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +dictionary RTCQuicTransportStats { + double timestamp; + unsigned long long bytesSent; + unsigned long long packetsSent; + unsigned long long streamBytesSent; + unsigned long long streamBytesReceived; + unsigned long numOutgoingStreamsCreated; + unsigned long numIncomingStreamsCreated; + unsigned long long bytesReceived; + unsigned long long packetsReceived; + unsigned long long packetsProcessed; + unsigned long long bytesRetransmitted; + unsigned long long packetsRetransmitted; + unsigned long long packetsLost; + unsigned long long packetsDropped; + unsigned long long cryptoRetransmitCount; + unsigned long long minRttUs; + unsigned long long smoothedRttUs; + unsigned long long maxPacketSize; + unsigned long long maxReceivedPacketSize; + unsigned long long estimatedBandwidthBps; + unsigned long long packetsReordered; + unsigned long long blockedFramesReceived; + unsigned long long blockedFramesSent; + unsigned long long connectivityProbingPacketsReceived; +};
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc index 22a3d70..f4b17da 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc
@@ -9,6 +9,8 @@ #include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_transport_stats.h" +#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h" #include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_packet_transport.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_gather_options.h" #include "third_party/webrtc/rtc_base/rtc_certificate_generator.h" @@ -21,6 +23,7 @@ using testing::ElementsAre; using testing::Invoke; using testing::Mock; +using testing::Return; HeapVector<Member<RTCCertificate>> GenerateLocalRTCCertificates() { HeapVector<Member<RTCCertificate>> certificates; @@ -631,4 +634,182 @@ EXPECT_GE(key->ByteLength(), 16u); } +// Test that stats are converted correctly to the RTCQuicTransportStats +// dictionary. +TEST_F(RTCQuicTransportTest, OnStatsConvertsRTCStatsDictionary) { + V8TestingScope scope; + + auto mock_transport = std::make_unique<MockP2PQuicTransport>(); + MockP2PQuicTransport* mock_transport_ptr = mock_transport.get(); + P2PQuicTransport::Delegate* delegate = nullptr; + Persistent<RTCQuicTransport> quic_transport = + CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate); + DCHECK(delegate); + + // Create some dummy values. + P2PQuicTransportStats stats; + stats.bytes_sent = 0; + stats.packets_sent = 1; + stats.stream_bytes_sent = 2; + stats.stream_bytes_received = 3; + stats.num_outgoing_streams_created = 4; + stats.num_incoming_streams_created = 5; + stats.bytes_received = 6; + stats.packets_received = 7; + stats.packets_processed = 8; + stats.bytes_retransmitted = 9; + stats.packets_retransmitted = 10; + stats.packets_lost = 11; + stats.packets_dropped = 12; + stats.crypto_retransmit_count = 13; + stats.min_rtt_us = 14; + stats.srtt_us = 15; + stats.max_packet_size = 16; + stats.max_received_packet_size = 17; + stats.estimated_bandwidth_bps = 18; + stats.packets_reordered = 19; + stats.blocked_frames_received = 20; + stats.blocked_frames_sent = 21; + stats.connectivity_probing_packets_received = 22; + EXPECT_CALL(*mock_transport_ptr, GetStats()).WillOnce(Return(stats)); + ScriptPromise stats_promise = + quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION); + + RunUntilIdle(); + + ASSERT_EQ(v8::Promise::kFulfilled, + stats_promise.V8Value().As<v8::Promise>()->State()); + + RTCQuicTransportStats* rtc_quic_stats = + NativeValueTraits<RTCQuicTransportStats>::NativeValue( + scope.GetIsolate(), + stats_promise.V8Value().As<v8::Promise>()->Result(), + ASSERT_NO_EXCEPTION); + ASSERT_TRUE(rtc_quic_stats->hasTimestamp()); + EXPECT_EQ(ConvertTimeTicksToDOMHighResTimeStamp(stats.timestamp), + rtc_quic_stats->timestamp()); + ASSERT_TRUE(rtc_quic_stats->hasBytesSent()); + EXPECT_EQ(stats.bytes_sent, rtc_quic_stats->bytesSent()); + ASSERT_TRUE(rtc_quic_stats->hasPacketsSent()); + EXPECT_EQ(stats.packets_sent, rtc_quic_stats->packetsSent()); + ASSERT_TRUE(rtc_quic_stats->hasStreamBytesSent()); + EXPECT_EQ(stats.stream_bytes_sent, rtc_quic_stats->streamBytesSent()); + ASSERT_TRUE(rtc_quic_stats->hasStreamBytesSent()); + EXPECT_EQ(stats.stream_bytes_received, rtc_quic_stats->streamBytesReceived()); + ASSERT_TRUE(rtc_quic_stats->hasNumOutgoingStreamsCreated()); + EXPECT_EQ(stats.num_outgoing_streams_created, + rtc_quic_stats->numOutgoingStreamsCreated()); + ASSERT_TRUE(rtc_quic_stats->hasNumIncomingStreamsCreated()); + EXPECT_EQ(stats.num_incoming_streams_created, + rtc_quic_stats->numIncomingStreamsCreated()); + ASSERT_TRUE(rtc_quic_stats->hasBytesReceived()); + EXPECT_EQ(stats.bytes_received, rtc_quic_stats->bytesReceived()); + ASSERT_TRUE(rtc_quic_stats->hasPacketsReceived()); + EXPECT_EQ(stats.packets_received, rtc_quic_stats->packetsReceived()); + ASSERT_TRUE(rtc_quic_stats->hasPacketsProcessed()); + EXPECT_EQ(stats.packets_processed, rtc_quic_stats->packetsProcessed()); + ASSERT_TRUE(rtc_quic_stats->hasBytesRetransmitted()); + EXPECT_EQ(stats.bytes_retransmitted, rtc_quic_stats->bytesRetransmitted()); + ASSERT_TRUE(rtc_quic_stats->hasPacketsRetransmitted()); + EXPECT_EQ(stats.packets_retransmitted, + rtc_quic_stats->packetsRetransmitted()); + ASSERT_TRUE(rtc_quic_stats->hasPacketsLost()); + EXPECT_EQ(stats.packets_lost, rtc_quic_stats->packetsLost()); + ASSERT_TRUE(rtc_quic_stats->hasPacketsDropped()); + EXPECT_EQ(stats.packets_dropped, rtc_quic_stats->packetsDropped()); + ASSERT_TRUE(rtc_quic_stats->hasCryptoRetransmitCount()); + EXPECT_EQ(stats.crypto_retransmit_count, + rtc_quic_stats->cryptoRetransmitCount()); + ASSERT_TRUE(rtc_quic_stats->hasMinRttUs()); + EXPECT_EQ(stats.min_rtt_us, rtc_quic_stats->minRttUs()); + ASSERT_TRUE(rtc_quic_stats->hasSmoothedRttUs()); + EXPECT_EQ(stats.srtt_us, rtc_quic_stats->smoothedRttUs()); + ASSERT_TRUE(rtc_quic_stats->hasMaxPacketSize()); + EXPECT_EQ(stats.max_packet_size, rtc_quic_stats->maxPacketSize()); + ASSERT_TRUE(rtc_quic_stats->hasMaxReceivedPacketSize()); + EXPECT_EQ(stats.max_received_packet_size, + rtc_quic_stats->maxReceivedPacketSize()); + ASSERT_TRUE(rtc_quic_stats->hasEstimatedBandwidthBps()); + EXPECT_EQ(stats.estimated_bandwidth_bps, + rtc_quic_stats->estimatedBandwidthBps()); + ASSERT_TRUE(rtc_quic_stats->hasPacketsReordered()); + EXPECT_EQ(stats.packets_reordered, rtc_quic_stats->packetsReordered()); + ASSERT_TRUE(rtc_quic_stats->hasBlockedFramesReceived()); + EXPECT_EQ(stats.blocked_frames_received, + rtc_quic_stats->blockedFramesReceived()); + ASSERT_TRUE(rtc_quic_stats->hasBlockedFramesSent()); + EXPECT_EQ(stats.blocked_frames_sent, rtc_quic_stats->blockedFramesSent()); + ASSERT_TRUE(rtc_quic_stats->hasConnectivityProbingPacketsReceived()); + EXPECT_EQ(stats.connectivity_probing_packets_received, + rtc_quic_stats->connectivityProbingPacketsReceived()); +} + +// Test that all promises are rejected if the connection closes before +// the OnStats callback is called. +TEST_F(RTCQuicTransportTest, FailedConnectionRejectsStatsPromises) { + V8TestingScope scope; + + auto mock_transport = std::make_unique<MockP2PQuicTransport>(); + P2PQuicTransport::Delegate* delegate = nullptr; + Persistent<RTCQuicTransport> quic_transport = + CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate); + DCHECK(delegate); + + ScriptPromise promise_1 = + quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION); + ScriptPromise promise_2 = + quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION); + delegate->OnConnectionFailed("test_failure", /*from_remote=*/false); + + RunUntilIdle(); + + EXPECT_EQ(v8::Promise::kRejected, + promise_1.V8Value().As<v8::Promise>()->State()); + EXPECT_EQ(v8::Promise::kRejected, + promise_2.V8Value().As<v8::Promise>()->State()); +} + +// Test that all promises are rejected if the remote side closes before +// the OnStats callback is called. +TEST_F(RTCQuicTransportTest, RemoteStopRejectsStatsPromises) { + V8TestingScope scope; + + auto mock_transport = std::make_unique<MockP2PQuicTransport>(); + P2PQuicTransport::Delegate* delegate = nullptr; + Persistent<RTCQuicTransport> quic_transport = + CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate); + DCHECK(delegate); + + ScriptPromise promise_1 = + quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION); + ScriptPromise promise_2 = + quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION); + delegate->OnRemoteStopped(); + + RunUntilIdle(); + + EXPECT_EQ(v8::Promise::kRejected, + promise_1.V8Value().As<v8::Promise>()->State()); + EXPECT_EQ(v8::Promise::kRejected, + promise_2.V8Value().As<v8::Promise>()->State()); +} + +// Test that calling getStats() after going to the "failed" state +// raises a kInvalidStateError. +TEST_F(RTCQuicTransportTest, FailedStateGetStatsRaisesInvalidStateError) { + V8TestingScope scope; + + auto mock_transport = std::make_unique<MockP2PQuicTransport>(); + P2PQuicTransport::Delegate* delegate = nullptr; + Persistent<RTCQuicTransport> quic_transport = + CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate); + DCHECK(delegate); + + delegate->OnRemoteStopped(); + RunUntilIdle(); + + quic_transport->getStats(scope.GetScriptState(), scope.GetExceptionState()); + EXPECT_EQ(DOMExceptionCode::kInvalidStateError, + scope.GetExceptionState().CodeAs<DOMExceptionCode>()); +} } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.idl b/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.idl index 641ca05b..97bf7400 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.idl +++ b/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.idl
@@ -27,6 +27,6 @@ NoInterfaceObject ] interface RTCStatsResponse { sequence<RTCLegacyStatsReport> result(); - RTCLegacyStatsReport namedItem([Default=Undefined] optional DOMString name); - [NotEnumerable, ImplementedAs=namedItem] getter RTCLegacyStatsReport ([Default=Undefined] optional DOMString name); + RTCLegacyStatsReport namedItem([DefaultValue=Undefined] optional DOMString name); + [NotEnumerable, ImplementedAs=namedItem] getter RTCLegacyStatsReport ([DefaultValue=Undefined] optional DOMString name); };
diff --git a/third_party/blink/renderer/modules/plugins/plugin_array.idl b/third_party/blink/renderer/modules/plugins/plugin_array.idl index 8b744aa..2ada86b 100644 --- a/third_party/blink/renderer/modules/plugins/plugin_array.idl +++ b/third_party/blink/renderer/modules/plugins/plugin_array.idl
@@ -27,5 +27,5 @@ readonly attribute unsigned long length; getter Plugin? item(unsigned long index); getter Plugin? namedItem(DOMString name); - void refresh([Default=Undefined] optional boolean reload); + void refresh([DefaultValue=Undefined] optional boolean reload); };
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc index b73b338..f905f026e 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -438,6 +438,11 @@ debugger->ExceptionThrown(GetThread(), event); } +mojom::RequestContextType +ServiceWorkerGlobalScope::GetDestinationForMainScript() { + return mojom::RequestContextType::SERVICE_WORKER; +} + void ServiceWorkerGlobalScope::CountCacheStorageInstalledScript( uint64_t script_size, uint64_t script_metadata_size) {
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h index b2497b79..a37587508 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -167,6 +167,7 @@ const KURL& script_url, const Vector<uint8_t>* meta_data) override; void ExceptionThrown(ErrorEvent*) override; + mojom::RequestContextType GetDestinationForMainScript() override; // Counts the |script_size| and |cached_metadata_size| for UMA to measure the // number of scripts and the total bytes of scripts.
diff --git a/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.idl b/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.idl index 031802e5..1c8ac28 100644 --- a/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.idl +++ b/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.idl
@@ -32,7 +32,7 @@ const unsigned long VERTEX_ARRAY_BINDING_OES = 0x85B5; WebGLVertexArrayObjectOES createVertexArrayOES(); - void deleteVertexArrayOES([Default=Undefined] optional WebGLVertexArrayObjectOES? arrayObject); - boolean isVertexArrayOES([Default=Undefined] optional WebGLVertexArrayObjectOES? arrayObject); - void bindVertexArrayOES([Default=Undefined] optional WebGLVertexArrayObjectOES? arrayObject); + void deleteVertexArrayOES([DefaultValue=Undefined] optional WebGLVertexArrayObjectOES? arrayObject); + boolean isVertexArrayOES([DefaultValue=Undefined] optional WebGLVertexArrayObjectOES? arrayObject); + void bindVertexArrayOES([DefaultValue=Undefined] optional WebGLVertexArrayObjectOES? arrayObject); };
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc index 16f4d3f..e46765a 100644 --- a/third_party/blink/renderer/modules/xr/xr.cc +++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -44,19 +44,12 @@ const char kNoDevicesMessage[] = "No XR hardware found."; -/** - * Helper method to convert IDL options into Mojo options. - */ +// Helper method to convert IDL options into Mojo options. device::mojom::blink::XRSessionOptionsPtr convertIdlOptionsToMojo( - const XRSessionCreationOptions* options) { + const XRSessionCreationOptions& options) { auto session_options = device::mojom::blink::XRSessionOptions::New(); - if (options->hasImmersive()) { - session_options->immersive = options->immersive(); - } - if (options->hasEnvironmentIntegration()) { - session_options->environment_integration = - options->environmentIntegration(); - } + session_options->immersive = options.immersive(); + session_options->environment_integration = options.environmentIntegration(); return session_options; } @@ -146,7 +139,7 @@ ScriptPromise promise = resolver->Promise(); device::mojom::blink::XRSessionOptionsPtr session_options = - convertIdlOptionsToMojo(options); + convertIdlOptionsToMojo(*options); device_->SupportsSession( std::move(session_options), @@ -213,7 +206,7 @@ ScriptPromise promise = resolver->Promise(); device::mojom::blink::XRSessionOptionsPtr session_options = - convertIdlOptionsToMojo(options); + convertIdlOptionsToMojo(*options); session_options->has_user_activation = has_user_activation; XRPresentationContext* output_context =
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc index 48070037..e282da6 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -436,53 +436,84 @@ scoped_refptr<CanvasResource> resource_; }; -enum CanvasResourceType { - kDirectGpuMemoryBufferResourceType, - kTextureGpuMemoryBufferResourceType, - kBitmapGpuMemoryBufferResourceType, - kSharedBitmapResourceType, - kTextureResourceType, - kBitmapResourceType, +namespace { + +enum class CanvasResourceType { + kDirectGpuMemoryBuffer, + kTextureGpuMemoryBuffer, + kBitmapGpuMemoryBuffer, + kSharedBitmap, + kTexture, + kBitmap, }; -constexpr CanvasResourceType kSoftwareCompositedFallbackList[] = { - kBitmapGpuMemoryBufferResourceType, - kSharedBitmapResourceType, - // Fallback to no direct compositing support - kBitmapResourceType, -}; +const std::vector<CanvasResourceType>& GetResourceTypeFallbackList( + CanvasResourceProvider::ResourceUsage usage) { + static const std::vector<CanvasResourceType> kSoftwareFallbackList({ + CanvasResourceType::kBitmap, + }); -constexpr CanvasResourceType kSoftwareFallbackList[] = { - kBitmapResourceType, -}; + static const std::vector<CanvasResourceType> kAcceleratedFallbackList({ + CanvasResourceType::kTexture, + // Fallback to software + CanvasResourceType::kBitmap, + }); -constexpr CanvasResourceType kAcceleratedFallbackList[] = { - kTextureResourceType, - // Fallback to software - kBitmapResourceType, -}; + static const std::vector<CanvasResourceType> kSoftwareCompositedFallbackList({ + CanvasResourceType::kBitmapGpuMemoryBuffer, + CanvasResourceType::kSharedBitmap, + // Fallback to no direct compositing support + CanvasResourceType::kBitmap, + }); -constexpr CanvasResourceType kAcceleratedCompositedFallbackList[] = { - kTextureGpuMemoryBufferResourceType, - kTextureResourceType, - // Fallback to software composited - kBitmapGpuMemoryBufferResourceType, - kSharedBitmapResourceType, - // Fallback to no direct compositing support - kBitmapResourceType, -}; + static const std::vector<CanvasResourceType> + kAcceleratedCompositedFallbackList({ + CanvasResourceType::kTextureGpuMemoryBuffer, + CanvasResourceType::kTexture, + // Fallback to software composited + // (|kSoftwareCompositedFallbackList|). + CanvasResourceType::kBitmapGpuMemoryBuffer, + CanvasResourceType::kSharedBitmap, + // Fallback to no direct compositing support + CanvasResourceType::kBitmap, + }); + DCHECK(std::equal(kAcceleratedCompositedFallbackList.begin() + 2, + kAcceleratedCompositedFallbackList.end(), + kSoftwareCompositedFallbackList.begin(), + kSoftwareCompositedFallbackList.end())); -constexpr CanvasResourceType kAcceleratedDirectFallbackList[] = { - kDirectGpuMemoryBufferResourceType, - // The rest is equal to |kAcceleratedCompositedFallbackList|. - kTextureGpuMemoryBufferResourceType, - kTextureResourceType, - // Fallback to software composited - kBitmapGpuMemoryBufferResourceType, - kSharedBitmapResourceType, - // Fallback to no direct compositing support - kBitmapResourceType, -}; + static const std::vector<CanvasResourceType> kAcceleratedDirectFallbackList({ + CanvasResourceType::kDirectGpuMemoryBuffer, + // The rest is equal to |kAcceleratedCompositedFallbackList|. + CanvasResourceType::kTextureGpuMemoryBuffer, + CanvasResourceType::kTexture, + // Fallback to software composited + CanvasResourceType::kBitmapGpuMemoryBuffer, + CanvasResourceType::kSharedBitmap, + // Fallback to no direct compositing support + CanvasResourceType::kBitmap, + }); + DCHECK(std::equal(kAcceleratedDirectFallbackList.begin() + 1, + kAcceleratedDirectFallbackList.end(), + kAcceleratedCompositedFallbackList.begin(), + kAcceleratedCompositedFallbackList.end())); + + switch (usage) { + case CanvasResourceProvider::kSoftwareResourceUsage: + return kSoftwareFallbackList; + case CanvasResourceProvider::kSoftwareCompositedResourceUsage: + return kSoftwareCompositedFallbackList; + case CanvasResourceProvider::kAcceleratedResourceUsage: + return kAcceleratedFallbackList; + case CanvasResourceProvider::kAcceleratedCompositedResourceUsage: + return kAcceleratedCompositedFallbackList; + case CanvasResourceProvider::kAcceleratedDirectResourceUsage: + return kAcceleratedDirectFallbackList; + } + NOTREACHED(); +} + +} // unnamed namespace std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create( const IntSize& size, @@ -493,41 +524,17 @@ PresentationMode presentation_mode, base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher, bool is_origin_top_left) { - const CanvasResourceType* resource_type_fallback_list = nullptr; - size_t list_length = 0; - - switch (usage) { - case kSoftwareResourceUsage: - resource_type_fallback_list = kSoftwareFallbackList; - list_length = base::size(kSoftwareFallbackList); - break; - case kSoftwareCompositedResourceUsage: - resource_type_fallback_list = kSoftwareCompositedFallbackList; - list_length = base::size(kSoftwareCompositedFallbackList); - break; - case kAcceleratedResourceUsage: - resource_type_fallback_list = kAcceleratedFallbackList; - list_length = base::size(kAcceleratedFallbackList); - break; - case kAcceleratedCompositedResourceUsage: - resource_type_fallback_list = kAcceleratedCompositedFallbackList; - list_length = base::size(kAcceleratedCompositedFallbackList); - break; - case kAcceleratedDirectResourceUsage: - resource_type_fallback_list = kAcceleratedDirectFallbackList; - list_length = base::size(kAcceleratedDirectFallbackList); - break; - } - std::unique_ptr<CanvasResourceProvider> provider; - for (size_t i = 0; i < list_length; ++i) { + const std::vector<CanvasResourceType>& fallback_list = + GetResourceTypeFallbackList(usage); + for (CanvasResourceType resource_type : fallback_list) { // Note: We are deliberately not using std::move() on // |context_provider_wrapper| and |resource_dispatcher| to ensure that the // pointers remain valid for the next iteration of this loop if necessary. - switch (resource_type_fallback_list[i]) { - case kTextureGpuMemoryBufferResourceType: + switch (resource_type) { + case CanvasResourceType::kTextureGpuMemoryBuffer: FALLTHROUGH; - case kDirectGpuMemoryBufferResourceType: + case CanvasResourceType::kDirectGpuMemoryBuffer: if (!SharedGpuContext::IsGpuCompositingEnabled()) continue; if (presentation_mode != kAllowImageChromiumPresentationMode) @@ -547,8 +554,7 @@ DCHECK_EQ(color_params.GLUnsizedInternalFormat(), gpu::InternalFormatForGpuMemoryBufferFormat( color_params.GetBufferFormat())); - if (resource_type_fallback_list[i] == - kDirectGpuMemoryBufferResourceType) { + if (resource_type == CanvasResourceType::kDirectGpuMemoryBuffer) { provider = std::make_unique<CanvasResourceProviderDirectGpuMemoryBuffer>( size, msaa_sample_count, color_params, @@ -562,7 +568,7 @@ is_origin_top_left); } break; - case kBitmapGpuMemoryBufferResourceType: + case CanvasResourceType::kBitmapGpuMemoryBuffer: if (!SharedGpuContext::IsGpuCompositingEnabled()) continue; if (presentation_mode != kAllowImageChromiumPresentationMode) @@ -580,20 +586,20 @@ size, color_params, context_provider_wrapper, resource_dispatcher); break; - case kSharedBitmapResourceType: + case CanvasResourceType::kSharedBitmap: if (!resource_dispatcher) continue; provider = std::make_unique<CanvasResourceProviderSharedBitmap>( size, color_params, resource_dispatcher); break; - case kTextureResourceType: + case CanvasResourceType::kTexture: if (!context_provider_wrapper) continue; provider = std::make_unique<CanvasResourceProviderTexture>( size, msaa_sample_count, color_params, context_provider_wrapper, resource_dispatcher, is_origin_top_left); break; - case kBitmapResourceType: + case CanvasResourceType::kBitmap: provider = std::make_unique<CanvasResourceProviderBitmap>( size, color_params, context_provider_wrapper, resource_dispatcher); break;
diff --git a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc index 2d0437b..dc6ed8d62 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc
@@ -32,7 +32,9 @@ cc_picture_layer_->SetLayerClient(weak_ptr_factory_.GetWeakPtr()); } -ContentLayerClientImpl::~ContentLayerClientImpl() = default; +ContentLayerClientImpl::~ContentLayerClientImpl() { + cc_picture_layer_->ClearClient(); +} static int GetTransformId(const TransformPaintPropertyNode* transform, ContentLayerClientImpl::LayerAsJSONContext& context) {
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc index 67fc10fc..3e9fe96 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -656,6 +656,7 @@ CompositorElementIdFromUniqueObjectId(NewUniqueObjectId()); layer_->SetIsDrawable(true); } + ~SynthesizedClip() override { layer_->ClearClient(); } void Update(const FloatRoundedRect& rrect, scoped_refptr<const RefCountedPath> path) {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 50cb536..f0d657e 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1124,7 +1124,8 @@ // Enables the use of the RTCIceTransport with extensions. { name: "RTCIceTransportExtension", - status: "test", + origin_trial_feature_name: "RTCQuicTransport", + status: "experimental", }, { name: "RtcPeerConnectionId", @@ -1134,7 +1135,8 @@ // Enables the use of the RTCQuicTransport object. { name: "RTCQuicTransport", - status: "test", + origin_trial_feature_name: "RTCQuicTransport", + status: "experimental", }, { name: "RTCRtpSenderParameters",
diff --git a/third_party/blink/renderer/platform/text/locale_mac.mm b/third_party/blink/renderer/platform/text/locale_mac.mm index ff17c916..fdd237e 100644 --- a/third_party/blink/renderer/platform/text/locale_mac.mm +++ b/third_party/blink/renderer/platform/text/locale_mac.mm
@@ -89,7 +89,8 @@ : locale_(locale), gregorian_calendar_( kAdoptNS, - [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]), + [[NSCalendar alloc] + initWithCalendarIdentifier:NSCalendarIdentifierGregorian]), did_initialize_number_data_(false) { NSArray* available_languages = [NSLocale ISOLanguageCodes]; // NSLocale returns a lower case NSLocaleLanguageCode so we don't have care
diff --git a/third_party/blink/renderer/platform/wtf/BUILD.gn b/third_party/blink/renderer/platform/wtf/BUILD.gn index 4e9a542..4e283444 100644 --- a/third_party/blink/renderer/platform/wtf/BUILD.gn +++ b/third_party/blink/renderer/platform/wtf/BUILD.gn
@@ -16,19 +16,10 @@ config("wtf_config") { if (is_win) { - defines = [ - "__STD_C", - "_CRT_SECURE_NO_DEPRECATE", - "_SCL_SECURE_NO_DEPRECATE", - ] - cflags = [ # Don't complain about calling specific versions of templatized # functions (e.g. in RefPtrHashMap.h). "/wd4344", - - # dtoa, icu, etc. like doing assignment within conditional. - "/wd4706", ] if (is_component_build) {
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint index 2731714..e86c4ba 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint +++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
@@ -431,3 +431,5 @@ crbug.com/923429 external/wpt/css/filter-effects/backdrop-filter-fixed-clip.html [ Failure ] Bug(none) css3/filters/blur-filter-page-scroll-self.html [ Failure ] + +crbug.com/921729 paint/invalidation/compositing/composited-layer-move.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 9f13ab2..4850bed 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -4264,26 +4264,9 @@ crbug.com/881180 virtual/outofblink-cors/external/wpt/xhr/open-url-multi-window-4.htm [ Timeout ] crbug.com/881180 virtual/outofblink-cors-ns/external/wpt/xhr/open-url-multi-window-4.htm [ Timeout ] -crbug.com/655458 external/wpt/workers/constructors/SharedWorker/undefined-arguments.html [ Failure ] -crbug.com/655458 external/wpt/workers/interfaces/SharedWorkerGlobalScope/onconnect.html [ Failure ] -crbug.com/655458 external/wpt/workers/constructors/SharedWorker/setting-port-members.html [ Failure ] -crbug.com/655458 external/wpt/workers/constructors/SharedWorker/connect-event.html [ Failure ] -crbug.com/655458 external/wpt/workers/constructors/Worker/unresolvable-url.html [ Failure ] -crbug.com/655458 external/wpt/workers/semantics/run-a-worker/003.html [ Failure ] crbug.com/655458 external/wpt/workers/Worker_terminate_event_queue.htm [ Pass Timeout ] -crbug.com/655458 external/wpt/workers/constructors/SharedWorker/interface-objects.html [ Failure ] -crbug.com/655458 external/wpt/workers/constructors/SharedWorker/unresolvable-url.html [ Failure ] crbug.com/655458 external/wpt/workers/semantics/multiple-workers/007.html [ Timeout ] - -crbug.com/655458 virtual/omt-worker-fetch/external/wpt/workers/constructors/SharedWorker/undefined-arguments.html [ Failure ] -crbug.com/655458 virtual/omt-worker-fetch/external/wpt/workers/interfaces/SharedWorkerGlobalScope/onconnect.html [ Failure ] -crbug.com/655458 virtual/omt-worker-fetch/external/wpt/workers/constructors/SharedWorker/setting-port-members.html [ Failure ] -crbug.com/655458 virtual/omt-worker-fetch/external/wpt/workers/constructors/SharedWorker/connect-event.html [ Failure ] -crbug.com/655458 virtual/omt-worker-fetch/external/wpt/workers/constructors/Worker/unresolvable-url.html [ Failure ] -crbug.com/655458 virtual/omt-worker-fetch/external/wpt/workers/semantics/run-a-worker/003.html [ Failure ] crbug.com/655458 virtual/omt-worker-fetch/external/wpt/workers/Worker_terminate_event_queue.htm [ Pass Timeout ] -crbug.com/655458 virtual/omt-worker-fetch/external/wpt/workers/constructors/SharedWorker/interface-objects.html [ Failure ] -crbug.com/655458 virtual/omt-worker-fetch/external/wpt/workers/constructors/SharedWorker/unresolvable-url.html [ Failure ] crbug.com/655458 virtual/omt-worker-fetch/external/wpt/workers/semantics/multiple-workers/007.html [ Timeout ] crbug.com/910709 navigator_language/worker_navigator_language.html [ Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json index 8c0a805d..b7569cfb 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -8151,6 +8151,18 @@ {} ] ], + "css/CSS2/floats-clear/clear-on-child-with-margins-2.html": [ + [ + "/css/CSS2/floats-clear/clear-on-child-with-margins-2.html", + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], "css/CSS2/floats-clear/clear-on-child-with-margins.html": [ [ "/css/CSS2/floats-clear/clear-on-child-with-margins.html", @@ -158637,6 +158649,16 @@ {} ] ], + "feature-policy/reporting/unoptimized-image.jpg": [ + [ + {} + ] + ], + "feature-policy/reporting/unoptimized-images-reporting.html.headers": [ + [ + {} + ] + ], "feature-policy/reporting/unsized-media-reporting.html.headers": [ [ {} @@ -187527,16 +187549,6 @@ {} ] ], - "webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive-expected.txt": [ - [ - {} - ] - ], - "webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https-expected.txt": [ - [ - {} - ] - ], "webrtc/protocol/README.txt": [ [ {} @@ -190467,6 +190479,16 @@ {} ] ], + "workers/constructors/SharedWorker/connect-event-expected.txt": [ + [ + {} + ] + ], + "workers/constructors/SharedWorker/interface-objects-expected.txt": [ + [ + {} + ] + ], "workers/constructors/SharedWorker/null": [ [ {} @@ -190477,6 +190499,11 @@ {} ] ], + "workers/constructors/SharedWorker/setting-port-members-expected.txt": [ + [ + {} + ] + ], "workers/constructors/SharedWorker/shared-worker.js": [ [ {} @@ -190487,6 +190514,16 @@ {} ] ], + "workers/constructors/SharedWorker/undefined-arguments-expected.txt": [ + [ + {} + ] + ], + "workers/constructors/SharedWorker/unresolvable-url-expected.txt": [ + [ + {} + ] + ], "workers/constructors/Worker/1": [ [ {} @@ -190517,6 +190554,11 @@ {} ] ], + "workers/constructors/Worker/unresolvable-url-expected.txt": [ + [ + {} + ] + ], "workers/data-url-shared-window.html": [ [ {} @@ -190537,6 +190579,11 @@ {} ] ], + "workers/interfaces/SharedWorkerGlobalScope/onconnect-expected.txt": [ + [ + {} + ] + ], "workers/interfaces/WorkerGlobalScope/location/helper-redirect.py": [ [ {} @@ -190907,6 +190954,11 @@ {} ] ], + "workers/semantics/run-a-worker/003-expected.txt": [ + [ + {} + ] + ], "workers/semantics/xhr/001-1.xml": [ [ {} @@ -212486,6 +212538,12 @@ {} ] ], + "css/css-sizing/percentage-height-in-flexbox.html": [ + [ + "/css/css-sizing/percentage-height-in-flexbox.html", + {} + ] + ], "css/css-sizing/percentage-height-replaced-content-in-auto-cb.html": [ [ "/css/css-sizing/percentage-height-replaced-content-in-auto-cb.html", @@ -232488,6 +232546,12 @@ {} ] ], + "feature-policy/reporting/unoptimized-images-reporting.html": [ + [ + "/feature-policy/reporting/unoptimized-images-reporting.html", + {} + ] + ], "feature-policy/reporting/unsized-media-reporting.html": [ [ "/feature-policy/reporting/unsized-media-reporting.html", @@ -249247,7 +249311,9 @@ "mediacapture-streams/MediaStreamTrack-getSettings.https.html": [ [ "/mediacapture-streams/MediaStreamTrack-getSettings.https.html", - {} + { + "timeout": "long" + } ] ], "mediacapture-streams/MediaStreamTrack-id.https.html": [ @@ -263314,6 +263380,12 @@ {} ] ], + "quirks/unitless-length/excluded-properties-003.html": [ + [ + "/quirks/unitless-length/excluded-properties-003.html", + {} + ] + ], "quirks/unitless-length/limited-quirks.html": [ [ "/quirks/unitless-length/limited-quirks.html", @@ -276248,9 +276320,33 @@ {} ] ], - "signed-exchange/sxg-referrer.tentative.https.html": [ + "signed-exchange/sxg-referrer-policy-header.tentative.https.html": [ [ - "/signed-exchange/sxg-referrer.tentative.https.html", + "/signed-exchange/sxg-referrer-policy-header.tentative.https.html", + {} + ] + ], + "signed-exchange/sxg-referrer-remote-physical-remote-logical.tentative.https.html": [ + [ + "/signed-exchange/sxg-referrer-remote-physical-remote-logical.tentative.https.html", + {} + ] + ], + "signed-exchange/sxg-referrer-remote-physical-same-logical.tentative.https.html": [ + [ + "/signed-exchange/sxg-referrer-remote-physical-same-logical.tentative.https.html", + {} + ] + ], + "signed-exchange/sxg-referrer-same-physical-remote-logical.tentative.https.html": [ + [ + "/signed-exchange/sxg-referrer-same-physical-remote-logical.tentative.https.html", + {} + ] + ], + "signed-exchange/sxg-referrer-same-physical-same-logical.tentative.https.html": [ + [ + "/signed-exchange/sxg-referrer-same-physical-same-logical.tentative.https.html", {} ] ], @@ -313015,6 +313111,10 @@ "db819b548bee017ea39115099bc2358683bcf5f6", "reftest" ], + "css/CSS2/floats-clear/clear-on-child-with-margins-2.html": [ + "594fee03f48859fb15ece07cb82293297ca1d87d", + "reftest" + ], "css/CSS2/floats-clear/clear-on-child-with-margins.html": [ "f65f314a2f8aa285a001ae8c4751bc9ceb6e1115", "reftest" @@ -354447,6 +354547,10 @@ "fa95069dbf0083b0dc7095d2bb3acf20a6ccf898", "reftest" ], + "css/css-sizing/percentage-height-in-flexbox.html": [ + "f5d9d528a15b4ed445808ebd74de2c3814cb5ee1", + "testharness" + ], "css/css-sizing/percentage-height-replaced-content-in-auto-cb.html": [ "c63c490c370cc2dfe9ffe041229869d67775ac5a", "testharness" @@ -393907,6 +394011,18 @@ "21a909e1fb6d84f066f42c09488f1bef032171c9", "support" ], + "feature-policy/reporting/unoptimized-image.jpg": [ + "599137a55d710fe6b8d3052c05c81915622ea0d0", + "support" + ], + "feature-policy/reporting/unoptimized-images-reporting.html": [ + "fb27a13996a46b0e4592f4d28cc3574ae1745fb5", + "testharness" + ], + "feature-policy/reporting/unoptimized-images-reporting.html.headers": [ + "10b41235409ea38507d9ffe29a18547174351cc3", + "support" + ], "feature-policy/reporting/unsized-media-reporting.html": [ "bb81a496ca5b8128b7438e6f1dd4ed0dd574238c", "testharness" @@ -398488,7 +398604,7 @@ "testharness" ], "html/browsers/history/the-location-interface/no-browsing-context.window-expected.txt": [ - "2a8862a3d020f71e2ebc8e59f52c2dff0eab938b", + "12dc8bca01799883ee0800e88e50b31ffb54fbea", "support" ], "html/browsers/history/the-location-interface/no-browsing-context.window.js": [ @@ -416676,7 +416792,7 @@ "support" ], "interfaces/IndexedDB.idl": [ - "137528c148ae434141eb72e9720bd9e3eaf04a30", + "868338b3080ccad6195c5764e6b70eb4854a93c3", "support" ], "interfaces/InputDeviceCapabilities.idl": [ @@ -416972,7 +417088,7 @@ "support" ], "interfaces/mediastream-recording.idl": [ - "5bf661e6cc5e2141181fef1f01eafa6e4da82248", + "0be0538d1227147930cb03c52391cce7497eb2e4", "support" ], "interfaces/mst-content-hint.idl": [ @@ -418648,7 +418764,7 @@ "support" ], "mediacapture-record/idlharness.window-expected.txt": [ - "ba8977f2c11c91f14b5badc691871e64ee213e93", + "743e4725f34b4b2945b20d468da3f8569fb116b4", "support" ], "mediacapture-record/idlharness.window.js": [ @@ -418820,7 +418936,7 @@ "testharness" ], "mediacapture-streams/MediaStreamTrack-getSettings.https.html": [ - "158c9014617744c7181fba4862bdb7ce7e672b9d", + "c062205f0d4bb6706170c07f0d58d4a63cdb7bca", "testharness" ], "mediacapture-streams/MediaStreamTrack-id.https.html": [ @@ -429088,7 +429204,7 @@ "support" ], "payment-request/MerchantValidationEvent/constructor.https.html": [ - "ec8a4ff1ed0925a354f2631d8459337e47ab079d", + "2978226f3cc31cc7433d3fb94927a04eb5b83f0d", "testharness" ], "payment-request/OWNERS": [ @@ -429096,7 +429212,7 @@ "support" ], "payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html": [ - "edde533be6b2e49415b81ae4df167139117a0d7c", + "45f3f0a5672cf64501718aa43dc5aac87249bab9", "manual" ], "payment-request/PaymentCurrencyAmount/currencySystem-member.https-expected.txt": [ @@ -429120,31 +429236,31 @@ "testharness" ], "payment-request/PaymentRequestUpdateEvent/constructor.https.html": [ - "fd66493bf4f2aa006e99198094d1b7afd34f4543", + "e8df7b35a94280a6c71d7d8ac6f1452904535df2", "testharness" ], "payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html": [ - "cd928d4be1d8609a34d06e0a960306fc95b84e32", + "28dfe1e448baea444698f38a20c70ff38e9d312a", "manual" ], "payment-request/PaymentRequestUpdateEvent/updateWith-duplicate-shipping-options-manual.https.html": [ - "40ba3057e0cb10412df759516ee19392ae70f1c3", + "fbf97d855ab82d8ee661f3deed9f1198698362ad", "manual" ], "payment-request/PaymentRequestUpdateEvent/updateWith-incremental-update-manual.https.html": [ - "3d1bfb41b84d6b0ecc2d4bde25eab2dead465e34", + "c1ed1b5f6850c7f26566ffb6e98b06ea51739e15", "manual" ], "payment-request/PaymentRequestUpdateEvent/updateWith-method-abort-update-manual.https.html": [ - "0ff7f23b6479695907aee3e479436b5ff13e165a", + "cf0bb289d73bf7168b93a19b81144d66349f5e95", "manual" ], "payment-request/PaymentRequestUpdateEvent/updateWith-state-checks-manual.https.html": [ - "4d4ef73949dd1dd271521c5005ca4e93108ab844", + "c5737aa8c31e31f5312135d9de84f82277806c50", "manual" ], "payment-request/PaymentRequestUpdateEvent/updatewith-method.https.html": [ - "adacdf3f06d1c1adb50a65585b64441c5e00de63", + "17a4741cdf97bd6dca6716c80a890af283f4a68a", "testharness" ], "payment-request/PaymentValidationErrors/retry-shows-error-member-manual.https.html": [ @@ -429156,11 +429272,11 @@ "manual" ], "payment-request/PaymentValidationErrors/retry-shows-shippingAddress-member-manual.https.html": [ - "356f30da6b54bef4136a2b3a806313bf4bb1f766", + "c3e2ba713223c94689d4549aa90008fe91faeb7c", "manual" ], "payment-request/algorithms-manual.https.html": [ - "5494353c6bceb4ed0d388852bd7f426e5715186d", + "6744649612576cb5006b76ee34182bd00eed754e", "manual" ], "payment-request/allowpaymentrequest/active-document-cross-origin.https.sub.html": [ @@ -429224,7 +429340,7 @@ "testharness" ], "payment-request/billing-address-changed-manual.https.html": [ - "cb9acf6eb6a20df5ddd03ef734796cefb6195467", + "ccfeb6fd364c759131022c96576c9289adb0c0ee", "manual" ], "payment-request/blank.html": [ @@ -429232,11 +429348,11 @@ "support" ], "payment-request/change-shipping-option-manual.https.html": [ - "a33365bac73ed51b6873215d0f54d79a73422163", + "438001804acdaca21410ce0d367a8208cac60aff", "manual" ], "payment-request/change-shipping-option-select-last-manual.https.html": [ - "f08491150ac7ee6d69520a936eb2868d60393c57", + "4ad31d65317338f0474c24e6e35688eb8f2b4cbe", "manual" ], "payment-request/constructor_convert_method_data.https-expected.txt": [ @@ -429248,11 +429364,11 @@ "testharness" ], "payment-request/historical.https-expected.txt": [ - "4dbafb7749ea64069e1fef206604284ddde93505", + "34cd1710caca9a6d09c9f1a14889980db40e34ab", "support" ], "payment-request/historical.https.html": [ - "cbd29d4cff8698365c05acfe75504de5ec7e1aec", + "e681f6486b9bdd46d7420cac15855dc9acaa2ca7", "testharness" ], "payment-request/idlharness.https.window-expected.txt": [ @@ -429272,11 +429388,11 @@ "support" ], "payment-request/onmerchantvalidation-attribute.https.html": [ - "c0ed23167ed9378ec32e769bd4f3e3afaef5040c", + "d31ac2dd72abcf51a28ecec850400f5f0c6b9bb5", "testharness" ], "payment-request/onpaymentmenthodchange-attribute.https.html": [ - "0484eb868f983e3cdb0efceab5fe2b3c6084b4ab", + "f641bec4aa91d8be4f1801869eb699ca4bad03a0", "testharness" ], "payment-request/payment-is-showing.https-expected.txt": [ @@ -429292,7 +429408,7 @@ "support" ], "payment-request/payment-request-abort-method.https.html": [ - "8e561b288d15fa30971dd1f88b930671c83a5887", + "75e39a011c390fb8c3bbbeba2dbe8826ea6291e1", "testharness" ], "payment-request/payment-request-canmakepayment-method-protection.https-expected.txt": [ @@ -429300,7 +429416,7 @@ "support" ], "payment-request/payment-request-canmakepayment-method-protection.https.html": [ - "b0582d520d306760d75754779de1ceef1d064a92", + "e221034dd4ebd05c5bd701e05a81895b8457c3b7", "testharness" ], "payment-request/payment-request-canmakepayment-method.https-expected.txt": [ @@ -429308,11 +429424,11 @@ "support" ], "payment-request/payment-request-canmakepayment-method.https.html": [ - "f38caa00b9313dc80f5ab5180dc10e850eb57147", + "672e5ce1571435e9f16b8010456e859f12d2c9c4", "testharness" ], "payment-request/payment-request-constructor-crash.https.html": [ - "1325681a4acf6841b67b2dd40d20cf0dcc449d8f", + "9763615bdd186d0a8a656af8a89bfdf8bbfac186", "testharness" ], "payment-request/payment-request-constructor.https.html": [ @@ -429340,11 +429456,11 @@ "testharness" ], "payment-request/payment-request-onshippingaddresschange-attribute.https.html": [ - "5c54d48568a40781df857986bcda5fc8ab08189b", + "5b2538992f76c774259f52b734bc844468fc14f7", "testharness" ], "payment-request/payment-request-onshippingoptionchange-attribute.https.html": [ - "a4d8fbc4825f8e797f9478d8bdd089e4391491a9", + "43ea5dcce87afe9dff0387891d57c3265be303f5", "testharness" ], "payment-request/payment-request-shippingAddress-attribute.https.html": [ @@ -429356,11 +429472,11 @@ "testharness" ], "payment-request/payment-request-shippingType-attribute.https.html": [ - "b1ed0d028860ea9c98dd1a61ba239db75a7e3864", + "11f75b1c862224b5655cb724d8c8f5b25ab1af00", "testharness" ], "payment-request/payment-request-show-method.https.html": [ - "c6e69d4c587602d51602aea41224731e692af2ae", + "3d362596c41c6f6ac7058e752c6c6f0e4f6b3781", "testharness" ], "payment-request/payment-response/complete-method-manual.https.html": [ @@ -429368,7 +429484,7 @@ "manual" ], "payment-request/payment-response/helpers.js": [ - "807f794e71efb35f8622eb0aa478ae6a6039c260", + "3e4f5cfd36f898c116717c1151806f966511a945", "support" ], "payment-request/payment-response/methodName-attribute-manual.https.html": [ @@ -429396,7 +429512,7 @@ "manual" ], "payment-request/payment-response/rejects_if_not_active-manual.https.html": [ - "60dd9655dd5bafcdb7768b929696cb9104214b29", + "516573c581a0a047a2f9b9a89d027568f8567c05", "manual" ], "payment-request/payment-response/requestId-attribute-manual.https.html": [ @@ -429420,7 +429536,7 @@ "support" ], "payment-request/rejects_if_not_active.https.html": [ - "f585e836f8d30e41bd33c7a8d8760ecf64f7a80d", + "06c1f7383a045d7ffd386cb6aec57d6010843d31", "testharness" ], "payment-request/resources/page1.html": [ @@ -429432,35 +429548,35 @@ "support" ], "payment-request/shipping-address-changed-manual.https.html": [ - "07b530657c339434aa924d1dfe96814fad2dbf3b", + "711ba2743601348594efd129f74f79fd89b4432a", "manual" ], "payment-request/show-method-optional-promise-rejects-manual.https.html": [ - "5c1028eec667c8573df890d201d1f1b9136dde57", + "172413ff59811ec38c2a7b23629fe3f4afa53785", "manual" ], "payment-request/show-method-optional-promise-resolves-manual.https.html": [ - "70c97faaf7a4496982a382a415e3a85e9a17c465", + "d41b1b39c988d68f26ee419c94dd549895ccbf13", "manual" ], "payment-request/show-method-postmessage-iframe.html": [ - "12a1e0cef82886f0514cae56eb9f4e11321ab5de", + "b50f18ecce3ac62d3193a86d668f457c1e9629ab", "support" ], "payment-request/show-method-postmessage-manual.https.html": [ - "e4ab550e4189e1518a4b601aa4c9e249df4c5ecd", + "05fce4f248e8ff116065988d1d4d3d2875967ce5", "manual" ], "payment-request/updateWith-method-pmi-handling-manual.https.html": [ - "06852bf8c47cb9e720190b9b0e2f81d9e7ddd335", + "8bab88212bab51ea771a0fc2a81a1a9e7ee6e0d1", "manual" ], "payment-request/user-abort-algorithm-manual.https.html": [ - "0ba0405c52fbd5805a36d2707618dc84a7111351", + "007fb681cebb494de5fb8ed5acf6c4c82920f1fe", "manual" ], "payment-request/user-accepts-payment-request-algo-manual.https.html": [ - "abaf6cb4e8580df5c6034e8b137ae8fc343067a6", + "3d7b8a08ebb34b2517e4bef4b746762b024d56e9", "manual" ], "performance-timeline/META.yml": [ @@ -430724,13 +430840,17 @@ "reftest" ], "quirks/unitless-length/excluded-properties-001.html": [ - "2e33cec0b33644576fb81e6fd9dbaf42bb02cf92", + "09fedcf6018a673d22f397936a0c6d25ae7fd9ae", "testharness" ], "quirks/unitless-length/excluded-properties-002.html": [ "5f98bc283ebc2b5d719815c59c3d1cd53acd2ed9", "testharness" ], + "quirks/unitless-length/excluded-properties-003.html": [ + "4cbe012a55e25510f5674875dddb6fb1fcb7173d", + "testharness" + ], "quirks/unitless-length/limited-quirks.html": [ "fab0b3b805bad3670ffce46f627ad4134c55a027", "testharness" @@ -440432,7 +440552,7 @@ "support" ], "resources/testharness.js": [ - "ed3ffb425a85cb8fabd8bba0d7a0a4f7b46437cd", + "fb86c580d22ca14159b19b21a55b2cabfc76a742", "support" ], "resources/testharness.js.headers": [ @@ -445060,7 +445180,7 @@ "support" ], "signed-exchange/resources/sxg-util.js": [ - "0d0e263fd620584b64b059fef1d11f315f4c2423", + "7d592ea21431802655ce3134d50718ef37394a42", "support" ], "signed-exchange/resources/sxg-version1b2.sxg": [ @@ -445175,8 +445295,24 @@ "5b60ab9e1a12e2b169c4972c422ddbe3ebc5f581", "testharness" ], - "signed-exchange/sxg-referrer.tentative.https.html": [ - "3be9b1ff9b430e986dc8784a680b11659ab480fa", + "signed-exchange/sxg-referrer-policy-header.tentative.https.html": [ + "5dff6af8cb08c665622b2c44437d6a51c537f4fc", + "testharness" + ], + "signed-exchange/sxg-referrer-remote-physical-remote-logical.tentative.https.html": [ + "c2870fdd0afce54e66f19ceb0b88deb898cf5787", + "testharness" + ], + "signed-exchange/sxg-referrer-remote-physical-same-logical.tentative.https.html": [ + "b3c77d14273f2cca42c078862f2bae5be4d38690", + "testharness" + ], + "signed-exchange/sxg-referrer-same-physical-remote-logical.tentative.https.html": [ + "8a6cdd993af3aa0e8b047c94512454de76b35a8e", + "testharness" + ], + "signed-exchange/sxg-referrer-same-physical-same-logical.tentative.https.html": [ + "88917167b9c8ffcf0e08a24cf09cbf76381623a3", "testharness" ], "signed-exchange/sxg-utf8-inner-url.tentative.html": [ @@ -450248,7 +450384,7 @@ "testharness" ], "web-locks/signal.tentative.https.any.js": [ - "5b8acbbbebc52aa5da651a28dc57a1f0222be109", + "e0b6e4eabd6138fd05784d0e52cc416d62f811d0", "testharness" ], "web-locks/steal.tentative.https.any.js": [ @@ -452152,7 +452288,7 @@ "support" ], "webrtc-quic/RTCQuicTransport.https.html": [ - "c64ed6af093c690ece59a5c68e949c4ae4f5e6af", + "82427e67cb4ab231f91d6e7d04bd25f79e5f94fa", "testharness" ], "webrtc-stats/META.yml": [ @@ -452791,18 +452927,10 @@ "5a35ebc53b8d7ce3857d4869a476e0e99a9078c8", "testharness" ], - "webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive-expected.txt": [ - "9714f8a864ea37f20d58ebe6013461a56dd8d268", - "support" - ], "webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html": [ "f710498e75f1be587c66d1d0dfe215cb136cc747", "testharness" ], - "webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https-expected.txt": [ - "0485f08a86317e6dd2cf68b9de93ec35459635e8", - "support" - ], "webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html": [ "9addb0098734320e98404e7911a920b6b85f2752", "testharness" @@ -457811,6 +457939,10 @@ "258eed05bf8ccbb21ba9f76ce91c998cec0f6b20", "testharness" ], + "workers/constructors/SharedWorker/connect-event-expected.txt": [ + "e9908f24abd3ebcb146b0024ed640785ec33439f", + "support" + ], "workers/constructors/SharedWorker/connect-event.html": [ "a9719d9dea651f75858e652389ae905a4d1b2a32", "testharness" @@ -457831,6 +457963,10 @@ "1396dc7b0ba1c5e50edc14faed1989206aa194c8", "testharness" ], + "workers/constructors/SharedWorker/interface-objects-expected.txt": [ + "9ac653aec3e7b20ee3125c159716f3469b6c2e11", + "support" + ], "workers/constructors/SharedWorker/interface-objects.html": [ "e91b2dc6a8c61f0f050ecafdca7c2411116ab89d", "testharness" @@ -457875,6 +458011,10 @@ "4addaec741b6023f43bc82c3b1c798767ff51858", "testharness" ], + "workers/constructors/SharedWorker/setting-port-members-expected.txt": [ + "312273341fa76ff2a6c097af9d14b23cc6c5a940", + "support" + ], "workers/constructors/SharedWorker/setting-port-members.html": [ "8c79ff295e536a8c01bd1866bdfdcc3515f2fcd9", "testharness" @@ -457887,6 +458027,10 @@ "3fe840d304285a8872d5b0c6dbf288ca4ec94642", "support" ], + "workers/constructors/SharedWorker/undefined-arguments-expected.txt": [ + "83e9421c158936d4a319f1239fd09a3e284000ad", + "support" + ], "workers/constructors/SharedWorker/undefined-arguments.html": [ "b9a3b3692c349d6b17191d961d3744080d08ceab", "testharness" @@ -457895,6 +458039,10 @@ "39739022d7ef4039608e8f83457e5204d82c8778", "testharness" ], + "workers/constructors/SharedWorker/unresolvable-url-expected.txt": [ + "4f92dcfdb9c43983363181ec73ebd029206da577", + "support" + ], "workers/constructors/SharedWorker/unresolvable-url.html": [ "2ca3d93d3e8fa2a16a557370fe85bca3952e1713", "testharness" @@ -457971,6 +458119,10 @@ "69d29b2297847124206b392fea67949106a8a3fe", "testharness" ], + "workers/constructors/Worker/unresolvable-url-expected.txt": [ + "f6e2da6493fce113e82a939cad82cc656d774c3a", + "support" + ], "workers/constructors/Worker/unresolvable-url.html": [ "8c04b0087839808e98f66b79797e38a2e58912f6", "testharness" @@ -458091,6 +458243,10 @@ "a3511263d5e86df633fd341013934c566b8e4678", "testharness" ], + "workers/interfaces/SharedWorkerGlobalScope/onconnect-expected.txt": [ + "23667a0f61a7985e3ceef4cefac4f64eb278e53e", + "support" + ], "workers/interfaces/SharedWorkerGlobalScope/onconnect.html": [ "2ad155bf7a933c14241bdc4c112ebcae42898eff", "testharness" @@ -458743,6 +458899,10 @@ "3617ad7272afe46249d0a7ad57128819fd0b2528", "testharness" ], + "workers/semantics/run-a-worker/003-expected.txt": [ + "efe31fbe8a9c2d9d50f17aa98cd09f161893418d", + "support" + ], "workers/semantics/run-a-worker/003.html": [ "8c2f07ee7305a7a6d83e3c2cd8aaf4367fac35ab", "testharness"
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/clear-on-child-with-margins-2.html b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/clear-on-child-with-margins-2.html new file mode 100644 index 0000000..594fee03 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/clear-on-child-with-margins-2.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<title>Child of block with clear</title> +<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#flow-control" title="9.5.2 Controlling flow next to floats: the 'clear' property"> +<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html"> +<p>Test passes if there is a filled green square.</p> +<div style="width: 100px;background: red;overflow: hidden;"> + <div style="float: right; height: 20px; width: 50%; background: green;"></div> + <div> + <div style="float: left; height:100px; width: 50%; background: green;"></div> + <div> + <div style="clear: right; height: 80px; margin-top: 16px; background: green;"></div> + </div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-tree-abiding-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-pseudo-elements-expected.txt similarity index 66% rename from third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-tree-abiding-expected.txt rename to third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-pseudo-elements-expected.txt index 129e043..8e2a02f 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-tree-abiding-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-pseudo-elements-expected.txt
@@ -2,5 +2,8 @@ PASS ::before in selected host is styled PASS ::after in selected host is styled FAIL ::placeholder in selected host is styled assert_equals: expected "rgb(0, 128, 0)" but got "rgb(0, 0, 0)" +PASS ::selection in selected host is styled +PASS ::first-line in selected host is styled +PASS ::first-letter in selected host is styled Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-pseudo-elements.html b/third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-pseudo-elements.html new file mode 100644 index 0000000..776ab2e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-pseudo-elements.html
@@ -0,0 +1,86 @@ +<!DOCTYPE html> +<html> + <head> + <title>CSS Shadow Parts - Interaction with pseudo-elements</title> + <meta href="mailto:fergal@chromium.org" rel="author" title="Fergal Daly"> + <link href="http://www.google.com/" rel="author" title="Google"> + <link href="https://drafts.csswg.org/css-shadow-parts/" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="support/shadow-helper.js"></script> + </head> + <body> + <style> + #c-e::part(before-p)::before { color: green; } + #c-e::part(after-p)::after { color: green; } + #c-e::part(placeholder-p)::placeholder { color: green; } + #c-e::part(selection-p)::selection { color: green; } + #c-e::part(first-line-p)::first-line { color: green; } + #c-e::part(first-letter-p)::first-letter { color: green; } + </style> + <script>installCustomElement("custom-element", "custom-element-template");</script> + <template id="custom-element-template"> + <style> + #before-i::before { content: "this text"; color: red; } + #after-i::after { content: "this text"; color: red; } + #placeholder-i::placeholder { color: red; } + #selection-i::selection { color: red; } + #first-line-i::first-line { color: red; } + #first-letter-i::first-letter { color: red; } + </style> + <div> + The following text should be green: + <span id="before-i" part="before-p"></span> + </div> + <div> + The following text should be green: + <span id="after-i" part="after-p"></span> + </div> + <div> + The following text should be green: + <input id="placeholder-i" part="placeholder-p" placeholder="this text"></input> + </div> + <div> + The selected text should be green: + <div id="selection-i" part="selection-p">select some text</div> + </div> + <div> + The following text should be green: + <div id="first-line-i" part="first-line-p">this text<br>Not this</div> + </div> + <div> + The first letter should be green: + <div id="first-letter-i" part="first-letter-p"><p>this text</p></div> + </div> + </template> + <custom-element id="c-e"></custom-element> + <script> + "use strict"; + const colorGreen = "rgb(0, 128, 0)"; + test(function() { + const el = getElementByShadowIds(document, ["c-e", "before-i"]); + assert_equals(window.getComputedStyle(el, '::before').color, colorGreen); + }, "::before in selected host is styled"); + test(function() { + const el = getElementByShadowIds(document, ["c-e", "after-i"]); + assert_equals(window.getComputedStyle(el, '::after').color, colorGreen); + }, "::after in selected host is styled"); + test(function() { + const el = getElementByShadowIds(document, ["c-e", "placeholder-i"]); + assert_equals(window.getComputedStyle(el, '::placeholder').color, colorGreen); + }, "::placeholder in selected host is styled"); + test(function() { + const el = getElementByShadowIds(document, ["c-e", "selection-i"]); + assert_equals(window.getComputedStyle(el, '::selection').color, colorGreen); + }, "::selection in selected host is styled"); + test(function() { + const el = getElementByShadowIds(document, ["c-e", "first-line-i"]); + assert_equals(window.getComputedStyle(el, '::first-line').color, colorGreen); + }, "::first-line in selected host is styled"); + test(function() { + const el = getElementByShadowIds(document, ["c-e", "first-letter-i"]); + assert_equals(window.getComputedStyle(el, '::first-letter').color, colorGreen); + }, "::first-letter in selected host is styled"); + </script> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-tree-abiding.html b/third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-tree-abiding.html deleted file mode 100644 index c11da7d..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-shadow-parts/interaction-with-tree-abiding.html +++ /dev/null
@@ -1,56 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>CSS Shadow Parts - Interaction with tree-abiding</title> - <meta href="mailto:fergal@chromium.org" rel="author" title="Fergal Daly"> - <link href="http://www.google.com/" rel="author" title="Google"> - <link href="https://drafts.csswg.org/css-shadow-parts/" rel="help"> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="support/shadow-helper.js"></script> - </head> - <body> - <style> - #c-e::part(before-p)::before { color: green; } - #c-e::part(after-p)::after { color: green; } - #c-e::part(placeholder-p)::placeholder { color: green; } - </style> - <script>installCustomElement("custom-element", "custom-element-template");</script> - <template id="custom-element-template"> - <style> - #before-i::before { content: "this text"; color: red; } - #after-i::after { content: "this text"; color: red; } - #placeholder-i::placeholder { color: red; } - </style> - <div> - The following text should be green: - <span id="before-i" part="before-p"></span> - </div> - <div> - The following text should be green: - <span id="after-i" part="after-p"></span> - </div> - <div> - The following text should be green: - <input id="placeholder-i" part="placeholder-p" placeholder="this text"></input> - </div> - </template> - <custom-element id="c-e"></custom-element> - <script> - "use strict"; - const colorGreen = "rgb(0, 128, 0)"; - test(function() { - const el = getElementByShadowIds(document, ["c-e", "before-i"]); - assert_equals(window.getComputedStyle(el, '::before').color, colorGreen); - }, "::before in selected host is styled"); - test(function() { - const el = getElementByShadowIds(document, ["c-e", "after-i"]); - assert_equals(window.getComputedStyle(el, '::after').color, colorGreen); - }, "::after in selected host is styled"); - test(function() { - const el = getElementByShadowIds(document, ["c-e", "placeholder-i"]); - assert_equals(window.getComputedStyle(el, '::placeholder').color, colorGreen); - }, "::placeholder in selected host is styled"); - </script> - </body> -</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/percentage-height-in-flexbox.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/percentage-height-in-flexbox.html new file mode 100644 index 0000000..f5d9d52 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/percentage-height-in-flexbox.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<title>Percentage height in flexbox: css-sizing-3</title> +<link rel="author" title="mailto:atotic@google.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://www.w3.org/TR/css-sizing-3/#percentage-sizing"> +<link rel="help" href="https://crbug.com/907911"> +<meta name="assert" content="Percentage height resolves correctly inside flexbox."> +<style> +#outer { + width: 100px; + height: 100px; + background: red; +} +#container { + display: inline-flex; + height: 50px; + background: green; +} +#target { + height:100%; + display:block; +} +</style> +<div id="outer"> + <div id="container"> + <img id="target" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"> + </div> +</div> +<script> +test(() => { + let target = document.querySelector("#target"); + assert_equals(target.offsetWidth, target.offsetHeight); + assert_equals(target.offsetWidth, target.parentNode.offsetWidth); + assert_equals(target.offsetHeight, target.parentNode.offsetHeight); +}, '#target offsetSize matches #container offsetSize' ); +test(() => { + document.querySelector("#container").style.height = "100px"; + let target = document.querySelector("#target"); + assert_equals(target.offsetWidth, target.offsetHeight); + assert_equals(target.offsetWidth, target.parentNode.offsetWidth); + assert_equals(target.offsetHeight, target.parentNode.offsetHeight); +}, '#target offsetSize matches #container offsetSize after resize' ); + +</script>
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-image.jpg b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-image.jpg new file mode 100644 index 0000000..599137a5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-image.jpg Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-images-reporting.html b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-images-reporting.html new file mode 100644 index 0000000..fb27a139 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-images-reporting.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html> + <head> + <script src='/resources/testharness.js'></script> + <script src='/resources/testharnessreport.js'></script> + </head> + <body> + <img src="./unoptimized-image.jpg"> + <script> +var check_report_format = (reports, observer) => { + let report = reports[0]; + assert_equals(report.type, "feature-policy-violation"); + assert_equals(report.url, document.location.href); + assert_equals(report.body.featureId, "unoptimized-images"); + assert_equals(report.body.disposition, "enforce"); +}; + +async_test(t => { + new ReportingObserver(t.step_func_done(check_report_format), + {types: ['feature-policy-violation'], buffered: true}).observe(); +}, "unoptimized-images Report Format"); + </script> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-images-reporting.html.headers b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-images-reporting.html.headers new file mode 100644 index 0000000..10b41235 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/unoptimized-images-reporting.html.headers
@@ -0,0 +1 @@ +Feature-Policy: unoptimized-images 'none'
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/no-browsing-context.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/no-browsing-context.window-expected.txt index 2a8862a3..12dc8bc 100644 --- a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/no-browsing-context.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/no-browsing-context.window-expected.txt
@@ -23,13 +23,13 @@ FAIL Setting `hash` to `test` of a `Location` object sans browsing context is a no-op assert_equals: expected (string) "" but got (undefined) undefined FAIL Setting `hash` to `#` of a `Location` object sans browsing context is a no-op assert_equals: expected (string) "" but got (undefined) undefined FAIL Getting `origin` of a `Location` object sans browsing context should be "null" assert_equals: expected (string) "null" but got (undefined) undefined -FAIL Invoking `assign` with `about:blank` on a `Location` object sans browsing context is a no-op assert_equals: expected (string) "about:blank" but got (undefined) undefined -FAIL Invoking `assign` with `https://example.com/` on a `Location` object sans browsing context is a no-op assert_equals: expected (string) "about:blank" but got (undefined) undefined -FAIL Invoking `assign` with `/` on a `Location` object sans browsing context is a no-op assert_equals: expected (string) "about:blank" but got (undefined) undefined -FAIL Invoking `assign` with `http://test:test/` on a `Location` object sans browsing context is a no-op assert_equals: expected (string) "about:blank" but got (undefined) undefined -FAIL Invoking `assign` with `test test` on a `Location` object sans browsing context is a no-op assert_equals: expected (string) "about:blank" but got (undefined) undefined -FAIL Invoking `assign` with `test:test` on a `Location` object sans browsing context is a no-op assert_equals: expected (string) "about:blank" but got (undefined) undefined -FAIL Invoking `assign` with `chrome:fail` on a `Location` object sans browsing context is a no-op assert_equals: expected (string) "about:blank" but got (undefined) undefined +FAIL Invoking `assign` with `about:blank` on a `Location` object sans browsing context is a no-op loc[method] is not a function +FAIL Invoking `assign` with `https://example.com/` on a `Location` object sans browsing context is a no-op loc[method] is not a function +FAIL Invoking `assign` with `/` on a `Location` object sans browsing context is a no-op loc[method] is not a function +FAIL Invoking `assign` with `http://test:test/` on a `Location` object sans browsing context is a no-op loc[method] is not a function +FAIL Invoking `assign` with `test test` on a `Location` object sans browsing context is a no-op loc[method] is not a function +FAIL Invoking `assign` with `test:test` on a `Location` object sans browsing context is a no-op loc[method] is not a function +FAIL Invoking `assign` with `chrome:fail` on a `Location` object sans browsing context is a no-op loc[method] is not a function FAIL Invoking `replace` with `about:blank` on a `Location` object sans browsing context is a no-op assert_equals: expected (string) "about:blank" but got (undefined) undefined FAIL Invoking `replace` with `https://example.com/` on a `Location` object sans browsing context is a no-op assert_equals: expected (string) "about:blank" but got (undefined) undefined FAIL Invoking `replace` with `/` on a `Location` object sans browsing context is a no-op assert_equals: expected (string) "about:blank" but got (undefined) undefined
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/IndexedDB.idl b/third_party/blink/web_tests/external/wpt/interfaces/IndexedDB.idl index 137528c..868338b3 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/IndexedDB.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/IndexedDB.idl
@@ -200,6 +200,7 @@ readonly attribute DOMException error; IDBObjectStore objectStore(DOMString name); + void commit(); void abort(); // Event handlers:
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/mediastream-recording.idl b/third_party/blink/web_tests/external/wpt/interfaces/mediastream-recording.idl index 5bf661e..0be0538 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/mediastream-recording.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/mediastream-recording.idl
@@ -18,7 +18,7 @@ readonly attribute unsigned long videoBitsPerSecond; readonly attribute unsigned long audioBitsPerSecond; - void start(optional long timeslice); + void start(optional unsigned long timeslice); void stop(); void pause(); void resume();
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-record/idlharness.window-expected.txt b/third_party/blink/web_tests/external/wpt/mediacapture-record/idlharness.window-expected.txt index ba8977f..743e472 100644 --- a/third_party/blink/web_tests/external/wpt/mediacapture-record/idlharness.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/mediacapture-record/idlharness.window-expected.txt
@@ -18,7 +18,7 @@ PASS MediaRecorder interface: attribute onerror PASS MediaRecorder interface: attribute videoBitsPerSecond PASS MediaRecorder interface: attribute audioBitsPerSecond -PASS MediaRecorder interface: operation start(long) +PASS MediaRecorder interface: operation start(unsigned long) PASS MediaRecorder interface: operation stop() PASS MediaRecorder interface: operation pause() PASS MediaRecorder interface: operation resume() @@ -37,8 +37,8 @@ PASS MediaRecorder interface: [object MediaRecorder] must inherit property "onerror" with the proper type PASS MediaRecorder interface: [object MediaRecorder] must inherit property "videoBitsPerSecond" with the proper type PASS MediaRecorder interface: [object MediaRecorder] must inherit property "audioBitsPerSecond" with the proper type -PASS MediaRecorder interface: [object MediaRecorder] must inherit property "start(long)" with the proper type -PASS MediaRecorder interface: calling start(long) on [object MediaRecorder] with too few arguments must throw TypeError +PASS MediaRecorder interface: [object MediaRecorder] must inherit property "start(unsigned long)" with the proper type +PASS MediaRecorder interface: calling start(unsigned long) on [object MediaRecorder] with too few arguments must throw TypeError PASS MediaRecorder interface: [object MediaRecorder] must inherit property "stop()" with the proper type PASS MediaRecorder interface: [object MediaRecorder] must inherit property "pause()" with the proper type PASS MediaRecorder interface: [object MediaRecorder] must inherit property "resume()" with the proper type
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getSettings.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getSettings.https.html index 158c901..c062205f 100644 --- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getSettings.https.html +++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getSettings.https.html
@@ -1,6 +1,7 @@ <!doctype html> <title>MediaStreamTrack GetSettings</title> <p class="instructions">When prompted, accept to share your video stream.</p> +<meta name=timeout content=long> <script src=/resources/testharness.js></script> <script src=/resources/testharnessreport.js></script> <script>
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/MerchantValidationEvent/constructor.https.html b/third_party/blink/web_tests/external/wpt/payment-request/MerchantValidationEvent/constructor.https.html index ec8a4ff1..2978226 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/MerchantValidationEvent/constructor.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/MerchantValidationEvent/constructor.https.html
@@ -8,6 +8,13 @@ <script> const applePay = Object.freeze({ supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } }); const basicCard = Object.freeze({ supportedMethods: "basic-card" }); const defaultMethods = Object.freeze([basicCard, applePay]);
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html index edde533..45f3f0a5 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html
@@ -68,7 +68,6 @@ <button onclick=" const expectedAddress = { country: 'AU', - regionCode: 'QLD', addressLine: '55 test st', city: 'Chapel Hill', dependentLocality: '',
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/constructor.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/constructor.https.html index fd66493..e8df7b35 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/constructor.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/constructor.https.html
@@ -6,8 +6,18 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const basicCard = Object.freeze({ supportedMethods: "basic-card" }); -const defaultMethods = Object.freeze([basicCard]); +const defaultMethods = Object.freeze([basicCard, applePay]); const defaultDetails = Object.freeze({ total: { label: "Total",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html index cd928d4..28dfe1e4 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html
@@ -9,8 +9,18 @@ <script src="/resources/testharnessreport.js"></script> <script> setup({ explicit_done: true, explicit_timeout: true }); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const validMethod = Object.freeze({ supportedMethods: "basic-card" }); -const validMethods = Object.freeze([validMethod]); +const validMethods = Object.freeze([validMethod, applePay]); const validAmount = Object.freeze({ currency: "USD", value: "5.00" }); const validTotal = Object.freeze({ label: "label",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-duplicate-shipping-options-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-duplicate-shipping-options-manual.https.html index 40ba305..fbf97d85 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-duplicate-shipping-options-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-duplicate-shipping-options-manual.https.html
@@ -8,9 +8,18 @@ <script src="/resources/testharnessreport.js"></script> <script> setup({ explicit_done: true, explicit_timeout: true }); - +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const validMethod = Object.freeze({ supportedMethods: "basic-card" }); -const validMethods = [validMethod]; +const validMethods = [validMethod, applePay]; const validAmount = Object.freeze({ currency: "USD", value: "5.00",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-incremental-update-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-incremental-update-manual.https.html index 3d1bfb4..c1ed1b5 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-incremental-update-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-incremental-update-manual.https.html
@@ -14,6 +14,15 @@ const methods = [{ supportedMethods: "basic-card", +}, { + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } }]; const options = {
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-method-abort-update-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-method-abort-update-manual.https.html index 0ff7f23..cf0bb28 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-method-abort-update-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-method-abort-update-manual.https.html
@@ -18,8 +18,19 @@ supportedMethods: "basic-card", }); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); + // Methods -const validMethods = Object.freeze([validMethodBasicCard, validMethod]); +const validMethods = Object.freeze([validMethodBasicCard, validMethod, applePay]); // Amounts const validAmount = Object.freeze({
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-state-checks-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-state-checks-manual.https.html index 4d4ef739..c5737aa 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-state-checks-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-state-checks-manual.https.html
@@ -6,8 +6,18 @@ <script src="/resources/testharnessreport.js"></script> <script> setup({ explicit_done: true, explicit_timeout: true }); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const validMethod = Object.freeze({ supportedMethods: "basic-card" }); -const validMethods = Object.freeze([validMethod]); +const validMethods = Object.freeze([validMethod, applePay]); const validAmount = Object.freeze({ currency: "USD", value: "5.00" }); const validTotal = Object.freeze({ label: "label",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updatewith-method.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updatewith-method.https.html index adacdf3..17a4741 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updatewith-method.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentRequestUpdateEvent/updatewith-method.https.html
@@ -6,8 +6,18 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const basicCard = Object.freeze({ supportedMethods: "basic-card" }); -const defaultMethods = Object.freeze([basicCard]); +const defaultMethods = Object.freeze([basicCard, applePay]); const defaultDetails = Object.freeze({ total: { label: "Total",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentValidationErrors/retry-shows-shippingAddress-member-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentValidationErrors/retry-shows-shippingAddress-member-manual.https.html index 356f30da..c3e2ba71 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentValidationErrors/retry-shows-shippingAddress-member-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentValidationErrors/retry-shows-shippingAddress-member-manual.https.html
@@ -82,11 +82,6 @@ </button> </li> <li> - <button onclick="retryShowsShippingAddressMember(this, { regionCode: 'REGIONCODE ERROR' });"> - The payment sheet shows "REGIONCODE ERROR" for the shipping address' region code. - </button> - </li> - <li> <button onclick="retryShowsShippingAddressMember(this, { sortingCode: 'SORTINGCODE ERROR' });"> The payment sheet shows "SORTINGCODE ERROR" for the shipping address' sorting code. </button>
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/algorithms-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/algorithms-manual.https.html index 5494353..6744649 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/algorithms-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/algorithms-manual.https.html
@@ -15,6 +15,16 @@ { supportedMethods: "basic-card", }, + { + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + }, + } ]; const shippingOptions = { shippingOptions: [
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/billing-address-changed-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/billing-address-changed-manual.https.html index cb9acf6..ccfeb6fd 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/billing-address-changed-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/billing-address-changed-manual.https.html
@@ -10,7 +10,16 @@ const methods = [ { supportedMethods: "basic-card" }, - { supportedMethods: "https://apple.com/apple-pay" }, + { + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + }, + }, ]; const details = {
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/change-shipping-option-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/change-shipping-option-manual.https.html index a33365ba..4380018 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/change-shipping-option-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/change-shipping-option-manual.https.html
@@ -9,7 +9,17 @@ <script> setup({ explicit_done: true, explicit_timeout: true }); const validMethod = Object.freeze({ supportedMethods: "basic-card" }); -const validMethods = Object.freeze([validMethod]); +const applePayMethod = { + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + }, +}; +const validMethods = Object.freeze([validMethod, applePayMethod]); const validAmount = Object.freeze({ currency: "USD", value: "5.00" }); const validTotal = Object.freeze({ label: "label",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/change-shipping-option-select-last-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/change-shipping-option-select-last-manual.https.html index f0849115..4ad31d6 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/change-shipping-option-select-last-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/change-shipping-option-select-last-manual.https.html
@@ -8,7 +8,16 @@ setup({ explicit_done: true, explicit_timeout: true }); const validMethods = Object.freeze([ { supportedMethods: "basic-card" }, - { supportedMethods: "https://apple.com/apple-pay" }, + { + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + }, + }, ]); const validAmount = Object.freeze({ currency: "USD", value: "5.00" }); const validTotal = Object.freeze({
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/historical.https-expected.txt b/third_party/blink/web_tests/external/wpt/payment-request/historical.https-expected.txt index 4dbafb774..34cd171 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/historical.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/payment-request/historical.https-expected.txt
@@ -6,6 +6,7 @@ PASS paymentRequestId in PaymentRequest PASS paymentRequestId in PaymentResponse FAIL languageCode in PaymentAddress assert_false: expected false got true +PASS regionCode in PaymentAddress PASS supportedMethods must not support sequence<DOMString> Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/historical.https.html b/third_party/blink/web_tests/external/wpt/payment-request/historical.https.html index cbd29d4..e681f64 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/historical.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/historical.https.html
@@ -21,6 +21,9 @@ // https://github.com/w3c/payment-request/pull/765 ["languageCode", "PaymentAddress"], + + // https://github.com/w3c/payment-request/pull/823 + ["regionCode", "PaymentAddress"], ].forEach(([member, interf]) => { test(() => { assert_false(member in window[interf].prototype);
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/onmerchantvalidation-attribute.https.html b/third_party/blink/web_tests/external/wpt/payment-request/onmerchantvalidation-attribute.https.html index c0ed231..d31ac2dd 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/onmerchantvalidation-attribute.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/onmerchantvalidation-attribute.https.html
@@ -7,7 +7,16 @@ <script> "use strict"; const testMethod = Object.freeze({ supportedMethods: "not-a-real-method" }); -const applePay = Object.freeze({ supportedMethods: "https://apple.com/apple-pay" }); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + }, +}); const defaultMethods = Object.freeze([testMethod, applePay]); const defaultDetails = Object.freeze({ total: {
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/onpaymentmenthodchange-attribute.https.html b/third_party/blink/web_tests/external/wpt/payment-request/onpaymentmenthodchange-attribute.https.html index 0484eb8..f641bec 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/onpaymentmenthodchange-attribute.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/onpaymentmenthodchange-attribute.https.html
@@ -7,7 +7,16 @@ <script> "use strict"; const testMethod = Object.freeze({ supportedMethods: "not-a-real-method" }); -const applePay = Object.freeze({ supportedMethods: "https://apple.com/apple-pay" }); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const defaultMethods = Object.freeze([testMethod, applePay]); const defaultDetails = Object.freeze({ total: {
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-abort-method.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-abort-method.https.html index 8e561b2..75e39a01 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-abort-method.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-abort-method.https.html
@@ -17,6 +17,13 @@ const basicCard = Object.freeze({ supportedMethods: "basic-card" }); const applePay = Object.freeze({ supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } }); const defaultMethods = Object.freeze([basicCard, applePay]); const defaultDetails = Object.freeze({
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method-protection.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method-protection.https.html index b0582d5..e221034d 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method-protection.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method-protection.https.html
@@ -8,7 +8,16 @@ <script src="/resources/testdriver.js"></script> <script> const basicCard = Object.freeze({ supportedMethods: "basic-card" }); -const applePay = Object.freeze({ supportedMethods: "https://apple.com/apple-pay" }); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const defaultMethods = Object.freeze([basicCard, applePay]); const defaultDetails = Object.freeze({ total: {
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html index f38caa0..672e5ce 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html
@@ -10,6 +10,13 @@ const basicCard = Object.freeze({ supportedMethods: "basic-card" }); const applePay = Object.freeze({ supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } }); const defaultMethods = Object.freeze([basicCard, applePay]); const defaultDetails = Object.freeze({
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-constructor-crash.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-constructor-crash.https.html index 1325681..9763615b 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-constructor-crash.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-constructor-crash.https.html
@@ -28,6 +28,17 @@ "use strict"; const ABUSIVE_AMOUNT = 100000; +const applePay = { + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}; + const basicCard = Object.freeze({ supportedMethods: "basic-card", }); @@ -42,7 +53,7 @@ value: "1".repeat(ABUSIVE_AMOUNT), }); -const defaultMethods = Object.freeze([basicCard]); +const defaultMethods = Object.freeze([basicCard, applePay]); const defaultTotal = Object.freeze({ label: "label",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html index 5c54d48..5b253899 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html
@@ -7,8 +7,18 @@ <script src="/resources/testharnessreport.js"></script> <script> "use strict"; +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const basicCard = Object.freeze({ supportedMethods: "basic-card" }); -const defaultMethods = Object.freeze([basicCard]); +const defaultMethods = Object.freeze([basicCard, applePay]); const defaultDetails = Object.freeze({ total: { label: "Total",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html index a4d8fbc4..43ea5dcc 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html
@@ -7,8 +7,18 @@ <script src="/resources/testharnessreport.js"></script> <script> "use strict"; +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const basicCard = Object.freeze({ supportedMethods: "basic-card" }); -const defaultMethods = Object.freeze([basicCard]); +const defaultMethods = Object.freeze([basicCard, applePay]); const defaultDetails = Object.freeze({ total: { label: "Total",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-shippingType-attribute.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-shippingType-attribute.https.html index b1ed0d0..11f75b1c 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-shippingType-attribute.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-shippingType-attribute.https.html
@@ -8,8 +8,18 @@ <script> "use strict"; const paymentShipingTypes = Object.freeze(["delivery", "pickup", "shipping"]); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const basicCard = Object.freeze({ supportedMethods: "basic-card" }); -const defaultMethods = Object.freeze([basicCard]); +const defaultMethods = Object.freeze([basicCard, applePay]); const defaultDetails = Object.freeze({ total: { label: "",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-show-method.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-show-method.https.html index c6e69d4c..3d36259 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-show-method.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-show-method.https.html
@@ -10,7 +10,16 @@ "use strict"; const defaultMethods = Object.freeze([ { supportedMethods: "basic-card" }, - { supportedMethods: "https://apple.com/apple-pay" }, + { + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } + }, ]); const defaultDetails = Object.freeze({
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-response/helpers.js b/third_party/blink/web_tests/external/wpt/payment-request/payment-response/helpers.js index 807f794e..3e4f5cf 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/payment-response/helpers.js +++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-response/helpers.js
@@ -1,10 +1,21 @@ setup({ explicit_done: true, explicit_timeout: true }); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); + const validMethod = Object.freeze({ supportedMethods: "basic-card", }); -const validMethods = Object.freeze([validMethod]); +const validMethods = Object.freeze([validMethod, applePay]); const validAmount = Object.freeze({ currency: "USD",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-response/rejects_if_not_active-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-response/rejects_if_not_active-manual.https.html index 60dd965..516573c 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/payment-response/rejects_if_not_active-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-response/rejects_if_not_active-manual.https.html
@@ -11,7 +11,17 @@ const validMethod = Object.freeze({ supportedMethods: "basic-card", }); -const validMethods = Object.freeze([validMethod]); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); +const validMethods = Object.freeze([validMethod, applePay]); const validAmount = Object.freeze({ currency: "USD", value: "5.00",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https.html b/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https.html index f585e836..06c1f738 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https.html
@@ -9,10 +9,20 @@ <link rel="help" href="https://w3c.github.io/payment-request/#dom-paymentrequest-show()"> <body> <script> +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const validMethod = Object.freeze({ supportedMethods: "basic-card", }); -const validMethods = Object.freeze([validMethod]); +const validMethods = Object.freeze([validMethod, applePay]); const validAmount = Object.freeze({ currency: "USD", value: "5.00",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/shipping-address-changed-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/shipping-address-changed-manual.https.html index 07b5306..711ba27 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/shipping-address-changed-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/shipping-address-changed-manual.https.html
@@ -8,8 +8,18 @@ <script src="/resources/testharnessreport.js"></script> <script> setup({ explicit_done: true, explicit_timeout: true }); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const validMethod = Object.freeze({ supportedMethods: "basic-card" }); -const validMethods = Object.freeze([validMethod]); +const validMethods = Object.freeze([validMethod, applePay]); const validAmount = Object.freeze({ currency: "USD", value: "5.00" }); const validTotal = Object.freeze({ label: "label",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/show-method-optional-promise-rejects-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/show-method-optional-promise-rejects-manual.https.html index 5c1028e..172413f 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/show-method-optional-promise-rejects-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/show-method-optional-promise-rejects-manual.https.html
@@ -24,6 +24,13 @@ const validMethodApplePay = Object.freeze({ supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } }); // Methods
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/show-method-optional-promise-resolves-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/show-method-optional-promise-resolves-manual.https.html index 70c97fa..d41b1b3 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/show-method-optional-promise-resolves-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/show-method-optional-promise-resolves-manual.https.html
@@ -23,6 +23,13 @@ }, { supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } }, ]);
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-iframe.html b/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-iframe.html index 12a1e0c..b50f18e 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-iframe.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-iframe.html
@@ -3,7 +3,16 @@ "use strict"; const defaultMethods = Object.freeze([ { supportedMethods: "basic-card" }, - { supportedMethods: "https://apple.com/apple-pay" }, + { + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } + }, ]); const defaultDetails = Object.freeze({
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-manual.https.html index e4ab550..05fce4f 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-manual.https.html
@@ -14,7 +14,16 @@ const defaultMethods = Object.freeze([ { supportedMethods: "basic-card" }, - { supportedMethods: "https://apple.com/apple-pay" }, + { + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } + }, ]); const defaultDetails = Object.freeze({
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/updateWith-method-pmi-handling-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/updateWith-method-pmi-handling-manual.https.html index 06852bf8..8bab8821 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/updateWith-method-pmi-handling-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/updateWith-method-pmi-handling-manual.https.html
@@ -8,11 +8,21 @@ <script> "use strict"; setup({ explicit_done: true, explicit_timeout: true }); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const validMethod = Object.freeze({ supportedMethods: "https://:@wpt.fyi:443/payment-request", }); -const validMethods = Object.freeze([validMethod]); +const validMethods = Object.freeze([validMethod, applePay]); const validAmount = Object.freeze({ currency: "USD",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/user-abort-algorithm-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/user-abort-algorithm-manual.https.html index 0ba0405..007fb68 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/user-abort-algorithm-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/user-abort-algorithm-manual.https.html
@@ -17,10 +17,20 @@ label: "Total due", amount: validAmount, }); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const validMethod = Object.freeze({ supportedMethods: "basic-card", }); -const validMethods = Object.freeze([validMethod]); +const validMethods = Object.freeze([validMethod, applePay]); const validDetails = Object.freeze({ total: validTotal, });
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/user-accepts-payment-request-algo-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/user-accepts-payment-request-algo-manual.https.html index abaf6cb..3d7b8a0 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/user-accepts-payment-request-algo-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/payment-request/user-accepts-payment-request-algo-manual.https.html
@@ -8,13 +8,23 @@ <script src="/resources/testharnessreport.js"></script> <script> setup({ explicit_done: true, explicit_timeout: true }); +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); const basicCardMethod = Object.freeze({ supportedMethods: "basic-card", }); const validMethod = Object.freeze({ supportedMethods: "this-is-just-for-testings-will-never-match", }); -const methods = Object.freeze([basicCardMethod, validMethod]); +const methods = Object.freeze([basicCardMethod, validMethod, applePay]); const validAmount = Object.freeze({ currency: "USD", value: "5.00",
diff --git a/third_party/blink/web_tests/external/wpt/quirks/unitless-length/excluded-properties-001.html b/third_party/blink/web_tests/external/wpt/quirks/unitless-length/excluded-properties-001.html index 2e33cec0..09fedcf 100644 --- a/third_party/blink/web_tests/external/wpt/quirks/unitless-length/excluded-properties-001.html +++ b/third_party/blink/web_tests/external/wpt/quirks/unitless-length/excluded-properties-001.html
@@ -30,6 +30,13 @@ 'grid-template-columns', 'grid-template-rows', 'inline-size', + 'inset', + 'inset-block', + 'inset-block-end', + 'inset-block-start', + 'inset-inline', + 'inset-inline-end', + 'inset-inline-start', 'margin-block-end', 'margin-block-start', 'margin-inline-end',
diff --git a/third_party/blink/web_tests/external/wpt/quirks/unitless-length/excluded-properties-003.html b/third_party/blink/web_tests/external/wpt/quirks/unitless-length/excluded-properties-003.html new file mode 100644 index 0000000..4cbe012 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/quirks/unitless-length/excluded-properties-003.html
@@ -0,0 +1,42 @@ +<html> +<head> +<meta charset="utf-8"> +<title>inset does not support quirky-length</title> +<link rel="help" href="https://quirks.spec.whatwg.org/#the-unitless-length-quirk"> +<meta name="assert" content="quirky-length is not supported by inset."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="target"></div> +<script> +'use strict'; + +test(() => { + const quirky_values = [ + '1', + '1 2px', + '1px 2', + '1 2', + '1 2px 3px', + '1px 2 3px', + '1px 2px 3', + '1 2 3', + '1 2px 3px 4px', + '1px 2 3px 4px', + '1px 2px 3 4px', + '1px 2px 3px 4', + '1 2 3 4' + ]; + + target.style['inset'] = '5px 6px 7px 8px'; + + for (let value of quirky_values) { + target.style['inset'] = value; + assert_equals(target.style['inset'], '5px 6px 7px 8px', 'inset rejects quirky length "' + value + '"'); + } +}, 'inset does not support quirky length values'); + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/resources/testharness.js b/third_party/blink/web_tests/external/wpt/resources/testharness.js index ed3ffb4..fb86c580 100644 --- a/third_party/blink/web_tests/external/wpt/resources/testharness.js +++ b/third_party/blink/web_tests/external/wpt/resources/testharness.js
@@ -2135,6 +2135,9 @@ } } else if (p == "timeout_multiplier") { this.timeout_multiplier = value; + if (this.timeout_length) { + this.timeout_length *= this.timeout_multiplier; + } } } }
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-util.js b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-util.js index 0d0e263..7d592ea2 100644 --- a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-util.js +++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-util.js
@@ -41,3 +41,27 @@ function innerURLOrigin() { return 'https://127.0.0.1:8444'; } + +function runReferrerTests(test_cases) { + for (const i in test_cases) { + const test_case = test_cases[i]; + promise_test(async (t) => { + const sxgUrl = test_case.origin + '/signed-exchange/resources/sxg/' + + test_case.sxg; + const message = + await openSXGInIframeAndWaitForMessage( + t, sxgUrl, test_case.referrerPolicy); + assert_false(message.is_fallback); + assert_equals(message.referrer, test_case.expectedReferrer); + + const invalidSxgUrl = + test_case.origin + '/signed-exchange/resources/sxg/invalid-' + + test_case.sxg; + const fallbackMessage = + await openSXGInIframeAndWaitForMessage( + t, invalidSxgUrl, test_case.referrerPolicy); + assert_true(fallbackMessage.is_fallback); + assert_equals(fallbackMessage.referrer, test_case.expectedReferrer); + }, 'Referrer of SignedHTTPExchange test : ' + JSON.stringify(test_case)); + } +}
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-policy-header.tentative.https.html b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-policy-header.tentative.https.html new file mode 100644 index 0000000..5dff6af --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-policy-header.tentative.https.html
@@ -0,0 +1,62 @@ +<!DOCTYPE html> +<title>Referrer-Policy header in outer SXG response</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="./resources/sxg-util.js"></script> +<body> +<script> +(() => { + const SAME_ORIGIN = get_host_info().HTTPS_ORIGIN; + const SAME_ORIGIN_SXG = 'sxg-referrer-same-origin.sxg'; + const TEST_CASES = [ + // Referrer-Policy header in outer SXG response. + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG + '?pipe=header(Referrer-Policy,no-referrer)', + referrerPolicy: undefined, + expectedReferrer: '' + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG + + '?pipe=header(Referrer-Policy,no-referrer-when-downgrade)', + referrerPolicy: undefined, + expectedReferrer: document.location.href + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG + '?pipe=header(Referrer-Policy,origin)', + referrerPolicy: undefined, + expectedReferrer: document.location.origin + '/' + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG + '?pipe=header(Referrer-Policy,same-origin)', + referrerPolicy: undefined, + expectedReferrer: document.location.href + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG + '?pipe=header(Referrer-Policy,strict-origin)', + referrerPolicy: undefined, + expectedReferrer: document.location.origin + '/' + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG + + '?pipe=header(Referrer-Policy,strict-origin-when-cross-origin)', + referrerPolicy: undefined, + expectedReferrer: document.location.href + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG + '?pipe=header(Referrer-Policy,unsafe-url)', + referrerPolicy: undefined, + expectedReferrer: document.location.href + }, + ]; + runReferrerTests(TEST_CASES); +})(); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-remote-physical-remote-logical.tentative.https.html b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-remote-physical-remote-logical.tentative.https.html new file mode 100644 index 0000000..c2870fd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-remote-physical-remote-logical.tentative.https.html
@@ -0,0 +1,66 @@ +<!DOCTYPE html> +<title>Referrer of SignedHTTPExchange(physical:remote origin, logical:remote origin)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="./resources/sxg-util.js"></script> +<body> +<script> +(() => { + const REMOTE_ORIGIN = get_host_info().HTTPS_REMOTE_ORIGIN; + const REMOTE_ORIGIN_SXG = 'sxg-referrer-remote-origin.sxg'; + const TEST_CASES = [ + // Physical origin = remote origin. Logical origin = remote origin. + { + origin: REMOTE_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: undefined, + expectedReferrer: document.location.href + }, + { + origin: REMOTE_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'no-referrer', + expectedReferrer: '' + }, + { + origin: REMOTE_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'no-referrer-when-downgrade', + expectedReferrer: document.location.href + }, + { + origin: REMOTE_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'origin', + expectedReferrer: document.location.origin + '/' + }, + { + origin: REMOTE_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'same-origin', + expectedReferrer: '' + }, + { + origin: REMOTE_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'strict-origin', + expectedReferrer: document.location.origin + '/' + }, + { + origin: REMOTE_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'strict-origin-when-cross-origin', + expectedReferrer: document.location.origin + '/' + }, + { + origin: REMOTE_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'unsafe-url', + expectedReferrer: document.location.href + }, + ]; + runReferrerTests(TEST_CASES); +})(); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-remote-physical-same-logical.tentative.https.html b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-remote-physical-same-logical.tentative.https.html new file mode 100644 index 0000000..b3c77d1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-remote-physical-same-logical.tentative.https.html
@@ -0,0 +1,66 @@ +<!DOCTYPE html> +<title>Referrer of SignedHTTPExchange(physical:remote origin, logical:same origin)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="./resources/sxg-util.js"></script> +<body> +<script> +(() => { + const REMOTE_ORIGIN = get_host_info().HTTPS_REMOTE_ORIGIN; + const SAME_ORIGIN_SXG = 'sxg-referrer-same-origin.sxg'; + const TEST_CASES = [ + // Physical origin = remote origin. Logical origin = same origin. + { + origin: REMOTE_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: undefined, + expectedReferrer: document.location.href + }, + { + origin: REMOTE_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'no-referrer', + expectedReferrer: '' + }, + { + origin: REMOTE_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'no-referrer-when-downgrade', + expectedReferrer: document.location.href + }, + { + origin: REMOTE_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'origin', + expectedReferrer: document.location.origin + '/' + }, + { + origin: REMOTE_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'same-origin', + expectedReferrer: '' + }, + { + origin: REMOTE_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'strict-origin', + expectedReferrer: document.location.origin + '/' + }, + { + origin: REMOTE_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'strict-origin-when-cross-origin', + expectedReferrer: document.location.origin + '/' + }, + { + origin: REMOTE_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'unsafe-url', + expectedReferrer: document.location.href + }, + ]; + runReferrerTests(TEST_CASES); +})(); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-same-physical-remote-logical.tentative.https.html b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-same-physical-remote-logical.tentative.https.html new file mode 100644 index 0000000..8a6cdd99 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-same-physical-remote-logical.tentative.https.html
@@ -0,0 +1,66 @@ +<!DOCTYPE html> +<title>Referrer of SignedHTTPExchange(physical:same origin, logical:remote origin)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="./resources/sxg-util.js"></script> +<body> +<script> +(() => { + const SAME_ORIGIN = get_host_info().HTTPS_ORIGIN; + const REMOTE_ORIGIN_SXG = 'sxg-referrer-remote-origin.sxg'; + const TEST_CASES = [ + // Physical origin = same origin. Logical origin = remote origin. + { + origin: SAME_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: undefined, + expectedReferrer: document.location.href + }, + { + origin: SAME_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'no-referrer', + expectedReferrer: '' + }, + { + origin: SAME_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'no-referrer-when-downgrade', + expectedReferrer: document.location.href + }, + { + origin: SAME_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'origin', + expectedReferrer: document.location.origin + '/' + }, + { + origin: SAME_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'same-origin', + expectedReferrer: '' + }, + { + origin: SAME_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'strict-origin', + expectedReferrer: document.location.origin + '/' + }, + { + origin: SAME_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'strict-origin-when-cross-origin', + expectedReferrer: document.location.origin + '/' + }, + { + origin: SAME_ORIGIN, + sxg: REMOTE_ORIGIN_SXG, + referrerPolicy: 'unsafe-url', + expectedReferrer: document.location.href + }, + ]; + runReferrerTests(TEST_CASES); +})(); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-same-physical-same-logical.tentative.https.html b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-same-physical-same-logical.tentative.https.html new file mode 100644 index 0000000..88917167 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer-same-physical-same-logical.tentative.https.html
@@ -0,0 +1,66 @@ +<!DOCTYPE html> +<title>Referrer of SignedHTTPExchange(physical:same origin, logical:same origin)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="./resources/sxg-util.js"></script> +<body> +<script> +(() => { + const SAME_ORIGIN = get_host_info().HTTPS_ORIGIN; + const SAME_ORIGIN_SXG = 'sxg-referrer-same-origin.sxg'; + const TEST_CASES = [ + // Physical origin = same origin. Logical origin = same origin. + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: undefined, + expectedReferrer: document.location.href + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'no-referrer', + expectedReferrer: '' + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'no-referrer-when-downgrade', + expectedReferrer: document.location.href + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'origin', + expectedReferrer: document.location.origin + '/' + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'same-origin', + expectedReferrer: document.location.href + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'strict-origin', + expectedReferrer: document.location.origin + '/' + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'strict-origin-when-cross-origin', + expectedReferrer: document.location.href + }, + { + origin: SAME_ORIGIN, + sxg: SAME_ORIGIN_SXG, + referrerPolicy: 'unsafe-url', + expectedReferrer: document.location.href + }, + ]; + runReferrerTests(TEST_CASES); +})(); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer.tentative.https.html b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer.tentative.https.html deleted file mode 100644 index 3be9b1f..0000000 --- a/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-referrer.tentative.https.html +++ /dev/null
@@ -1,284 +0,0 @@ -<!DOCTYPE html> -<title>Referrer of SignedHTTPExchange</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/common/get-host-info.sub.js"></script> -<script src="./resources/sxg-util.js"></script> -<body> -<script> -(() => { - const SAME_ORIGIN = get_host_info().HTTPS_ORIGIN; - const REMOTE_ORIGIN = get_host_info().HTTPS_REMOTE_ORIGIN; - const SAME_ORIGIN_SXG = 'sxg-referrer-same-origin.sxg'; - const REMOTE_ORIGIN_SXG = 'sxg-referrer-remote-origin.sxg'; - const TEST_CASES = [ - // Physical origin = same origin. Logical origin = same origin. - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: undefined, - expectedReferrer: document.location.href - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'no-referrer', - expectedReferrer: '' - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'no-referrer-when-downgrade', - expectedReferrer: document.location.href - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'origin', - expectedReferrer: document.location.origin + '/' - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'same-origin', - expectedReferrer: document.location.href - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'strict-origin', - expectedReferrer: document.location.origin + '/' - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'strict-origin-when-cross-origin', - expectedReferrer: document.location.href - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'unsafe-url', - expectedReferrer: document.location.href - }, - - // Physical origin = same origin. Logical origin = remote origin. - { - origin: SAME_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: undefined, - expectedReferrer: document.location.href - }, - { - origin: SAME_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'no-referrer', - expectedReferrer: '' - }, - { - origin: SAME_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'no-referrer-when-downgrade', - expectedReferrer: document.location.href - }, - { - origin: SAME_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'origin', - expectedReferrer: document.location.origin + '/' - }, - { - origin: SAME_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'same-origin', - expectedReferrer: '' - }, - { - origin: SAME_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'strict-origin', - expectedReferrer: document.location.origin + '/' - }, - { - origin: SAME_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'strict-origin-when-cross-origin', - expectedReferrer: document.location.origin + '/' - }, - { - origin: SAME_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'unsafe-url', - expectedReferrer: document.location.href - }, - - // Physical origin = remote origin. Logical origin = same origin. - { - origin: REMOTE_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: undefined, - expectedReferrer: document.location.href - }, - { - origin: REMOTE_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'no-referrer', - expectedReferrer: '' - }, - { - origin: REMOTE_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'no-referrer-when-downgrade', - expectedReferrer: document.location.href - }, - { - origin: REMOTE_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'origin', - expectedReferrer: document.location.origin + '/' - }, - { - origin: REMOTE_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'same-origin', - expectedReferrer: '' - }, - { - origin: REMOTE_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'strict-origin', - expectedReferrer: document.location.origin + '/' - }, - { - origin: REMOTE_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'strict-origin-when-cross-origin', - expectedReferrer: document.location.origin + '/' - }, - { - origin: REMOTE_ORIGIN, - sxg: SAME_ORIGIN_SXG, - referrerPolicy: 'unsafe-url', - expectedReferrer: document.location.href - }, - - // Physical origin = remote origin. Logical origin = remote origin. - { - origin: REMOTE_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: undefined, - expectedReferrer: document.location.href - }, - { - origin: REMOTE_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'no-referrer', - expectedReferrer: '' - }, - { - origin: REMOTE_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'no-referrer-when-downgrade', - expectedReferrer: document.location.href - }, - { - origin: REMOTE_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'origin', - expectedReferrer: document.location.origin + '/' - }, - { - origin: REMOTE_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'same-origin', - expectedReferrer: '' - }, - { - origin: REMOTE_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'strict-origin', - expectedReferrer: document.location.origin + '/' - }, - { - origin: REMOTE_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'strict-origin-when-cross-origin', - expectedReferrer: document.location.origin + '/' - }, - { - origin: REMOTE_ORIGIN, - sxg: REMOTE_ORIGIN_SXG, - referrerPolicy: 'unsafe-url', - expectedReferrer: document.location.href - }, - - // Referrer-Policy header in outer SXG response. - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG + '?pipe=header(Referrer-Policy,no-referrer)', - referrerPolicy: undefined, - expectedReferrer: '' - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG + - '?pipe=header(Referrer-Policy,no-referrer-when-downgrade)', - referrerPolicy: undefined, - expectedReferrer: document.location.href - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG + '?pipe=header(Referrer-Policy,origin)', - referrerPolicy: undefined, - expectedReferrer: document.location.origin + '/' - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG + '?pipe=header(Referrer-Policy,same-origin)', - referrerPolicy: undefined, - expectedReferrer: document.location.href - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG + '?pipe=header(Referrer-Policy,strict-origin)', - referrerPolicy: undefined, - expectedReferrer: document.location.origin + '/' - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG + - '?pipe=header(Referrer-Policy,strict-origin-when-cross-origin)', - referrerPolicy: undefined, - expectedReferrer: document.location.href - }, - { - origin: SAME_ORIGIN, - sxg: SAME_ORIGIN_SXG + '?pipe=header(Referrer-Policy,unsafe-url)', - referrerPolicy: undefined, - expectedReferrer: document.location.href - }, - ]; - for (const i in TEST_CASES) { - const test_case = TEST_CASES[i]; - promise_test(async (t) => { - const sxgUrl = test_case.origin + '/signed-exchange/resources/sxg/' + - test_case.sxg; - const message = - await openSXGInIframeAndWaitForMessage( - t, sxgUrl, test_case.referrerPolicy); - assert_false(message.is_fallback); - assert_equals(message.referrer, test_case.expectedReferrer); - - const invalidSxgUrl = - test_case.origin + '/signed-exchange/resources/sxg/invalid-' + - test_case.sxg; - const fallbackMessage = - await openSXGInIframeAndWaitForMessage( - t, invalidSxgUrl, test_case.referrerPolicy); - assert_true(fallbackMessage.is_fallback); - assert_equals(fallbackMessage.referrer, test_case.expectedReferrer); - }, 'Referrer of SignedHTTPExchange test : ' + JSON.stringify(test_case)); - } -})(); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/web-locks/signal.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/web-locks/signal.tentative.https.any.js index 5b8acbb..e0b6e4e 100644 --- a/third_party/blink/web_tests/external/wpt/web-locks/signal.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/web-locks/signal.tentative.https.any.js
@@ -50,8 +50,10 @@ // Verify the request is enqueued: const state = await navigator.locks.query(); - assert_equals(state.held.filter(lock => lock.name === res).length, 1); - assert_equals(state.pending.filter(lock => lock.name === res).length, 1); + assert_equals(state.held.filter(lock => lock.name === res).length, 1, + 'Number of held locks'); + assert_equals(state.pending.filter(lock => lock.name === res).length, 1, + 'Number of pending locks'); const rejected = promise_rejects( t, 'AbortError', promise, 'Request should reject with AbortError'); @@ -76,8 +78,10 @@ // Verify the request is enqueued: const state = await navigator.locks.query(); - assert_equals(state.held.filter(lock => lock.name === res).length, 1); - assert_equals(state.pending.filter(lock => lock.name === res).length, 1); + assert_equals(state.held.filter(lock => lock.name === res).length, 1, + 'Number of held locks'); + assert_equals(state.pending.filter(lock => lock.name === res).length, 1, + 'Number of pending locks'); const rejected = promise_rejects( t, 'AbortError', promise, 'Request should reject with AbortError');
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-quic/RTCQuicTransport.https.html b/third_party/blink/web_tests/external/wpt/webrtc-quic/RTCQuicTransport.https.html index c64ed6af..82427e6 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc-quic/RTCQuicTransport.https.html +++ b/third_party/blink/web_tests/external/wpt/webrtc-quic/RTCQuicTransport.https.html
@@ -5,6 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="../webrtc/RTCIceTransport-extension-helper.js"></script> <script src="RTCQuicTransport-helper.js"></script> +<script src="../webrtc/dictionary-helper.js"></script> <script> 'use strict'; @@ -21,6 +22,7 @@ // makeStandaloneQuicTransport // makeAndStartTwoQuicTransports // makeTwoConnectedQuicTransports +// sleep test(t => { const iceTransport = makeIceTransport(t); @@ -174,5 +176,93 @@ assert_not_equals(update_key, new Uint8Array(new_key)); }, 'Cannot mutate key retrieved from getKey().'); +promise_test(async t => { + const [ localQuicTransport, remoteQuicTransport ] = + makeAndStartTwoQuicTransports(t); + const stats = await localQuicTransport.getStats(); + assert_number_field(stats, 'timestamp'); + assert_unsigned_int_field(stats, 'bytesSent'); + assert_unsigned_int_field(stats, 'packetsSent'); + assert_unsigned_int_field(stats, 'streamBytesSent'); + assert_unsigned_int_field(stats, 'streamBytesReceived'); + assert_unsigned_int_field(stats, 'numOutgoingStreamsCreated'); + assert_unsigned_int_field(stats, 'numIncomingStreamsCreated'); + assert_unsigned_int_field(stats, 'bytesReceived'); + assert_unsigned_int_field(stats, 'packetsReceived'); + assert_unsigned_int_field(stats, 'packetsProcessed'); + assert_unsigned_int_field(stats, 'bytesRetransmitted'); + assert_unsigned_int_field(stats, 'packetsRetransmitted'); + assert_unsigned_int_field(stats, 'packetsLost'); + assert_unsigned_int_field(stats, 'packetsDropped'); + assert_unsigned_int_field(stats, 'cryptoRetransmitCount'); + assert_unsigned_int_field(stats, 'minRttUs'); + assert_unsigned_int_field(stats, 'smoothedRttUs'); + assert_unsigned_int_field(stats, 'maxPacketSize'); + assert_unsigned_int_field(stats, 'maxReceivedPacketSize'); + assert_unsigned_int_field(stats, 'estimatedBandwidthBps'); + assert_unsigned_int_field(stats, 'packetsReordered'); + assert_unsigned_int_field(stats, 'blockedFramesReceived'); + assert_unsigned_int_field(stats, 'blockedFramesSent'); + assert_unsigned_int_field(stats, 'connectivityProbingPacketsReceived'); +}, 'Stats returned by getStats() are present.'); + +promise_test(async t => { + const [ localQuicTransport, remoteQuicTransport ] = + await makeTwoConnectedQuicTransports(t); + const localStream = localQuicTransport.createStream(); + localStream.write({ finish: true }); + const remoteWatcher = new EventWatcher(t, remoteQuicTransport, 'quicstream'); + await remoteWatcher.wait_for('quicstream'); + const localStats = await localQuicTransport.getStats(); + const remoteStats = await remoteQuicTransport.getStats(); + assert_equals(localStats.numOutgoingStreamsCreated, 1); + assert_equals(localStats.numIncomingStreamsCreated, 0); + assert_equals(remoteStats.numOutgoingStreamsCreated, 0); + assert_equals(remoteStats.numIncomingStreamsCreated, 1); +}, 'getStats() returns proper stream counts after creating streams.'); + +promise_test(async t => { + const [ localQuicTransport, remoteQuicTransport ] = + makeAndStartTwoQuicTransports(t); + const stats1 = await localQuicTransport.getStats(); + await new Promise(resolve => t.step_timeout(resolve, 20)); + const stats2 = await localQuicTransport.getStats(); + assert_greater_than(stats2.timestamp, stats1.timestamp); +}, 'Two separate stats returned by getStats() give different timestamps.'); + +promise_test(async t => { + const quicTransport = makeStandaloneQuicTransport(t); + const promise = quicTransport.getStats(); + promise_rejects(t, 'InvalidStateError', promise); +}, 'getStats() promises immediately rejected with InvalidStateError ' + + `if called before 'connecting'.`); + +promise_test(async t => { + const [ localQuicTransport, remoteQuicTransport ] = + await makeTwoConnectedQuicTransports(t); + const promise = localQuicTransport.getStats(); + localQuicTransport.stop(); + promise_rejects(t, 'InvalidStateError', promise); +}, 'getStats() promises rejected with InvalidStateError if stop() ' + + 'is called before being fulfilled.'); + +promise_test(async t => { + const [ localQuicTransport, remoteQuicTransport ] = + await makeTwoConnectedQuicTransports(t); + const promise = localQuicTransport.getStats(); + localQuicTransport.transport.stop(); + promise_rejects(t, 'InvalidStateError', promise); +}, 'getStats() promises rejected with InvalidStateError if ' + + 'RTCIceTransport calls stop() before being fulfilled.'); + +promise_test(async t => { + const [ localQuicTransport, remoteQuicTransport ] = + await makeTwoConnectedQuicTransports(t); + localQuicTransport.transport.stop(); + const promise = localQuicTransport.getStats(); + promise_rejects(t, 'InvalidStateError', promise); +}, 'getStats() promises immediately rejected if called after' + + `'closed' state.`); + </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState-expected.txt index e3cf316..b2860142 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState-expected.txt
@@ -1,5 +1,7 @@ This is a testharness.js-based test. PASS Initial iceConnectionState should be new +PASS Closing the connection should set iceConnectionState to closed +PASS connection with one data channel should eventually have connected or completed connection state FAIL connection with one data channel should eventually have connected connection state Cannot read property 'transport' of undefined Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.html index 4071033..b647b3d3 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.html +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.html
@@ -64,6 +64,12 @@ assert_equals(pc.iceConnectionState, 'new'); }, 'Initial iceConnectionState should be new'); + test(t => { + const pc = new RTCPeerConnection(); + pc.close(); + assert_equals(pc.iceConnectionState, 'closed'); + }, 'Closing the connection should set iceConnectionState to closed'); + /* 4.4.4 RTCIceConnectionState Enum checking @@ -106,6 +112,35 @@ const pc1 = new RTCPeerConnection(); t.add_cleanup(() => pc1.close()); const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc2.close()); + + let had_checking = false; + + const onIceConnectionStateChange = t.step_func(() => { + const {iceConnectionState} = pc1; + if (iceConnectionState === 'checking') { + had_checking = true; + } else if (iceConnectionState === 'connected' || + iceConnectionState === 'completed') { + assert_true(had_checking, 'state should pass checking before' + + ' reaching connected or completed'); + t.done(); + } + }); + + pc1.createDataChannel('test'); + + pc1.addEventListener('iceconnectionstatechange', onIceConnectionStateChange); + + exchangeIceCandidates(pc1, pc2); + doSignalingHandshake(pc1, pc2); + }, 'connection with one data channel should eventually have connected or ' + + 'completed connection state'); + +async_test(t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + const pc2 = new RTCPeerConnection(); t.add_cleanup(() => pc2.close()); @@ -116,19 +151,22 @@ const iceTransport = pc1.sctp.transport.transport; assert_equals(iceTransport.state, 'checking', - 'Expect ICE transport to be in checking state when iceConnectionState is checking'); + 'Expect ICE transport to be in checking state when' + + ' iceConnectionState is checking'); } else if(iceConnectionState === 'connected') { const iceTransport = pc1.sctp.transport.transport; assert_equals(iceTransport.state, 'connected', - 'Expect ICE transport to be in connected state when iceConnectionState is connected'); + 'Expect ICE transport to be in connected state when' + + ' iceConnectionState is connected'); } else if(iceConnectionState === 'completed') { const iceTransport = pc1.sctp.transport.transport; assert_equals(iceTransport.state, 'completed', - 'Expect ICE transport to be in connected state when iceConnectionState is completed'); + 'Expect ICE transport to be in connected state when' + + ' iceConnectionState is completed'); } }); @@ -141,7 +179,8 @@ exchangeIceCandidates(pc1, pc2); doSignalingHandshake(pc1, pc2); - }, 'connection with one data channel should eventually have connected connection state'); + }, 'connection with one data channel should eventually ' + + 'have connected connection state'); /* TODO
diff --git a/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/connect-event-expected.txt b/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/connect-event-expected.txt new file mode 100644 index 0000000..e9908f2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/connect-event-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL connect event assert_true: e.data === '' expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/interface-objects-expected.txt b/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/interface-objects-expected.txt new file mode 100644 index 0000000..9ac653a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/interface-objects-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL expected interface objects/constructors assert_equals: expected "" but got "These were missing: Worker, SharedWorker" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/setting-port-members-expected.txt b/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/setting-port-members-expected.txt new file mode 100644 index 0000000..31227334 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/setting-port-members-expected.txt
@@ -0,0 +1,10 @@ +This is a testharness.js-based test. +PASS postMessage +PASS start +PASS close +FAIL onmessage assert_equals: {handleEvent:function(){}} expected null but got object "[object Object]" +PASS addEventListener +PASS removeEventListener +PASS despatchEvent +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/undefined-arguments-expected.txt b/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/undefined-arguments-expected.txt new file mode 100644 index 0000000..83e9421 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/undefined-arguments-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL undefined as arguments assert_equals: second arg expected "undefined" but got "" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/unresolvable-url-expected.txt b/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/unresolvable-url-expected.txt new file mode 100644 index 0000000..4f92dcfdb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/workers/constructors/SharedWorker/unresolvable-url-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL resolving broken url assert_throws: function "function() { + var worker = new SharedWorker('http://foo bar'); + }" threw object "SecurityError: Failed to construct 'SharedWorker': Script at 'http://foo%20bar/' cannot be accessed from origin 'http://web-platform.test:8001'." that is not a DOMException SyntaxError: property "code" is equal to 18, expected 12 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/unresolvable-url-expected.txt b/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/unresolvable-url-expected.txt new file mode 100644 index 0000000..f6e2da6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/unresolvable-url-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL unresolvable url assert_throws: function "function() { new Worker('http://invalid url/'); }" threw object "SecurityError: Failed to construct 'Worker': Script at 'http://invalid%20url/' cannot be accessed from origin 'http://web-platform.test:8001'." that is not a DOMException SyntaxError: property "code" is equal to 18, expected 12 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/SharedWorkerGlobalScope/onconnect-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/SharedWorkerGlobalScope/onconnect-expected.txt new file mode 100644 index 0000000..23667a0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/workers/interfaces/SharedWorkerGlobalScope/onconnect-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL onconnect assert_array_equals: property 1, expected "null" but got "[object Object]" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/workers/semantics/run-a-worker/003-expected.txt b/third_party/blink/web_tests/external/wpt/workers/semantics/run-a-worker/003-expected.txt new file mode 100644 index 0000000..efe31fb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/workers/semantics/run-a-worker/003-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +PASS worker +FAIL shared assert_unreached: Reached unreachable code +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/fast/css/containment/change-text-node-data-ellipsis-crash-expected.txt b/third_party/blink/web_tests/fast/css/containment/change-text-node-data-ellipsis-crash-expected.txt new file mode 100644 index 0000000..be3388e2 --- /dev/null +++ b/third_party/blink/web_tests/fast/css/containment/change-text-node-data-ellipsis-crash-expected.txt
@@ -0,0 +1,3 @@ +The test passes if you see the word "PASS" (without any ellipsis) below and it doesn't crash in debug. + +PASS
diff --git a/third_party/blink/web_tests/fast/css/containment/change-text-node-data-ellipsis-crash.html b/third_party/blink/web_tests/fast/css/containment/change-text-node-data-ellipsis-crash.html new file mode 100644 index 0000000..28f6611 --- /dev/null +++ b/third_party/blink/web_tests/fast/css/containment/change-text-node-data-ellipsis-crash.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<style> +#test { + width: 100px; + height: 50px; + overflow: hidden; + text-overflow: ellipsis; + line-height: 1; + white-space: nowrap; + contain: layout size; +} +</style> +<p>The test passes if you see the word "PASS" (without any ellipsis) below and it doesn't crash in debug.</p> +<div id="test"> + Hellowooooorld! +</div> +<script> + if (window.testRunner) + testRunner.dumpAsText(); + + document.body.offsetLeft; + test.childNodes[0].data = "PASS"; +</script>
diff --git a/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-datachannel.html b/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-datachannel.html index bbfe876..73590e09 100644 --- a/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-datachannel.html +++ b/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-datachannel.html
@@ -90,9 +90,13 @@ shouldNotThrow("dc.send('xyzzy');"); } +var pc_has_connected = false; function pc_onicechange() { - if (pc.iceConnectionState === "completed") { + if ((pc.iceConnectionState === "connected" || + pc.iceConnectionState === "completed") && + !pc_has_connected) { testPassed("pc is connected"); + pc_has_connected = true; } }
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/markers-zoomed-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/markers-zoomed-expected.png index c3458c014..a5a82aa 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/markers-zoomed-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/markers-zoomed-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/vertical-lr-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/vertical-lr-expected.png index 7f0235af..e6172ed 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/vertical-lr-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/vertical-lr-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/vertical-rl-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/vertical-rl-expected.png index f48b38e..0873496 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/vertical-rl-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/markers/vertical-rl-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/contacts/idl-NavigatorContacts.html b/third_party/blink/web_tests/http/tests/contacts/idl-NavigatorContacts.html deleted file mode 100644 index db516519..0000000 --- a/third_party/blink/web_tests/http/tests/contacts/idl-NavigatorContacts.html +++ /dev/null
@@ -1,11 +0,0 @@ -<!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script> -test(function() { - assert_true('contacts' in navigator, - 'navigator.contacts exists in navigator.'); - assert_true('ContactInfo' in window, - 'ContactInfo exists in window.'); -}, 'navigator.contacts IDL test'); -</script>
diff --git a/third_party/blink/web_tests/http/tests/contacts/select-function.html b/third_party/blink/web_tests/http/tests/contacts/select-function.html index 0fcf2113..346017a 100644 --- a/third_party/blink/web_tests/http/tests/contacts/select-function.html +++ b/third_party/blink/web_tests/http/tests/contacts/select-function.html
@@ -1,13 +1,74 @@ -<!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="resources.js"></script> - +<!doctype html> +<meta charset="utf-8"> +<title>Contact API: Behaviour of the select() function</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> <script> -promise_test(function() { - return assert_promise_rejects_with_message( - navigator.contacts.select({multiple: true, properties: ['name', 'email', 'tel']}), - new DOMException('Unable to open a contact selector', 'AbortError'), - 'navigator.contacts.select'); -}, 'Select function throws exception.'); +'use strict'; + +// Creates a "user gesture" using Blink's test-only eventSender. +function triggerUserGesture() { + if (!window.eventSender) + throw new Error('The `eventSender` must be available for this test'); + + eventSender.mouseDown(); + eventSender.mouseUp(); +} + +// Verifies that |func|, when invoked, throws a TypeError exception. +async function expectTypeError(func) { + try { + await func(); + } catch (e) { + assert_equals(e.name, 'TypeError'); + return; + } + + assert_unreached('expected a TypeError, but none was thrown'); +} + +test(() => { + // Exposure of the interface and method. + assert_own_property(window, 'ContactsManager'); + assert_own_property(ContactsManager.prototype, 'select'); + + // Exposure of the instance. + assert_idl_attribute(navigator, 'contacts'); + assert_idl_attribute(navigator.contacts, 'select'); + +}, 'The Contact API is exposed on the Window context'); + +promise_test(async () => { + await expectTypeError(() => + navigator.contacts.select({ properties: ['name'] })); + +}, 'The Contact API requires a user gesture') + +promise_test(async () => { + triggerUserGesture(); + + // At least one property must be provided. + await expectTypeError(() => navigator.contacts.select()); + await expectTypeError(() => navigator.contacts.select({ properties: [] })); + + // Per WebIDL parsing, no invalid values may be provided. + await expectTypeError(() => + navigator.contacts.select({ properties: [''] })); + await expectTypeError(() => + navigator.contacts.select({ properties: ['foo'] })); + await expectTypeError(() => + navigator.contacts.select({ properties: ['name', 'photo'] })); + +}, 'The Contact API requires at least one valid property to be provided'); + +promise_test(async () => { + triggerUserGesture(); + + // TODO(peter): Fake the Mojo interface so that we can extend this test with + // valid behaviour, and actually verify the API's functionality. + await expectTypeError(() => + navigator.contacts.select({ properties: ['name'] })); + +}, 'The Contact API can fail when the selector cannot be opened'); + </script>
diff --git a/third_party/blink/web_tests/http/tests/devtools/components/dom-extension-expected.txt b/third_party/blink/web_tests/http/tests/devtools/components/dom-extension-expected.txt index ab05449a..898c7221 100644 --- a/third_party/blink/web_tests/http/tests/devtools/components/dom-extension-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/components/dom-extension-expected.txt
@@ -4,12 +4,12 @@ Running: traverseNextNodeInShadowDom #document-fragment DIV.shadow-component1 -CONTENT +SLOT DIV.component1-content text 1 SPAN.component1-content text 4 -CONTENT +SLOT SPAN text 3 DIV.component2 @@ -18,9 +18,11 @@ DIV.mid-div DIV component2-text -CONTENT +SLOT +SLOT DIV.component2-content text 2 +SLOT DIV.component2-content component2 light dom text
diff --git a/third_party/blink/web_tests/http/tests/devtools/components/dom-extension.js b/third_party/blink/web_tests/http/tests/devtools/components/dom-extension.js index 14909d3a..b19c396 100644 --- a/third_party/blink/web_tests/http/tests/devtools/components/dom-extension.js +++ b/third_party/blink/web_tests/http/tests/devtools/components/dom-extension.js
@@ -8,33 +8,45 @@ TestRunner.runTestSuite([ function traverseNextNodeInShadowDom(next) { - function createContent(parent, selection) { - var content = parent.createChild('content'); - content.setAttribute('select', selection); + function createSlot(parent, name) { + const slot = parent.createChild('slot'); + if (name) + slot.name = name; + return slot; + } + + function createChild(parent, tagName, name, text = '') { + const child = parent.createChild(tagName, name); + if (name) + child.slot = name; + child.textContent = text; + return child; } var component1 = createElementWithClass('div', 'component1'); - var shadow1 = component1.createShadowRoot(); - component1.createChild('div', 'component1-content').textContent = 'text 1'; - component1.createChild('div', 'component2-content').textContent = 'text 2'; - component1.createChild('span').textContent = 'text 3'; - component1.createChild('span', 'component1-content').textContent = 'text 4'; + var shadow1 = component1.attachShadow({mode: 'open'}); + createChild(component1, 'div', 'component1-content', 'text 1'); + createChild(component1, 'div', 'component2-content', 'text 2'); + createChild(component1, 'span', undefined, 'text 3'); + createChild(component1, 'span', 'component1-content', 'text 4'); var shadow1Content = createElementWithClass('div', 'shadow-component1'); shadow1.appendChild(shadow1Content); - createContent(shadow1Content, '.component1-content'); - createContent(shadow1Content, 'span'); + createSlot(shadow1Content, 'component1-content'); + createSlot(shadow1Content); var component2 = shadow1Content.createChild('div', 'component2'); - var shadow2 = component2.createShadowRoot(); - createContent(component2, '.component2-content'); - component2.createChild('div', 'component2-content').textContent = 'component2 light dom text'; + var shadow2 = component2.attachShadow({mode: 'open'}); + createSlot(component2, 'component2-content'); + createChild( + component2, 'div', 'component2-content', 'component2 light dom text'); var shadow2Content = createElementWithClass('div', 'shadow-component1'); shadow2.appendChild(shadow2Content); - var midDiv = shadow2Content.createChild('div', 'mid-div'); - midDiv.createChild('div').textContent = 'component2-text'; - createContent(midDiv, '.component2-content'); + var midDiv = createChild(shadow2Content, 'div', 'mid-div'); + createChild(midDiv, 'div', undefined, 'component2-text'); + createSlot(midDiv); + createSlot(midDiv, 'component2-content'); var node = component1; while ((node = node.traverseNextNode(component1))) {
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/color-swatch.js b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/color-swatch.js index c5f058fd..f8ddef7 100644 --- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/color-swatch.js +++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/color-swatch.js
@@ -64,12 +64,21 @@ ]); function createShiftClick() { - var event = document.createEvent('MouseEvent'); - event.initMouseEvent('click', true, true, null, 1, 0, 0, 0, 0, false, false, true, false, 0, null); + const event = new MouseEvent('click', { + bubbles: true, + cancelable: true, + detail: 1, + screenX: 0, + screenY: 0, + clientX: 0, + clientY: 0, + shiftKey: true, + composed: true + }); return event; } function popoverVisible() { - return !!document.body.querySelector('* /deep/ .spectrum-color'); + return !!UI.GlassPane._panes.size; } })();
diff --git a/third_party/blink/web_tests/http/tests/devtools/extensions/extensions-panel.js b/third_party/blink/web_tests/http/tests/devtools/extensions/extensions-panel.js index 1599fec..5e209af 100644 --- a/third_party/blink/web_tests/http/tests/devtools/extensions/extensions-panel.js +++ b/third_party/blink/web_tests/http/tests/devtools/extensions/extensions-panel.js
@@ -28,7 +28,7 @@ TestRunner.addResult("Status bar buttons state:"); for (var i = 0; i < items.length; ++i) { var item = items[i]; - if (item instanceof HTMLContentElement) + if (item instanceof HTMLSlotElement) continue; if (!(item instanceof HTMLButtonElement)) { TestRunner.addResult("status bar item " + i + " is not a button: " + item);
diff --git a/third_party/blink/web_tests/http/tests/devtools/layers/layer-compositing-reasons-expected.txt b/third_party/blink/web_tests/http/tests/devtools/layers/layer-compositing-reasons-expected.txt index 1e1f37e..edbb765 100644 --- a/third_party/blink/web_tests/http/tests/devtools/layers/layer-compositing-reasons-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/layers/layer-compositing-reasons-expected.txt
@@ -1,8 +1,7 @@ Tests layer compositing reasons in Layers Panel Compositing reasons for div#transform3d: assumedOverlap,transform3D Compositing reasons for div#transform3d-individual: assumedOverlap,transform3D -Compositing reasons for iframe#iframe: iFrame -Compositing reasons for div#backface-visibility: assumedOverlap,backfaceVisibilityHidden +Compositing reasons for div#backface-visibility: backfaceVisibilityHidden Compositing reasons for div#animation: activeTransformAnimation,assumedOverlap Compositing reasons for div#animation-individual: activeTransformAnimation,assumedOverlap Compositing reasons for div#transformWithCompositedDescendants: assumedOverlap,transformWithCompositedDescendants
diff --git a/third_party/blink/web_tests/http/tests/devtools/layers/layer-compositing-reasons.js b/third_party/blink/web_tests/http/tests/devtools/layers/layer-compositing-reasons.js index fdf38a4..bdf9e2c 100644 --- a/third_party/blink/web_tests/http/tests/devtools/layers/layer-compositing-reasons.js +++ b/third_party/blink/web_tests/http/tests/devtools/layers/layer-compositing-reasons.js
@@ -7,15 +7,6 @@ await TestRunner.loadModule('layers_test_runner'); await TestRunner.navigatePromise(TestRunner.url('resources/compositing-reasons.html')); - await TestRunner.evaluateInPageAsync(` - (function() { - return new Promise(fulfill => { - var iframe = document.getElementById('iframe'); - iframe.onload = fulfill; - iframe.src = "composited-iframe.html"; - }); - })()`); - async function dumpCompositingReasons(layer) { var reasons = await layer.requestCompositingReasons(); var node = layer.nodeForSelfOrAncestor(); @@ -24,7 +15,7 @@ } var idsToTest = [ - 'transform3d', 'transform3d-individual', 'iframe', 'backface-visibility', 'animation', 'animation-individual', + 'transform3d', 'transform3d-individual', 'backface-visibility', 'animation', 'animation-individual', 'transformWithCompositedDescendants', 'transformWithCompositedDescendants-individual', 'opacityWithCompositedDescendants', 'reflectionWithCompositedDescendants', 'perspective', 'preserve3d' ];
diff --git a/third_party/blink/web_tests/http/tests/devtools/layers/layer-scroll-rects-get.js b/third_party/blink/web_tests/http/tests/devtools/layers/layer-scroll-rects-get.js index ac00eed..ffb97ba 100644 --- a/third_party/blink/web_tests/http/tests/devtools/layers/layer-scroll-rects-get.js +++ b/third_party/blink/web_tests/http/tests/devtools/layers/layer-scroll-rects-get.js
@@ -11,9 +11,12 @@ <div style="height:40px;width:40px;"></div> </div> `); - await TestRunner.evaluateInPagePromise(` - var element = document.getElementById('touchable'); - element.addEventListener("touchstart", () => {}, false); + await TestRunner.evaluateInPageAsync(` + (function() { + var element = document.getElementById('touchable'); + element.addEventListener("touchstart", () => {}, false); + return new Promise(f => testRunner.updateAllLifecyclePhasesAndCompositeThen(f)); + })(); `); await LayersTestRunner.requestLayers();
diff --git a/third_party/blink/web_tests/http/tests/devtools/layers/resources/compositing-reasons.html b/third_party/blink/web_tests/http/tests/devtools/layers/resources/compositing-reasons.html index 79b58ff..26102d18c 100644 --- a/third_party/blink/web_tests/http/tests/devtools/layers/resources/compositing-reasons.html +++ b/third_party/blink/web_tests/http/tests/devtools/layers/resources/compositing-reasons.html
@@ -17,7 +17,6 @@ </script> <div id="transform3d" style="transform: translateZ(100px);"></div> <div id="transform3d-individual" style="translate: 0px 0px 100px;">translated individual</div> -<iframe id="iframe"></iframe> <div id="backface-visibility" style="backface-visibility: hidden">backface hidden</div> <div id="animation" style="width: 50px; height: 50px; -webkit-animation-name: rotate; -webkit-animation-iteration-count: infinite; -webkit-animation-duration: 5s;">animated</div> <div id="animation-individual" style="width: 50px; height: 50px; animation-name: rotate-individual; animation-iteration-count: infinite; animation-duration: 5s;">animated individual</div>
diff --git a/third_party/blink/web_tests/http/tests/devtools/security/blank-origins-not-shown-expected.txt b/third_party/blink/web_tests/http/tests/devtools/security/blank-origins-not-shown-expected.txt index ff23453..deebff6 100644 --- a/third_party/blink/web_tests/http/tests/devtools/security/blank-origins-not-shown-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/security/blank-origins-not-shown-expected.txt
@@ -2,7 +2,7 @@ Group: Main origin Group: Unknown / canceled -<SPAN is=url-text > +<SPAN > <SPAN class=url-scheme-unknown > https </SPAN>
diff --git a/third_party/blink/web_tests/http/tests/devtools/security/failed-request-expected.txt b/third_party/blink/web_tests/http/tests/devtools/security/failed-request-expected.txt index 709926a..dba7588 100644 --- a/third_party/blink/web_tests/http/tests/devtools/security/failed-request-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/security/failed-request-expected.txt
@@ -2,7 +2,7 @@ Group: Main origin Group: Secure origins -<SPAN is=url-text > +<SPAN > <SPAN class=url-scheme-secure > https </SPAN> @@ -23,7 +23,7 @@ foo.test </SPAN> Group: Unknown / canceled -<SPAN is=url-text > +<SPAN > <SPAN class=url-scheme-unknown > https </SPAN>
diff --git a/third_party/blink/web_tests/http/tests/devtools/security/interstitial-sidebar-expected.txt b/third_party/blink/web_tests/http/tests/devtools/security/interstitial-sidebar-expected.txt index 95b45ff..4f24fee 100644 --- a/third_party/blink/web_tests/http/tests/devtools/security/interstitial-sidebar-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/security/interstitial-sidebar-expected.txt
@@ -68,7 +68,7 @@ </SPAN> <DIV class=icon security-property security-property-secure > </DIV> - <SPAN is=url-text > + <SPAN > <SPAN class=url-scheme-secure > https </SPAN> @@ -89,7 +89,7 @@ </SPAN> <DIV class=icon security-property security-property-secure > </DIV> - <SPAN is=url-text > + <SPAN > <SPAN class=url-scheme-secure > https </SPAN> @@ -189,7 +189,7 @@ </SPAN> <DIV class=icon security-property security-property-secure > </DIV> - <SPAN is=url-text > + <SPAN > <SPAN class=url-scheme-secure > https </SPAN> @@ -210,7 +210,7 @@ </SPAN> <DIV class=icon security-property security-property-secure > </DIV> - <SPAN is=url-text > + <SPAN > <SPAN class=url-scheme-secure > https </SPAN> @@ -310,7 +310,7 @@ </SPAN> <DIV class=icon security-property security-property-secure > </DIV> - <SPAN is=url-text > + <SPAN > <SPAN class=url-scheme-secure > https </SPAN> @@ -331,7 +331,7 @@ </SPAN> <DIV class=icon security-property security-property-secure > </DIV> - <SPAN is=url-text > + <SPAN > <SPAN class=url-scheme-secure > https </SPAN>
diff --git a/third_party/blink/web_tests/http/tests/devtools/security/main-origin-assigned-despite-request-missing-expected.txt b/third_party/blink/web_tests/http/tests/devtools/security/main-origin-assigned-despite-request-missing-expected.txt index bc9da3c..02fafde 100644 --- a/third_party/blink/web_tests/http/tests/devtools/security/main-origin-assigned-despite-request-missing-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/security/main-origin-assigned-despite-request-missing-expected.txt
@@ -3,7 +3,7 @@ Page origin: http://127.0.0.1:8000 Detected main origin: http://127.0.0.1:8000 Group: Main origin -<SPAN is=url-text > +<SPAN > <SPAN class=url-scheme-unknown > http </SPAN> @@ -24,7 +24,7 @@ 127.0.0.1:8000 </SPAN> Group: Unknown / canceled -<SPAN is=url-text > +<SPAN > <SPAN class=url-scheme-unknown > https </SPAN> @@ -44,7 +44,7 @@ <SPAN > foo.test </SPAN> -<SPAN is=url-text > +<SPAN > <SPAN class=url-scheme-unknown > https </SPAN>
diff --git a/third_party/blink/web_tests/http/tests/devtools/security/origin-view-ct-compliance-expected.txt b/third_party/blink/web_tests/http/tests/devtools/security/origin-view-ct-compliance-expected.txt index ba9f064..54da9805 100644 --- a/third_party/blink/web_tests/http/tests/devtools/security/origin-view-ct-compliance-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/security/origin-view-ct-compliance-expected.txt
@@ -1,7 +1,7 @@ Tests that the panel includes Certificate Transparency compliance status Panel on origin view: -<DIV class=widget vbox security-origin-view insertion-point-main > +<DIV class=widget vbox security-origin-view slot=insertion-point-main > <STYLE type=text/css > </STYLE> <STYLE type=text/css > @@ -13,7 +13,7 @@ <DIV class=origin-display > <SPAN class=security-property security-property-secure > </SPAN> - <SPAN is=url-text > + <SPAN > <SPAN class=url-scheme-secure > https </SPAN>
diff --git a/third_party/blink/web_tests/http/tests/devtools/security/origin-view-then-interstitial-expected.txt b/third_party/blink/web_tests/http/tests/devtools/security/origin-view-then-interstitial-expected.txt index 1a6bee5..87a4665 100644 --- a/third_party/blink/web_tests/http/tests/devtools/security/origin-view-then-interstitial-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/security/origin-view-then-interstitial-expected.txt
@@ -29,7 +29,7 @@ </DIV> </DIV> Panel on origin view before interstitial: -<DIV class=widget vbox security-origin-view insertion-point-main > +<DIV class=widget vbox security-origin-view slot=insertion-point-main > <STYLE type=text/css > </STYLE> <STYLE type=text/css > @@ -41,7 +41,7 @@ <DIV class=origin-display > <SPAN class=security-property security-property-secure > </SPAN> - <SPAN is=url-text > + <SPAN > <SPAN class=url-scheme-secure > https </SPAN>
diff --git a/third_party/blink/web_tests/http/tests/devtools/security/security-details-updated-with-security-state-expected.txt b/third_party/blink/web_tests/http/tests/devtools/security/security-details-updated-with-security-state-expected.txt index 9877d71..efa79d5 100644 --- a/third_party/blink/web_tests/http/tests/devtools/security/security-details-updated-with-security-state-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/security/security-details-updated-with-security-state-expected.txt
@@ -3,7 +3,7 @@ Sidebar Origins -------------------------------- Group: Main origin Group: Secure origins -<SPAN is=url-text > +<SPAN > <SPAN class=url-scheme-unknown > https </SPAN> @@ -24,7 +24,7 @@ foo.test </SPAN> Group: Unknown / canceled -<SPAN is=url-text > +<SPAN > <SPAN class=url-scheme-unknown > https </SPAN> @@ -45,7 +45,7 @@ bar.test </SPAN> Origin view ------------------------------------ -<DIV class=widget vbox security-origin-view insertion-point-main > +<DIV class=widget vbox security-origin-view slot=insertion-point-main > <STYLE type=text/css > </STYLE> <STYLE type=text/css > @@ -57,7 +57,7 @@ <DIV class=origin-display > <SPAN class=security-property security-property-secure > </SPAN> - <SPAN is=url-text > + <SPAN > <SPAN class=url-scheme-secure > https </SPAN>
diff --git a/third_party/blink/web_tests/http/tests/devtools/security/security-unknown-resource-expected.txt b/third_party/blink/web_tests/http/tests/devtools/security/security-unknown-resource-expected.txt index a95b9c2b..682016f 100644 --- a/third_party/blink/web_tests/http/tests/devtools/security/security-unknown-resource-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/security/security-unknown-resource-expected.txt
@@ -2,7 +2,7 @@ Group: Main origin Group: Unknown / canceled -<SPAN is=url-text > +<SPAN > <SPAN class=url-scheme-unknown > http </SPAN>
diff --git a/third_party/blink/web_tests/http/tests/images/feature-policy-image-policies-with-border-radius-expected.txt b/third_party/blink/web_tests/http/tests/images/feature-policy-image-policies-with-border-radius-expected.txt index af489f7..00df7e5 100644 --- a/third_party/blink/web_tests/http/tests/images/feature-policy-image-policies-with-border-radius-expected.txt +++ b/third_party/blink/web_tests/http/tests/images/feature-policy-image-policies-with-border-radius-expected.txt
@@ -1,2 +1,4 @@ +CONSOLE ERROR: Feature policy violation: unoptimized-images is not allowed in this document. +CONSOLE ERROR: Feature policy violation: unoptimized-images is not allowed in this document. CONSOLE ERROR: Feature policy violation: legacy-image-formats is not allowed in this document. CONSOLE ERROR: Feature policy violation: legacy-image-formats is not allowed in this document.
diff --git a/third_party/blink/web_tests/http/tests/images/feature-policy-unoptimized-images-cached-image-expected.txt b/third_party/blink/web_tests/http/tests/images/feature-policy-unoptimized-images-cached-image-expected.txt new file mode 100644 index 0000000..09961d9 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/images/feature-policy-unoptimized-images-cached-image-expected.txt
@@ -0,0 +1,6 @@ +CONSOLE ERROR: Feature policy violation: unoptimized-images is not allowed in this document. +CONSOLE ERROR: Feature policy violation: unoptimized-images is not allowed in this document. +CONSOLE ERROR: Feature policy violation: unoptimized-images is not allowed in this document. +CONSOLE ERROR: Feature policy violation: unoptimized-images is not allowed in this document. +CONSOLE ERROR: Feature policy violation: unoptimized-images is not allowed in this document. +CONSOLE ERROR: Feature policy violation: unoptimized-images is not allowed in this document.
diff --git a/third_party/blink/web_tests/http/tests/images/feature-policy-unoptimized-images-expected.txt b/third_party/blink/web_tests/http/tests/images/feature-policy-unoptimized-images-expected.txt new file mode 100644 index 0000000..be394bb5 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/images/feature-policy-unoptimized-images-expected.txt
@@ -0,0 +1,2 @@ +CONSOLE ERROR: Feature policy violation: unoptimized-images is not allowed in this document. +CONSOLE ERROR: Feature policy violation: unoptimized-images is not allowed in this document.
diff --git a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/rtc-quic-transport-origin-trial-interfaces.html b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/rtc-quic-transport-origin-trial-interfaces.html new file mode 100644 index 0000000..306a950 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/rtc-quic-transport-origin-trial-interfaces.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<!-- Generate token with the command: +tools/origin_trials/generate_token.py http://127.0.0.1:8000 RTCQuicTransport --expire-timestamp=2000000000 +--> +<meta http-equiv="origin-trial" content="Atq6Jbo2/q1/mFJ9lErFsAqkyeHIwkjR2qIq0jIhkh3UCvNEYAwfwd0cMLR9EF/qobLllgi4vGKKAJ23kdnCNgUAAABYeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiUlRDUXVpY1RyYW5zcG9ydCIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ==" /> +<title>RTCQuicTransport and RTCIceTransport - interfaces exposed by origin trial</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/origin-trials-helper.js"></script> +<script> + +properties_to_check = { + 'RTCQuicTransport': ['transport', 'state', 'getKey', 'connect', 'listen', + 'stop', 'createStream', 'onstatechange', 'onerror', + 'onquicstream'], + 'RTCIceTransport': ['role', 'state', 'gatheringState', 'getLocalCandidates', + 'getRemoteCandidates', 'getSelectedCandidatePair', + 'getLocalParameters', 'getRemoteParameters', + 'onstatechange', 'ongatheringstatechange', + 'onselectedcandidatepairchange', 'gather', 'start', + 'addRemoteCandidate', 'onicecandidate'], + 'RTCQuicStream': ['transport', 'state', 'readBufferedAmount', + 'maxReadBufferedAmount', 'writeBufferedAmount', + 'readInto', 'write', 'reset', + 'waitForWriteBufferedAmountBelow', + 'waitForReadable', 'onstatechange'], + 'RTCQuicStreamEvent': ['stream'] +}; + +test(t => { + OriginTrialsHelper.check_properties(this, properties_to_check); +}, 'RTCQuicTransport and RTCIceTransport properties are available.'); + +</script>
diff --git a/third_party/blink/web_tests/http/tests/performance-timing/element-timing/progressively-loaded-image.html b/third_party/blink/web_tests/http/tests/performance-timing/element-timing/progressively-loaded-image.html new file mode 100644 index 0000000..ce7ce73 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/performance-timing/element-timing/progressively-loaded-image.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> +<meta charset=utf-8 /> +<title>Element Timing: buffer elements before onload</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src="resources/element-timing-helpers.js"></script> +<body> +<img src=/resources/slow-image.php?name=square20.png&mimeType=image&sleep=500> +<script> + let beforeRender; + // Number of bytes to be read on the initial read, before sleeping. + // Should be sufficient to do at least a first scan. + let numInitial = 300; + let sleep = 500; + async_test(function(t) { + const observer = new PerformanceObserver( + t.step_func_done(function(entryList) { + assert_equals(entryList.getEntries().length, 1); + const entry = entryList.getEntries()[0]; + // Since the image is only fully loaded after the sleep, the render timestamp + // must be greater than |beforeRender| + |sleep|. + checkElement(entry, 'my_image', beforeRender + sleep); + }) + ); + observer.observe({entryTypes: ['element']}); + + const img = document.createElement('img'); + img.src = '/resources/progressive-image.php?name=square20.jpg&numInitial=' + + numInitial + '&sleep=' + sleep; + img.setAttribute('elementtiming', 'my_image'); + document.body.appendChild(img) + beforeRender = performance.now(); + }, "Element Timing: image render timestamp occurs after it is fully loaded."); +</script>
diff --git a/third_party/blink/web_tests/http/tests/resources/progressive-image.php b/third_party/blink/web_tests/http/tests/resources/progressive-image.php new file mode 100644 index 0000000..70f9b60 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/resources/progressive-image.php
@@ -0,0 +1,17 @@ +<?php +$name = $_GET['name']; +$sleepTime = $_GET['sleep']; +$numInitial = $_GET['numInitial']; + +header('Content-Type: image'); +header('Content-Length: ' . filesize($name)); +// Read from the beginning, |numInitial| bytes. +$first = file_get_contents($name, FALSE, NULL, 0, $numInitial); +echo $first; +flush(); + +usleep($sleepTime*1000); + +// Read the remainder after having slept. +$second = file_get_contents($name, FALSE, NULL, $numInitial); +echo $second;
diff --git a/third_party/blink/web_tests/http/tests/security/cross-frame-access-getOwnPropertyDescriptor-expected.txt b/third_party/blink/web_tests/http/tests/security/cross-frame-access-getOwnPropertyDescriptor-expected.txt index 2631850c..3010a8184 100644 --- a/third_party/blink/web_tests/http/tests/security/cross-frame-access-getOwnPropertyDescriptor-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/cross-frame-access-getOwnPropertyDescriptor-expected.txt
@@ -219,8 +219,8 @@ PASS: canGetDescriptor(targetLocation, 'toString') should be 'false' and is. PASS: canGetDescriptor(targetLocation, 'valueOf') should be 'false' and is. PASS: canGetDescriptor(targetLocation, 'customProperty') should be 'false' and is. +PASS: canGetDescriptor(targetLocation, 'assign') should be 'false' and is. PASS: canGetDescriptor(targetLocation, 'reload') should be 'false' and is. -PASS: canGetDescriptor(targetLocation, 'assign') should be 'true' and is. PASS: canGetDescriptor(targetLocation, 'replace') should be 'true' and is. ----- tests access to cross domain history object ----- PASS: targetWindow.history should have thrown an exception, and did: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
diff --git a/third_party/blink/web_tests/http/tests/security/cross-frame-access-getOwnPropertyDescriptor.html b/third_party/blink/web_tests/http/tests/security/cross-frame-access-getOwnPropertyDescriptor.html index cd2cc70..555c5182 100644 --- a/third_party/blink/web_tests/http/tests/security/cross-frame-access-getOwnPropertyDescriptor.html +++ b/third_party/blink/web_tests/http/tests/security/cross-frame-access-getOwnPropertyDescriptor.html
@@ -253,12 +253,12 @@ log("----- tests access to cross domain location object -----"); window.targetLocation = targetWindow.location; var locationProperties = [ - "protocol", "host", "hostname", "port", "pathname", "search", "hash", "toString", "valueOf", "customProperty", "reload" + "protocol", "host", "hostname", "port", "pathname", "search", "hash", "toString", "valueOf", "customProperty", "assign", "reload" ]; for (var i = 0; i < locationProperties.length; i++) shouldBeFalse("canGetDescriptor(targetLocation, '" + locationProperties[i] + "')"); var locationPropertiesAllowed = [ - "assign", "replace" + "replace" ]; for (var i = 0; i < locationPropertiesAllowed.length; i++) shouldBeTrue("canGetDescriptor(targetLocation, '" + locationPropertiesAllowed[i] + "')");
diff --git a/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-expected.txt b/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-expected.txt index f694e92347..ad33773 100644 --- a/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-expected.txt
@@ -6,10 +6,11 @@ Firefox allows access to 'location.toString' but throws an exception when you call it. PASS: canGet('targetWindow.location.toString') should be 'false' and is. PASS: accessThrowsException('targetWindow.location.toString') should be 'true' and is. -PASS: canGet('targetWindow.location.href') should be 'false' and is. +PASS: canGet('targetWindow.location.assign') should be 'false' and is. PASS: canGet('targetWindow.location.hash') should be 'false' and is. PASS: canGet('targetWindow.location.host') should be 'false' and is. PASS: canGet('targetWindow.location.hostname') should be 'false' and is. +PASS: canGet('targetWindow.location.href') should be 'false' and is. PASS: canGet('targetWindow.location.pathname') should be 'false' and is. PASS: canGet('targetWindow.location.port') should be 'false' and is. PASS: canGet('targetWindow.location.protocol') should be 'false' and is. @@ -27,6 +28,5 @@ PASS: accessThrowsException('targetWindow.location.search') should be 'true' and is. PASS: accessThrowsException('targetWindow.location.existingCustomProperty') should be 'true' and is. PASS: accessThrowsException('targetWindow.location[1]') should be 'true' and is. -PASS: canGet('targetWindow.location.assign') should be 'true' and is. PASS: canGet('targetWindow.location.replace') should be 'true' and is.
diff --git a/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-override-expected.txt b/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-override-expected.txt index f45a2757..07c5bdf7 100644 --- a/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-override-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-override-expected.txt
@@ -1,7 +1,6 @@ ----- tests for getting a targetWindow's location object's functions which have custom overrides. The desired behavior is for the targetWindow to return the builtin function, not the override ----- -PASS: canGet('targetWindow.location.assign') should be 'true' and is. -PASS: toString('targetWindow.location.assign') should be 'function () { [native code] }' and is. +PASS: canGet('targetWindow.location.assign') should be 'false' and is. PASS: canGet('targetWindow.location.reload') should be 'false' and is. PASS: canGet('targetWindow.location.replace') should be 'true' and is. PASS: toString('targetWindow.location.replace') should be 'function () { [native code] }' and is.
diff --git a/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-override.html b/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-override.html index 8e136a7..faa0e8dd 100644 --- a/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-override.html +++ b/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get-override.html
@@ -17,8 +17,7 @@ // We should test overriding using window.location.__proto__ once the Location object has a proper prototype. // Overriden using window.location.assign = function() { return "new assign" } - shouldBeTrue("canGet('targetWindow.location.assign')"); - shouldBe("toString('targetWindow.location.assign')", "toString('window.location.assign')"); + shouldBeFalse("canGet('targetWindow.location.assign')"); // Overriden using window.location.reload = "new reload" shouldBeFalse("canGet('targetWindow.location.reload')");
diff --git a/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get.html b/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get.html index a174277..dce7d088 100644 --- a/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get.html +++ b/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-get.html
@@ -20,10 +20,11 @@ shouldBeFalse("canGet('targetWindow.location.toString')"); shouldBeTrue("accessThrowsException('targetWindow.location.toString')"); - shouldBeFalse("canGet('targetWindow.location.href')"); + shouldBeFalse("canGet('targetWindow.location.assign')"); shouldBeFalse("canGet('targetWindow.location.hash')"); shouldBeFalse("canGet('targetWindow.location.host')"); shouldBeFalse("canGet('targetWindow.location.hostname')"); + shouldBeFalse("canGet('targetWindow.location.href')"); shouldBeFalse("canGet('targetWindow.location.pathname')"); shouldBeFalse("canGet('targetWindow.location.port')"); shouldBeFalse("canGet('targetWindow.location.protocol')"); @@ -43,7 +44,6 @@ shouldBeTrue("accessThrowsException('targetWindow.location.existingCustomProperty')"); shouldBeTrue("accessThrowsException('targetWindow.location[1]')"); - shouldBeTrue("canGet('targetWindow.location.assign')"); shouldBeTrue("canGet('targetWindow.location.replace')"); if (window.testRunner)
diff --git a/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-put-expected.txt b/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-put-expected.txt index 7948b17..2e9cb15 100644 --- a/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-put-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/cross-frame-access-location-put-expected.txt
@@ -11,7 +11,7 @@ ----- tests for putting window.history and its properties ----- -PASS: window.location.assign should be 'function () { [native code] }' and is. +PASS: window.location.assign should be 'function assign() { [native code] }' and is. PASS: window.location.replace should be 'function () { [native code] }' and is. PASS: window.location.reload should be 'function reload() { [native code] }' and is. PASS: window.location.toString should be 'function toString() { [native code] }' and is.
diff --git a/third_party/blink/web_tests/media/controls/accessibility-time-element.html b/third_party/blink/web_tests/media/controls/accessibility-time-element.html new file mode 100644 index 0000000..2c711a0 --- /dev/null +++ b/third_party/blink/web_tests/media/controls/accessibility-time-element.html
@@ -0,0 +1,44 @@ +<!DOCTYPE html> +<html lang="en-US"> +<title>Media Controls: time elements accessibility test</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../media-controls.js"></script> +<video controls></video> +<script> +async_test(t => { + var video = document.querySelector('video'); + video.src = '../content/test.ogv'; + + enableTestMode(video); + + var current_time = currentTimeElement(video); + var remaining_time = timeRemainingElement(video); + assert_not_equals(current_time, null); + assert_not_equals(remaining_time, null); + + assert_equals(current_time.getAttribute('aria-label'), + 'elapsed time: 0:00'); + + assert_equals(remaining_time.getAttribute('aria-label'), + 'remaining time: / 0:00'); + + video.oncanplaythrough = t.step_func_done(_ => { + assert_equals(current_time.getAttribute('aria-label'), + 'elapsed time: 0:00'); + + assert_equals(remaining_time.getAttribute('aria-label'), + 'remaining time: / 0:06'); + + video.currentTime = 1; + video.onseeked = t.step_func(_ => { + assert_equals(current_time.getAttribute('aria-label'), + 'elapsed time: 0:01'); + + assert_equals(remaining_time.getAttribute('aria-label'), + 'remaining time: / 0:06'); + }); + }); +}); +</script> +</html>
diff --git a/third_party/blink/web_tests/media/media-controls.js b/third_party/blink/web_tests/media/media-controls.js index 9417cd6..06f0ab9a 100644 --- a/third_party/blink/web_tests/media/media-controls.js +++ b/third_party/blink/web_tests/media/media-controls.js
@@ -55,6 +55,14 @@ return element; } +function timeRemainingElement(videoElement) { + var controlID = '-webkit-media-controls-time-remaining-display'; + var element = mediaControlsElement(internals.shadowRoot(videoElement).firstChild, controlID); + if (!element) + throw 'Failed to find time remaining element'; + return element; +} + function downloadButton(videoElement) { var controlID = '-internal-media-controls-download-button'; var button = mediaControlsElement(internals.shadowRoot(videoElement).firstChild, controlID);
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/composited-layer-move-expected.html b/third_party/blink/web_tests/paint/invalidation/compositing/composited-layer-move-expected.html new file mode 100644 index 0000000..6ffbf4c --- /dev/null +++ b/third_party/blink/web_tests/paint/invalidation/compositing/composited-layer-move-expected.html
@@ -0,0 +1,3 @@ +<!DOCTYPE html> +<div id="target" style="position: relative; left: 200px; width: 100px; height: 100px; background: green"> +</div>
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/composited-layer-move-expected.txt b/third_party/blink/web_tests/paint/invalidation/compositing/composited-layer-move-expected.txt new file mode 100644 index 0000000..dc83c6f --- /dev/null +++ b/third_party/blink/web_tests/paint/invalidation/compositing/composited-layer-move-expected.txt
@@ -0,0 +1,29 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "drawsContent": false, + "backgroundColor": "#FFFFFF" + }, + { + "name": "Scrolling Layer", + "bounds": [800, 600], + "drawsContent": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF" + }, + { + "name": "LayoutBlockFlow (relative positioned) DIV id='target'", + "position": [208, 8], + "bounds": [100, 100], + "contentsOpaque": true, + "backgroundColor": "#008000" + } + ] +} +
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/composited-layer-move.html b/third_party/blink/web_tests/paint/invalidation/compositing/composited-layer-move.html new file mode 100644 index 0000000..c26bb0f4 --- /dev/null +++ b/third_party/blink/web_tests/paint/invalidation/compositing/composited-layer-move.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<script src="../resources/text-based-repaint.js"></script> +<div id="target" style="position: relative; width: 100px; height: 100px; will-change: transform; background: green"> +</div> +<script> +function repaintTest() { + target.style.left = '200px'; +} +onload = runRepaintAndPixelTest; +</script>
diff --git a/third_party/blink/web_tests/paint/markers/document-markers-font-64px.html b/third_party/blink/web_tests/paint/markers/document-markers-font-64px.html new file mode 100644 index 0000000..d94aa50 --- /dev/null +++ b/third_party/blink/web_tests/paint/markers/document-markers-font-64px.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html> +<head> +<style> + #editable { font-size: 64px; } +</style> +<script> +function runTest() { + const editable = document.getElementById("editable"); + getSelection().selectAllChildren(editable); + if (window.internals) { + const range = document.createRange(); + range.setStart(editable.firstChild, 0); + range.setEnd(editable.firstChild, 8); + internals.setMarker(document, range, 'spelling'); + } +} +</script> +</head> +<body onload="runTest();"> + <div id="editable" contenteditable="true">wellcome should be marked</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/paint/markers/document-markers-font-8px.html b/third_party/blink/web_tests/paint/markers/document-markers-font-8px.html new file mode 100644 index 0000000..a577ee4 --- /dev/null +++ b/third_party/blink/web_tests/paint/markers/document-markers-font-8px.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html> +<head> +<style> + #editable { font-size: 8px; } +</style> +<script> +function runTest() { + const editable = document.getElementById("editable"); + getSelection().selectAllChildren(editable); + if (window.internals) { + const range = document.createRange(); + range.setStart(editable.firstChild, 0); + range.setEnd(editable.firstChild, 8); + internals.setMarker(document, range, 'spelling'); + } +} +</script> +</head> +<body onload="runTest();"> + <div id="editable" contenteditable="true">wellcome should be marked</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/paint/markers/document-markers-zoom-2000.html b/third_party/blink/web_tests/paint/markers/document-markers-zoom-2000.html new file mode 100644 index 0000000..c95e1c9 --- /dev/null +++ b/third_party/blink/web_tests/paint/markers/document-markers-zoom-2000.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html> +<head> +<style> + #editable { zoom: 2000%; font-size: 8px; } +</style> +<script> +function runTest() { + const editable = document.getElementById("editable"); + getSelection().selectAllChildren(editable); + if (window.internals) { + const range = document.createRange(); + range.setStart(editable.firstChild, 0); + range.setEnd(editable.firstChild, 8); + internals.setMarker(document, range, 'spelling'); + } +} +</script> +</head> +<body onload="runTest();"> + <div id="editable" contenteditable="true">wellcome should be marked</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/platform/android/external/wpt/workers/constructors/SharedWorker/unresolvable-url-expected.txt b/third_party/blink/web_tests/platform/android/external/wpt/workers/constructors/SharedWorker/unresolvable-url-expected.txt new file mode 100644 index 0000000..cc2205c --- /dev/null +++ b/third_party/blink/web_tests/platform/android/external/wpt/workers/constructors/SharedWorker/unresolvable-url-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL resolving broken url assert_throws: function "function() { + var worker = new SharedWorker('http://foo bar'); + }" threw object "ReferenceError: SharedWorker is not defined" that is not a DOMException SyntaxError: property "code" is equal to undefined, expected 12 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/overflow/overflow-delete-line-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/overflow/overflow-delete-line-expected.txt index 89f9f09..e23cfba 100644 --- a/third_party/blink/web_tests/platform/linux/paint/invalidation/overflow/overflow-delete-line-expected.txt +++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/overflow/overflow-delete-line-expected.txt
@@ -23,9 +23,19 @@ "reason": "appeared" }, { - "object": "LayoutBlockFlow DIV id='dv'", + "object": "InlineTextBox ' '", "rect": [8, 74, 46, 36], - "reason": "chunk disappeared" + "reason": "disappeared" + }, + { + "object": "InlineTextBox 'Lorem'", + "rect": [8, 74, 46, 36], + "reason": "disappeared" + }, + { + "object": "InlineTextBox 'ipsum'", + "rect": [8, 74, 46, 36], + "reason": "disappeared" } ] }
diff --git a/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-font-64px-expected.png b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-font-64px-expected.png new file mode 100644 index 0000000..850338c --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-font-64px-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-font-8px-expected.png b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-font-8px-expected.png new file mode 100644 index 0000000..29d2da6 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-font-8px-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-125-expected.png b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-125-expected.png index bef2ecf..921ec3ef 100644 --- a/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-125-expected.png +++ b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-125-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-200-expected.png b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-200-expected.png index 9da3a756f..d7e57c2c 100644 --- a/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-200-expected.png +++ b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-200-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-2000-expected.png b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-2000-expected.png new file mode 100644 index 0000000..8dddcc13 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-2000-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-250-expected.png b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-250-expected.png index 25ca3ed8..4e2a4a9 100644 --- a/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-250-expected.png +++ b/third_party/blink/web_tests/platform/linux/paint/markers/document-markers-zoom-250-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/paint/markers/markers-zoomed-expected.png b/third_party/blink/web_tests/platform/linux/paint/markers/markers-zoomed-expected.png index 8b261ad6..c220fd9 100644 --- a/third_party/blink/web_tests/platform/linux/paint/markers/markers-zoomed-expected.png +++ b/third_party/blink/web_tests/platform/linux/paint/markers/markers-zoomed-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/paint/markers/vertical-lr-expected.png b/third_party/blink/web_tests/platform/linux/paint/markers/vertical-lr-expected.png index a2633b4..d0a16cb 100644 --- a/third_party/blink/web_tests/platform/linux/paint/markers/vertical-lr-expected.png +++ b/third_party/blink/web_tests/platform/linux/paint/markers/vertical-lr-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/paint/markers/vertical-rl-expected.png b/third_party/blink/web_tests/platform/linux/paint/markers/vertical-rl-expected.png index 4424ba78..bfd39405 100644 --- a/third_party/blink/web_tests/platform/linux/paint/markers/vertical-rl-expected.png +++ b/third_party/blink/web_tests/platform/linux/paint/markers/vertical-rl-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-font-64px-expected.png b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-font-64px-expected.png new file mode 100644 index 0000000..850338c --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-font-64px-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-font-8px-expected.png b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-font-8px-expected.png new file mode 100644 index 0000000..29d2da6 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-font-8px-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-125-expected.png b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-125-expected.png new file mode 100644 index 0000000..921ec3ef --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-125-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-200-expected.png b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-200-expected.png new file mode 100644 index 0000000..d7e57c2c --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-200-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-2000-expected.png b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-2000-expected.png new file mode 100644 index 0000000..8dddcc13 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-2000-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-250-expected.png b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-250-expected.png new file mode 100644 index 0000000..4e2a4a9 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/document-markers-zoom-250-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/markers-zoomed-expected.png b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/markers-zoomed-expected.png new file mode 100644 index 0000000..c220fd9 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/markers-zoomed-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/vertical-lr-expected.png b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/vertical-lr-expected.png new file mode 100644 index 0000000..d0a16cb --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/vertical-lr-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/vertical-rl-expected.png b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/vertical-rl-expected.png new file mode 100644 index 0000000..bfd39405 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/stable/paint/markers/vertical-rl-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-font-64px-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-font-64px-expected.png new file mode 100644 index 0000000..8a5d9eea --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-font-64px-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-font-8px-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-font-8px-expected.png new file mode 100644 index 0000000..ec91ab7 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-font-8px-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-zoom-2000-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-zoom-2000-expected.png new file mode 100644 index 0000000..8faf1fe6 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-zoom-2000-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-zoom-250-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-zoom-250-expected.png index d09e5f4..aa246883 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-zoom-250-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/document-markers-zoom-250-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-ltr-text-in-ltr-flow-with-markers-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-ltr-text-in-ltr-flow-with-markers-expected.png index 0ec3396..94f368f 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-ltr-text-in-ltr-flow-with-markers-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-ltr-text-in-ltr-flow-with-markers-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-ltr-text-in-rtl-flow-with-markers-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-ltr-text-in-rtl-flow-with-markers-expected.png index 5130ee38..2386b66 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-ltr-text-in-rtl-flow-with-markers-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-ltr-text-in-rtl-flow-with-markers-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-mixed-text-in-ltr-flow-with-markers-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-mixed-text-in-ltr-flow-with-markers-expected.png index 43e570f2..07b201b 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-mixed-text-in-ltr-flow-with-markers-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-mixed-text-in-ltr-flow-with-markers-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-mixed-text-in-rtl-flow-with-markers-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-mixed-text-in-rtl-flow-with-markers-expected.png index 7d63ca8a..b43e00f 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-mixed-text-in-rtl-flow-with-markers-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-mixed-text-in-rtl-flow-with-markers-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-rtl-text-in-rtl-flow-with-markers-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-rtl-text-in-rtl-flow-with-markers-expected.png index df6c5b10..9f12eaa 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-rtl-text-in-rtl-flow-with-markers-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/ellipsis-rtl-text-in-rtl-flow-with-markers-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/inline-spelling-markers-hidpi-composited-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/inline-spelling-markers-hidpi-composited-expected.png index d821438..fc0e961 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/inline-spelling-markers-hidpi-composited-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/inline-spelling-markers-hidpi-composited-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/inline-spelling-markers-hidpi-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/inline-spelling-markers-hidpi-expected.png index d821438..fc0e961 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/inline-spelling-markers-hidpi-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/inline-spelling-markers-hidpi-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/inline_spelling_markers-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/inline_spelling_markers-expected.png index 19373db..985bac95 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/inline_spelling_markers-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/inline_spelling_markers-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/markers-zoomed-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/markers-zoomed-expected.png index f3e446a..7e1b4a3 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/markers-zoomed-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/markers-zoomed-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/suggestion-marker-basic-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/suggestion-marker-basic-expected.png index 02f61ca..0f70890 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/suggestion-marker-basic-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/suggestion-marker-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/vertical-lr-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/vertical-lr-expected.png index da2b87e8..28653f0 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/vertical-lr-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/vertical-lr-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/markers/vertical-rl-expected.png b/third_party/blink/web_tests/platform/mac/paint/markers/vertical-rl-expected.png index 17ce15a..3688b43f 100644 --- a/third_party/blink/web_tests/platform/mac/paint/markers/vertical-rl-expected.png +++ b/third_party/blink/web_tests/platform/mac/paint/markers/vertical-rl-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/document-markers-font-64px-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-font-64px-expected.png new file mode 100644 index 0000000..bb09410 --- /dev/null +++ b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-font-64px-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/document-markers-font-8px-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-font-8px-expected.png new file mode 100644 index 0000000..bb737dd --- /dev/null +++ b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-font-8px-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-125-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-125-expected.png index d7e701d..098bc27 100644 --- a/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-125-expected.png +++ b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-125-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-200-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-200-expected.png index ed03f14..bb3712a 100644 --- a/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-200-expected.png +++ b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-200-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-2000-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-2000-expected.png new file mode 100644 index 0000000..251e248 --- /dev/null +++ b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-2000-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-250-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-250-expected.png index 1efba95..6b3b8d9 100644 --- a/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-250-expected.png +++ b/third_party/blink/web_tests/platform/win/paint/markers/document-markers-zoom-250-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/grammar-markers-hidpi-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/grammar-markers-hidpi-expected.png index bd262bdb..74435588 100644 --- a/third_party/blink/web_tests/platform/win/paint/markers/grammar-markers-hidpi-expected.png +++ b/third_party/blink/web_tests/platform/win/paint/markers/grammar-markers-hidpi-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/inline-spelling-markers-hidpi-composited-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/inline-spelling-markers-hidpi-composited-expected.png index 13966c5..e06732d6 100644 --- a/third_party/blink/web_tests/platform/win/paint/markers/inline-spelling-markers-hidpi-composited-expected.png +++ b/third_party/blink/web_tests/platform/win/paint/markers/inline-spelling-markers-hidpi-composited-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/inline-spelling-markers-hidpi-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/inline-spelling-markers-hidpi-expected.png index 13966c5..e06732d6 100644 --- a/third_party/blink/web_tests/platform/win/paint/markers/inline-spelling-markers-hidpi-expected.png +++ b/third_party/blink/web_tests/platform/win/paint/markers/inline-spelling-markers-hidpi-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/markers-zoomed-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/markers-zoomed-expected.png index 51e893b9..7e07069 100644 --- a/third_party/blink/web_tests/platform/win/paint/markers/markers-zoomed-expected.png +++ b/third_party/blink/web_tests/platform/win/paint/markers/markers-zoomed-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/vertical-lr-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/vertical-lr-expected.png index 6cb88a0..04ceb0a 100644 --- a/third_party/blink/web_tests/platform/win/paint/markers/vertical-lr-expected.png +++ b/third_party/blink/web_tests/platform/win/paint/markers/vertical-lr-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/markers/vertical-rl-expected.png b/third_party/blink/web_tests/platform/win/paint/markers/vertical-rl-expected.png index 0931bf9..9b73a365 100644 --- a/third_party/blink/web_tests/platform/win/paint/markers/vertical-rl-expected.png +++ b/third_party/blink/web_tests/platform/win/paint/markers/vertical-rl-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index 969a3213..c0dbf6e 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -1129,12 +1129,6 @@ attribute @@toStringTag getter offset method constructor -interface ContactInfo - attribute @@toStringTag - getter email - getter name - getter tel - method constructor interface ContactsManager attribute @@toStringTag method constructor @@ -5723,6 +5717,7 @@ method constructor method createStream method getKey + method getStats method listen method stop setter onerror
diff --git a/third_party/breakpad/BUILD.gn b/third_party/breakpad/BUILD.gn index adfbe88..de3146ad 100644 --- a/third_party/breakpad/BUILD.gn +++ b/third_party/breakpad/BUILD.gn
@@ -455,6 +455,10 @@ defines = [ "USE_PROTECTED_ALLOCATIONS=1" ] include_dirs = [ "breakpad/src/client/apple/Framework" ] + # TODO(crbug.com/841631): Breakpad uses bootstrap_subset() and + # bootstrap_create_server(), both of which are deprecated starting in 10.10. + cflags = [ "-Wno-deprecated-declarations" ] + deps = [ ":crash_inspector", ":crash_report_sender",
diff --git a/third_party/closure_compiler/externs/autofill_private.js b/third_party/closure_compiler/externs/autofill_private.js index d905d06..4b74fd6 100644 --- a/third_party/closure_compiler/externs/autofill_private.js +++ b/third_party/closure_compiler/externs/autofill_private.js
@@ -180,6 +180,20 @@ chrome.autofillPrivate.getCreditCardList = function(callback) {}; /** + * Gets the list of local credit cards. + * @param {function(!Array<!chrome.autofillPrivate.CreditCardEntry>):void} + * callback Callback which will be called with the list of credit cards. + */ +chrome.autofillPrivate.getLocalCreditCardList = function(callback) {}; + +/** + * Gets the list of server credit cards. + * @param {function(!Array<!chrome.autofillPrivate.CreditCardEntry>):void} + * callback Callback which will be called with the list of credit cards. + */ +chrome.autofillPrivate.getServerCreditCardList = function(callback) {}; + +/** * Clears the data associated with a wallet card which was saved locally so that * the saved copy is masked (e.g., "Card ending in 1234"). * @param {string} guid GUID of the credit card to mask. @@ -209,3 +223,17 @@ * @type {!ChromeEvent} */ chrome.autofillPrivate.onCreditCardListChanged; + +/** + * Fired when the local credit card list has changed, meaning that an entry had + * been added, removed, or changed. |entries| The updated list of entries. + * @type {!ChromeEvent} + */ +chrome.autofillPrivate.onLocalCreditCardListChanged; + +/** + * Fired when the server credit card list has changed, meaning that an entry has + * been added, removed, or changed. |entries| The updated list of entries. + * @type {!ChromeEvent} + */ +chrome.autofillPrivate.onServerCreditCardListChanged;
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js index c47129f..63c173c4 100644 --- a/third_party/closure_compiler/externs/file_manager_private.js +++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -323,7 +323,8 @@ * mountCondition: (!chrome.fileManagerPrivate.MountCondition|undefined), * mountContext: (!chrome.fileManagerPrivate.MountContext|undefined), * diskFileSystemType: (string|undefined), - * iconSet: !chrome.fileManagerPrivate.IconSet + * iconSet: !chrome.fileManagerPrivate.IconSet, + * driveLabel: (string|undefined) * }} */ chrome.fileManagerPrivate.VolumeMetadata;
diff --git a/third_party/google_android_play_core/README.chromium b/third_party/google_android_play_core/README.chromium index 3e37261..e3b3bb1 100644 --- a/third_party/google_android_play_core/README.chromium +++ b/third_party/google_android_play_core/README.chromium
@@ -10,4 +10,5 @@ Local Modifications: -Unproguarded verification API. +- Unproguarded verification API. +- Unproguarded inline update API.
diff --git a/third_party/google_android_play_core/cipd.yaml b/third_party/google_android_play_core/cipd.yaml index a397474..92671aa 100644 --- a/third_party/google_android_play_core/cipd.yaml +++ b/third_party/google_android_play_core/cipd.yaml
@@ -3,7 +3,7 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:1.3.7-cr0 +# cipd create --pkg-def cipd.yaml -tag version:1.3.7-cr1 package: chromium/third_party/android_deps/libs/com_google_android_play_core_verification description: "" data:
diff --git a/third_party/google_toolbox_for_mac/BUILD.gn b/third_party/google_toolbox_for_mac/BUILD.gn index 67768b1..78ca06a 100644 --- a/third_party/google_toolbox_for_mac/BUILD.gn +++ b/third_party/google_toolbox_for_mac/BUILD.gn
@@ -39,6 +39,11 @@ "Cocoa.framework", "QuartzCore.framework", ] + + # TODO(crbug.com/841631): GTM uses accessibility APIs that are deprecated as + # of 10.10. These can't yet be compiled out, so for now, ignore deprecated + # declarations in GTM altogether. + cflags = [ "-Wno-deprecated-declarations" ] } else { # is_ios sources += [ "src/DebugUtils/GTMMethodCheck.h",
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium index d3911aa3..5074be7 100644 --- a/third_party/harfbuzz-ng/README.chromium +++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,9 +1,9 @@ Name: harfbuzz-ng Short Name: harfbuzz-ng URL: http://harfbuzz.org -Version: 2.3.0-122 -Date: 20190118 -Revision: 89bcfb204c736f5962d377896af2c1350f179882 +Version: 2.3.0-155 +Date: 20190124 +Revision: 36fb2b4da9718a86978fa07c99ba4345f7ca9b4b Security Critical: yes License: MIT License File: src/COPYING
diff --git a/third_party/mozilla/NSWorkspace+Utils.h b/third_party/mozilla/NSWorkspace+Utils.h index 13096a9..a1ea48c1 100644 --- a/third_party/mozilla/NSWorkspace+Utils.h +++ b/third_party/mozilla/NSWorkspace+Utils.h
@@ -43,16 +43,13 @@ - (NSArray*)installedBrowserIdentifiers; // sort order not specified - (NSString*)defaultBrowserIdentifier; -- (NSURL*)defaultBrowserURL; - (NSArray*)installedFeedViewerIdentifiers; - (NSString*)defaultFeedViewerIdentifier; -- (NSURL*)defaultFeedViewerURL; - (void)setDefaultBrowserWithIdentifier:(NSString*)bundleID; - (void)setDefaultFeedViewerWithIdentifier:(NSString*)bundleID; -- (NSURL*)urlOfApplicationWithIdentifier:(NSString*)bundleID; - (NSString*)identifierForBundle:(NSURL*)inBundleURL; - (NSString*)displayNameForFile:(NSURL*)inFileURL;
diff --git a/third_party/mozilla/NSWorkspace+Utils.m b/third_party/mozilla/NSWorkspace+Utils.m index f6aab2c0..f4c4914 100644 --- a/third_party/mozilla/NSWorkspace+Utils.m +++ b/third_party/mozilla/NSWorkspace+Utils.m
@@ -81,22 +81,6 @@ return [(NSString*)LSCopyDefaultHandlerForURLScheme(CFSTR("feed")) autorelease]; } -- (NSURL*)defaultBrowserURL -{ - NSString* defaultBundleId = [self defaultBrowserIdentifier]; - if (defaultBundleId) - return [self urlOfApplicationWithIdentifier:defaultBundleId]; - return nil; -} - -- (NSURL*)defaultFeedViewerURL -{ - NSString* defaultBundleId = [self defaultFeedViewerIdentifier]; - if (defaultBundleId) - return [self urlOfApplicationWithIdentifier:defaultBundleId]; - return nil; -} - - (void)setDefaultBrowserWithIdentifier:(NSString*)bundleID { LSSetDefaultHandlerForURLScheme(CFSTR("http"), (CFStringRef)bundleID); @@ -110,17 +94,6 @@ LSSetDefaultHandlerForURLScheme(CFSTR("feed"), (CFStringRef)bundleID); } -- (NSURL*)urlOfApplicationWithIdentifier:(NSString*)bundleID -{ - if (!bundleID) - return nil; - NSURL* appURL = nil; - if (LSFindApplicationForInfo(kLSUnknownCreator, (CFStringRef)bundleID, NULL, NULL, (CFURLRef*)&appURL) == noErr) - return [appURL autorelease]; - - return nil; -} - - (NSString*)identifierForBundle:(NSURL*)inBundleURL { if (!inBundleURL) return nil;
diff --git a/third_party/mozilla/README.chromium b/third_party/mozilla/README.chromium index 7a44e328..9ea000df 100644 --- a/third_party/mozilla/README.chromium +++ b/third_party/mozilla/README.chromium
@@ -33,3 +33,6 @@ - MOZILLA_EXPORT was added to some constants in NSPasteboard+Utils.h. - +[NSWorkspace(CaminoDefaultBrowserAdditions) isLeopardOrHigher] hidden since it relies on methods deprecated in 10.8 (and is unused in Chrome). +- NSWorkspace(CaminoDefaultBrowserAdditions) methods defaultBrowserURL, + defaultFeedViewerURL, and urlOfApplicationWithIdentifier: removed since they + are unused in Chrome and rely on deprecated APIs as of 10.10.
diff --git a/third_party/webxr_test_pages/.gitignore b/third_party/webxr_test_pages/.gitignore new file mode 100644 index 0000000..c59768b --- /dev/null +++ b/third_party/webxr_test_pages/.gitignore
@@ -0,0 +1 @@ +media/ \ No newline at end of file
diff --git a/third_party/webxr_test_pages/README.chromium b/third_party/webxr_test_pages/README.chromium index 5e62024..2e009f54 100644 --- a/third_party/webxr_test_pages/README.chromium +++ b/third_party/webxr_test_pages/README.chromium
@@ -7,8 +7,16 @@ License: MIT License File: NOT_SHIPPED Security Critical: no + Description: A fork of the WebXR samples to be kept in sync with Chrome and used for testing Chrome. + Local Modifications: Forked to provide a stable set of test pages in sync with Chrome. -Stripped out the media/ directory to minimize the size. \ No newline at end of file +Stripped out the media/ directory to minimize the size. + +Instructions: +In order to serve the samples locally, few steps are required: +1. Copy contents of src/chrome/test/data/xr/webxr_samples/media into src/third_party/webxr_test_pages/webxr-samples/media +2. (optional) If editing cottontail code, run `npm install` and `npm run build-all` in src/third_party/webxr_test_pages/webxr-samples/js/cottontail +3. Serve files, for example by running `python -m SimpleHTTPServer <port number>` in src/third_party/webxr_test_pages/webxr-samples
diff --git a/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js b/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js index f5729682..40deaa60 100644 --- a/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js +++ b/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js
@@ -67,19 +67,34 @@ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? @@ -117,26 +132,6 @@ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setMatrixArrayType", function() { return setMatrixArrayType; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toRadian", function() { return toRadian; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; }); -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ - /** * Common utilities * @module glMatrix @@ -219,26 +214,6 @@ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; }); /* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js"); -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ - /** @@ -253,9 +228,11 @@ */ function create() { let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](4); + if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) { + out[1] = 0; + out[2] = 0; + } out[0] = 1; - out[1] = 0; - out[2] = 0; out[3] = 1; return out; } @@ -691,26 +668,6 @@ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; }); /* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js"); -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ - /** @@ -739,12 +696,14 @@ */ function create() { let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](6); + if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) { + out[1] = 0; + out[2] = 0; + out[4] = 0; + out[5] = 0; + } out[0] = 1; - out[1] = 0; - out[2] = 0; out[3] = 1; - out[4] = 0; - out[5] = 0; return out; } @@ -1203,26 +1162,6 @@ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; }); /* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js"); -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ - /** @@ -1237,14 +1176,16 @@ */ function create() { let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](9); + if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) { + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[5] = 0; + out[6] = 0; + out[7] = 0; + } out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; out[4] = 1; - out[5] = 0; - out[6] = 0; - out[7] = 0; out[8] = 1; return out; } @@ -2029,31 +1970,11 @@ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; }); /* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js"); -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ - /** - * @class 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied. - * @name mat4 + * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied. + * @module mat4 */ /** @@ -2063,21 +1984,23 @@ */ function create() { let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](16); + if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) { + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + } out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; out[5] = 1; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; out[10] = 1; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; out[15] = 1; return out; } @@ -2538,7 +2461,7 @@ let b10, b11, b12; let b20, b21, b22; - if (Math.abs(len) < _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]) { return null; } + if (len < _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]) { return null; } len = 1 / len; x *= len; @@ -2789,7 +2712,7 @@ let len = Math.sqrt(x * x + y * y + z * z); let s, c, t; - if (Math.abs(len) < _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]) { return null; } + if (len < _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]) { return null; } len = 1 / len; x *= len; @@ -2988,7 +2911,7 @@ let translation = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](3); let bx = -a[0], by = -a[1], bz = -a[2], bw = a[3], ax = a[4], ay = a[5], az = a[6], aw = a[7]; - + let magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense if (magnitude > 0) { @@ -3307,18 +3230,18 @@ } /** - * Generates a perspective projection matrix with the given bounds + * Generates a perspective projection matrix with the given bounds. + * Passing null/undefined/no value for far will generate infinite projection matrix. * * @param {mat4} out mat4 frustum matrix will be written into * @param {number} fovy Vertical field of view in radians * @param {number} aspect Aspect ratio. typically viewport width/height * @param {number} near Near bound of the frustum - * @param {number} far Far bound of the frustum + * @param {number} far Far bound of the frustum, can be null or Infinity * @returns {mat4} out */ function perspective(out, fovy, aspect, near, far) { - let f = 1.0 / Math.tan(fovy / 2); - let nf = 1 / (near - far); + let f = 1.0 / Math.tan(fovy / 2), nf; out[0] = f / aspect; out[1] = 0; out[2] = 0; @@ -3329,12 +3252,18 @@ out[7] = 0; out[8] = 0; out[9] = 0; - out[10] = (far + near) * nf; out[11] = -1; out[12] = 0; out[13] = 0; - out[14] = (2 * far * near) * nf; out[15] = 0; + if (far != null && far !== Infinity) { + nf = 1 / (near - far); + out[10] = (far + near) * nf; + out[14] = (2 * far * near) * nf; + } else { + out[10] = -1; + out[14] = -2 * near; + } return out; } @@ -3412,7 +3341,7 @@ } /** - * Generates a look-at matrix with the given eye position, focal point, and up axis. + * Generates a look-at matrix with the given eye position, focal point, and up axis. * If you want a matrix that actually makes an object look at another object, you should use targetTo instead. * * @param {mat4} out mat4 frustum matrix will be written into @@ -3764,7 +3693,7 @@ /*!******************************************************!*\ !*** ./node_modules/gl-matrix/src/gl-matrix/quat.js ***! \******************************************************/ -/*! exports provided: create, identity, setAxisAngle, getAxisAngle, multiply, rotateX, rotateY, rotateZ, calculateW, slerp, invert, conjugate, fromMat3, fromEuler, str, clone, fromValues, copy, set, add, mul, scale, dot, lerp, length, len, squaredLength, sqrLen, normalize, exactEquals, equals, rotationTo, sqlerp, setAxes */ +/*! exports provided: create, identity, setAxisAngle, getAxisAngle, multiply, rotateX, rotateY, rotateZ, calculateW, slerp, random, invert, conjugate, fromMat3, fromEuler, str, clone, fromValues, copy, set, add, mul, scale, dot, lerp, length, len, squaredLength, sqrLen, normalize, exactEquals, equals, rotationTo, sqlerp, setAxes */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -3779,6 +3708,7 @@ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotateZ", function() { return rotateZ; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "calculateW", function() { return calculateW; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "slerp", function() { return slerp; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "random", function() { return random; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "invert", function() { return invert; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "conjugate", function() { return conjugate; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromMat3", function() { return fromMat3; }); @@ -3807,26 +3737,6 @@ /* harmony import */ var _mat3_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mat3.js */ "./node_modules/gl-matrix/src/gl-matrix/mat3.js"); /* harmony import */ var _vec3_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./vec3.js */ "./node_modules/gl-matrix/src/gl-matrix/vec3.js"); /* harmony import */ var _vec4_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./vec4.js */ "./node_modules/gl-matrix/src/gl-matrix/vec4.js"); -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ - @@ -3844,9 +3754,11 @@ */ function create() { let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](4); - out[0] = 0; - out[1] = 0; - out[2] = 0; + if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } out[3] = 1; return out; } @@ -3900,7 +3812,7 @@ function getAxisAngle(out_axis, q) { let rad = Math.acos(q[3]) * 2.0; let s = Math.sin(rad / 2.0); - if (s != 0.0) { + if (s > _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"]) { out_axis[0] = q[0] / s; out_axis[1] = q[1] / s; out_axis[2] = q[2] / s; @@ -4020,7 +3932,7 @@ * @param {quat} out the receiving quaternion * @param {quat} a the first operand * @param {quat} b the second operand - * @param {Number} t interpolation amount between the two inputs + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {quat} out */ function slerp(out, a, b, t) { @@ -4042,7 +3954,7 @@ bw = - bw; } // calculate coefficients - if ( (1.0 - cosom) > 0.000001 ) { + if ( (1.0 - cosom) > _common_js__WEBPACK_IMPORTED_MODULE_0__["EPSILON"] ) { // standard case (slerp) omega = Math.acos(cosom); sinom = Math.sin(omega); @@ -4064,6 +3976,29 @@ } /** + * Generates a random quaternion + * + * @param {quat} out the receiving quaternion + * @returns {quat} out + */ +function random(out) { + // Implementation of http://planning.cs.uiuc.edu/node198.html + // TODO: Calling random 3 times is probably not the fastest solution + let u1 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"](); + let u2 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"](); + let u3 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"](); + + let sqrt1MinusU1 = Math.sqrt(1 - u1); + let sqrtU1 = Math.sqrt(u1); + + out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2); + out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2); + out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3); + out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3); + return out; +} + +/** * Calculates the inverse of a quat * * @param {quat} out the receiving quaternion @@ -4275,7 +4210,7 @@ * @param {quat} out the receiving quaternion * @param {quat} a the first operand * @param {quat} b the second operand - * @param {Number} t interpolation amount between the two inputs + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {quat} out * @function */ @@ -4388,7 +4323,7 @@ * @param {quat} b the second operand * @param {quat} c the third operand * @param {quat} d the fourth operand - * @param {Number} t interpolation amount + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {quat} out */ const sqlerp = (function () { @@ -4488,27 +4423,6 @@ /* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js"); /* harmony import */ var _quat_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./quat.js */ "./node_modules/gl-matrix/src/gl-matrix/quat.js"); /* harmony import */ var _mat4_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mat4.js */ "./node_modules/gl-matrix/src/gl-matrix/mat4.js"); -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ - - @@ -4529,14 +4443,16 @@ */ function create() { let dq = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](8); - dq[0] = 0; - dq[1] = 0; - dq[2] = 0; + if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) { + dq[0] = 0; + dq[1] = 0; + dq[2] = 0; + dq[4] = 0; + dq[5] = 0; + dq[6] = 0; + dq[7] = 0; + } dq[3] = 1; - dq[4] = 0; - dq[5] = 0; - dq[6] = 0; - dq[7] = 0; return dq; } @@ -4686,14 +4602,14 @@ /** * Creates a new dual quat from a matrix (4x4) - * + * * @param {quat2} out the dual quaternion * @param {mat4} a the matrix * @returns {quat2} dual quat receiving operation result * @function */ function fromMat4(out, a) { - //TODO Optimize this + //TODO Optimize this let outer = _quat_js__WEBPACK_IMPORTED_MODULE_1__["create"](); _mat4_js__WEBPACK_IMPORTED_MODULE_2__["getRotation"](outer, a); let t = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](3); @@ -5178,7 +5094,7 @@ * @param {quat2} out the receiving dual quat * @param {quat2} a the first operand * @param {quat2} b the second operand - * @param {Number} t interpolation amount between the two inputs + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {quat2} out */ function lerp(out, a, b, t) { @@ -5279,14 +5195,28 @@ let magnitude = squaredLength(a); if (magnitude > 0) { magnitude = Math.sqrt(magnitude); - out[0] = a[0] / magnitude; - out[1] = a[1] / magnitude; - out[2] = a[2] / magnitude; - out[3] = a[3] / magnitude; - out[4] = a[4] / magnitude; - out[5] = a[5] / magnitude; - out[6] = a[6] / magnitude; - out[7] = a[7] / magnitude; + + let a0 = a[0] / magnitude; + let a1 = a[1] / magnitude; + let a2 = a[2] / magnitude; + let a3 = a[3] / magnitude; + + let b0 = a[4]; + let b1 = a[5]; + let b2 = a[6]; + let b3 = a[7]; + + let a_dot_b = (a0 * b0) + (a1 * b1) + (a2 * b2) + (a3 * b3); + + out[0] = a0; + out[1] = a1; + out[2] = a2; + out[3] = a3; + + out[4] = (b0 - (a0 * a_dot_b)) / magnitude; + out[5] = (b1 - (a1 * a_dot_b)) / magnitude; + out[6] = (b2 - (a2 * a_dot_b)) / magnitude; + out[7] = (b3 - (a3 * a_dot_b)) / magnitude; } return out; } @@ -5355,7 +5285,7 @@ /*!******************************************************!*\ !*** ./node_modules/gl-matrix/src/gl-matrix/vec2.js ***! \******************************************************/ -/*! exports provided: create, clone, fromValues, copy, set, add, subtract, multiply, divide, ceil, floor, min, max, round, scale, scaleAndAdd, distance, squaredDistance, length, squaredLength, negate, inverse, normalize, dot, cross, lerp, random, transformMat2, transformMat2d, transformMat3, transformMat4, str, exactEquals, equals, len, sub, mul, div, dist, sqrDist, sqrLen, forEach */ +/*! exports provided: create, clone, fromValues, copy, set, add, subtract, multiply, divide, ceil, floor, min, max, round, scale, scaleAndAdd, distance, squaredDistance, length, squaredLength, negate, inverse, normalize, dot, cross, lerp, random, transformMat2, transformMat2d, transformMat3, transformMat4, rotate, angle, str, exactEquals, equals, len, sub, mul, div, dist, sqrDist, sqrLen, forEach */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -5391,6 +5321,8 @@ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformMat2d", function() { return transformMat2d; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformMat3", function() { return transformMat3; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformMat4", function() { return transformMat4; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotate", function() { return rotate; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "angle", function() { return angle; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "str", function() { return str; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exactEquals", function() { return exactEquals; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; }); @@ -5403,26 +5335,6 @@ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forEach", function() { return forEach; }); /* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js"); -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ - /** @@ -5437,8 +5349,10 @@ */ function create() { let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](2); - out[0] = 0; - out[1] = 0; + if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) { + out[0] = 0; + out[1] = 0; + } return out; } @@ -5536,7 +5450,7 @@ out[0] = a[0] * b[0]; out[1] = a[1] * b[1]; return out; -}; +} /** * Divides two vec2's @@ -5550,7 +5464,7 @@ out[0] = a[0] / b[0]; out[1] = a[1] / b[1]; return out; -}; +} /** * Math.ceil the components of a vec2 @@ -5563,7 +5477,7 @@ out[0] = Math.ceil(a[0]); out[1] = Math.ceil(a[1]); return out; -}; +} /** * Math.floor the components of a vec2 @@ -5576,7 +5490,7 @@ out[0] = Math.floor(a[0]); out[1] = Math.floor(a[1]); return out; -}; +} /** * Returns the minimum of two vec2's @@ -5590,7 +5504,7 @@ out[0] = Math.min(a[0], b[0]); out[1] = Math.min(a[1], b[1]); return out; -}; +} /** * Returns the maximum of two vec2's @@ -5604,7 +5518,7 @@ out[0] = Math.max(a[0], b[0]); out[1] = Math.max(a[1], b[1]); return out; -}; +} /** * Math.round the components of a vec2 @@ -5617,7 +5531,7 @@ out[0] = Math.round(a[0]); out[1] = Math.round(a[1]); return out; -}; +} /** * Scales a vec2 by a scalar number @@ -5631,7 +5545,7 @@ out[0] = a[0] * b; out[1] = a[1] * b; return out; -}; +} /** * Adds two vec2's after scaling the second operand by a scalar value @@ -5646,7 +5560,7 @@ out[0] = a[0] + (b[0] * scale); out[1] = a[1] + (b[1] * scale); return out; -}; +} /** * Calculates the euclidian distance between two vec2's @@ -5659,7 +5573,7 @@ var x = b[0] - a[0], y = b[1] - a[1]; return Math.sqrt(x*x + y*y); -}; +} /** * Calculates the squared euclidian distance between two vec2's @@ -5672,7 +5586,7 @@ var x = b[0] - a[0], y = b[1] - a[1]; return x*x + y*y; -}; +} /** * Calculates the length of a vec2 @@ -5684,7 +5598,7 @@ var x = a[0], y = a[1]; return Math.sqrt(x*x + y*y); -}; +} /** * Calculates the squared length of a vec2 @@ -5696,7 +5610,7 @@ var x = a[0], y = a[1]; return x*x + y*y; -}; +} /** * Negates the components of a vec2 @@ -5709,7 +5623,7 @@ out[0] = -a[0]; out[1] = -a[1]; return out; -}; +} /** * Returns the inverse of the components of a vec2 @@ -5722,7 +5636,7 @@ out[0] = 1.0 / a[0]; out[1] = 1.0 / a[1]; return out; -}; +} /** * Normalize a vec2 @@ -5742,7 +5656,7 @@ out[1] = a[1] * len; } return out; -}; +} /** * Calculates the dot product of two vec2's @@ -5753,7 +5667,7 @@ */ function dot(a, b) { return a[0] * b[0] + a[1] * b[1]; -}; +} /** * Computes the cross product of two vec2's @@ -5769,7 +5683,7 @@ out[0] = out[1] = 0; out[2] = z; return out; -}; +} /** * Performs a linear interpolation between two vec2's @@ -5777,7 +5691,7 @@ * @param {vec2} out the receiving vector * @param {vec2} a the first operand * @param {vec2} b the second operand - * @param {Number} t interpolation amount between the two inputs + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {vec2} out */ function lerp(out, a, b, t) { @@ -5786,7 +5700,7 @@ out[0] = ax + t * (b[0] - ax); out[1] = ay + t * (b[1] - ay); return out; -}; +} /** * Generates a random vector with the given scale @@ -5801,7 +5715,7 @@ out[0] = Math.cos(r) * scale; out[1] = Math.sin(r) * scale; return out; -}; +} /** * Transforms the vec2 with a mat2 @@ -5817,7 +5731,7 @@ out[0] = m[0] * x + m[2] * y; out[1] = m[1] * x + m[3] * y; return out; -}; +} /** * Transforms the vec2 with a mat2d @@ -5833,7 +5747,7 @@ out[0] = m[0] * x + m[2] * y + m[4]; out[1] = m[1] * x + m[3] * y + m[5]; return out; -}; +} /** * Transforms the vec2 with a mat3 @@ -5850,7 +5764,7 @@ out[0] = m[0] * x + m[3] * y + m[6]; out[1] = m[1] * x + m[4] * y + m[7]; return out; -}; +} /** * Transforms the vec2 with a mat4 @@ -5871,6 +5785,65 @@ } /** + * Rotate a 2D vector + * @param {vec2} out The receiving vec2 + * @param {vec2} a The vec2 point to rotate + * @param {vec2} b The origin of the rotation + * @param {Number} c The angle of rotation + * @returns {vec2} out + */ +function rotate(out, a, b, c) { + //Translate point to the origin + let p0 = a[0] - b[0], + p1 = a[1] - b[1], + sinC = Math.sin(c), + cosC = Math.cos(c); + + //perform rotation and translate to correct position + out[0] = p0*cosC - p1*sinC + b[0]; + out[1] = p0*sinC + p1*cosC + b[1]; + + return out; +} + +/** + * Get the angle between two 2D vectors + * @param {vec2} a The first operand + * @param {vec2} b The second operand + * @returns {Number} The angle in radians + */ +function angle(a, b) { + let x1 = a[0], + y1 = a[1], + x2 = b[0], + y2 = b[1]; + + let len1 = x1*x1 + y1*y1; + if (len1 > 0) { + //TODO: evaluate use of glm_invsqrt here? + len1 = 1 / Math.sqrt(len1); + } + + let len2 = x2*x2 + y2*y2; + if (len2 > 0) { + //TODO: evaluate use of glm_invsqrt here? + len2 = 1 / Math.sqrt(len2); + } + + let cosine = (x1 * x2 + y1 * y2) * len1 * len2; + + + if(cosine > 1.0) { + return 0; + } + else if(cosine < -1.0) { + return Math.PI; + } else { + return Math.acos(cosine); + } +} + +/** * Returns a string representation of a vector * * @param {vec2} a vector to represent as a string @@ -6048,26 +6021,6 @@ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forEach", function() { return forEach; }); /* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js"); -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ - /** @@ -6082,9 +6035,11 @@ */ function create() { let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](3); - out[0] = 0; - out[1] = 0; - out[2] = 0; + if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } return out; } @@ -6450,7 +6405,7 @@ * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand - * @param {Number} t interpolation amount between the two inputs + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {vec3} out */ function lerp(out, a, b, t) { @@ -6471,7 +6426,7 @@ * @param {vec3} b the second operand * @param {vec3} c the third operand * @param {vec3} d the fourth operand - * @param {Number} t interpolation amount between the two inputs + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {vec3} out */ function hermite(out, a, b, c, d, t) { @@ -6496,7 +6451,7 @@ * @param {vec3} b the second operand * @param {vec3} c the third operand * @param {vec3} d the fourth operand - * @param {Number} t interpolation amount between the two inputs + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {vec3} out */ function bezier(out, a, b, c, d, t) { @@ -6888,26 +6843,6 @@ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forEach", function() { return forEach; }); /* harmony import */ var _common_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./common.js */ "./node_modules/gl-matrix/src/gl-matrix/common.js"); -/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ - /** @@ -6922,10 +6857,12 @@ */ function create() { let out = new _common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"](4); - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 0; + if(_common_js__WEBPACK_IMPORTED_MODULE_0__["ARRAY_TYPE"] != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + } return out; } @@ -7297,7 +7234,7 @@ * @param {vec4} out the receiving vector * @param {vec4} a the first operand * @param {vec4} b the second operand - * @param {Number} t interpolation amount between the two inputs + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {vec4} out */ function lerp(out, a, b, t) { @@ -7319,16 +7256,30 @@ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned * @returns {vec4} out */ -function random(out, vectorScale) { - vectorScale = vectorScale || 1.0; +function random(out, scale) { + scale = scale || 1.0; - //TODO: This is a pretty awful way of doing this. Find something better. - out[0] = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"](); - out[1] = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"](); - out[2] = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"](); - out[3] = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"](); - normalize(out, out); - scale(out, out, vectorScale); + // Marsaglia, George. Choosing a Point from the Surface of a + // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646. + // http://projecteuclid.org/euclid.aoms/1177692644; + var v1, v2, v3, v4; + var s1, s2; + do { + v1 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]() * 2 - 1; + v2 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]() * 2 - 1; + s1 = v1 * v1 + v2 * v2; + } while (s1 >= 1); + do { + v3 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]() * 2 - 1; + v4 = _common_js__WEBPACK_IMPORTED_MODULE_0__["RANDOM"]() * 2 - 1; + s2 = v3 * v3 + v4 * v4; + } while (s2 >= 1); + + var d = Math.sqrt((1 - s1) / s2); + out[0] = scale * v1; + out[1] = scale * v2; + out[2] = scale * v3 * d; + out[3] = scale * v4 * d; return out; } @@ -14586,10 +14537,10 @@ var WebXRView = exports.WebXRView = function (_RenderView) { _inherits(WebXRView, _RenderView); - function WebXRView(view, pose, layer) { + function WebXRView(view, layer) { _classCallCheck(this, WebXRView); - return _possibleConstructorReturn(this, (WebXRView.__proto__ || Object.getPrototypeOf(WebXRView)).call(this, view ? view.projectionMatrix : null, pose && view ? pose.getViewMatrix(view) : null, layer && view ? layer.getViewport(view) : null, view ? view.eye : 'left')); + return _possibleConstructorReturn(this, (WebXRView.__proto__ || Object.getPrototypeOf(WebXRView)).call(this, view ? view.projectionMatrix : null, view ? view.viewMatrix : null, layer && view ? layer.getViewport(view) : null, view ? view.eye : 'left')); } return WebXRView; @@ -14863,10 +14814,10 @@ var _iteratorError3 = undefined; try { - for (var _iterator3 = xrFrame.views[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + for (var _iterator3 = pose.views[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var view = _step3.value; - views.push(new WebXRView(view, pose, layer)); + views.push(new WebXRView(view, layer)); } } catch (err) { _didIteratorError3 = true;
diff --git a/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js.map b/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js.map index c7af513..1877d6c 100644 --- a/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js.map +++ b/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.debug.js.map
@@ -1 +1 @@ -{"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap","webpack:///./node_modules/gl-matrix/src/gl-matrix/common.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat2.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat2d.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat3.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat4.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/quat.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/quat2.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/vec2.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/vec3.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/vec4.js","webpack:///./src/core/material.js","webpack:///./src/core/node.js","webpack:///./src/core/primitive.js","webpack:///./src/core/program.js","webpack:///./src/core/renderer.js","webpack:///./src/core/texture.js","webpack:///./src/cottontail.js","webpack:///./src/geometry/box-builder.js","webpack:///./src/geometry/primitive-stream.js","webpack:///./src/loaders/gltf2.js","webpack:///./src/materials/pbr.js","webpack:///./src/math/gl-matrix.js","webpack:///./src/math/ray.js","webpack:///./src/nodes/bounds-renderer.js","webpack:///./src/nodes/button.js","webpack:///./src/nodes/cube-sea.js","webpack:///./src/nodes/drop-shadow.js","webpack:///./src/nodes/gltf2.js","webpack:///./src/nodes/input-renderer.js","webpack:///./src/nodes/seven-segment-text.js","webpack:///./src/nodes/skybox.js","webpack:///./src/nodes/stats-viewer.js","webpack:///./src/nodes/video.js","webpack:///./src/scenes/scene.js","webpack:///./src/util/fallback-helper.js","webpack:///./src/util/query-args.js"],"names":["stateToBlendFunc","GL","WebGLRenderingContext","CAP","CULL_FACE","BLEND","DEPTH_TEST","STENCIL_TEST","COLOR_MASK","DEPTH_MASK","STENCIL_MASK","MAT_STATE","CAPS_RANGE","BLEND_SRC_SHIFT","BLEND_SRC_RANGE","BLEND_DST_SHIFT","BLEND_DST_RANGE","BLEND_FUNC_RANGE","DEPTH_FUNC_SHIFT","DEPTH_FUNC_RANGE","RENDER_ORDER","OPAQUE","SKY","TRANSPARENT","ADDITIVE","DEFAULT","state","mask","shift","value","SRC_COLOR","MaterialState","_state","blendFuncSrc","SRC_ALPHA","blendFuncDst","ONE_MINUS_SRC_ALPHA","depthFunc","LESS","NEVER","MaterialSampler","uniformName","_uniformName","_texture","MaterialUniform","defaultValue","length","_value","_length","Array","Material","renderOrder","_samplers","_uniforms","sampler","push","uniform","renderPrimitive","DEFAULT_TRANSLATION","Float32Array","DEFAULT_ROTATION","DEFAULT_SCALE","tmpRayMatrix","mat4","create","Node","name","children","parent","visible","selectable","_matrix","_dirtyTRS","_translation","_rotation","_scale","_dirtyWorldMatrix","_worldMatrix","_activeFrameId","_hoverFrameId","_renderPrimitives","_renderer","_selectHandler","renderer","clearRenderPrimitives","onRendererChanged","child","_setRenderer","cloneNode","vec3","copy","quat","waitForComplete","then","primitive","addRenderPrimitive","addNode","clone","frameId","markActive","removeNode","i","indexOf","splice","setMatrixDirty","fromRotationTranslationScale","childPromises","Promise","all","_instances","index","ray","localRay","_min","invert","worldMatrix","multiply","transformMatrix","Ray","intersection","intersectsAABB","_max","transformMat4","_hitTestSelectableNode","origin","fromValues","x","y","z","node","distance","result","childResult","hitTest","timestamp","frameDelta","onUpdate","_update","_updateLocalMatrix","mul","PrimitiveAttribute","buffer","componentCount","componentType","stride","byteOffset","normalized","Primitive","attributes","elementCount","mode","indexBuffer","indexByteOffset","indexType","min","max","Program","gl","vertSrc","fragSrc","attribMap","defines","_gl","program","createProgram","attrib","_firstUse","_nextUseCallbacks","definesString","define","_vertShader","createShader","VERTEX_SHADER","attachShader","shaderSource","compileShader","_fragShader","FRAGMENT_SHADER","attribName","bindAttribLocation","linkProgram","callback","getProgramParameter","LINK_STATUS","getShaderParameter","COMPILE_STATUS","console","error","getShaderInfoLog","getProgramInfoLog","deleteProgram","attribCount","ACTIVE_ATTRIBUTES","attribInfo","getActiveAttrib","getAttribLocation","uniformCount","ACTIVE_UNIFORMS","uniformInfo","getActiveUniform","replace","getUniformLocation","deleteShader","useProgram","createWebGLContext","ATTRIB","POSITION","NORMAL","TANGENT","TEXCOORD_0","TEXCOORD_1","COLOR_0","ATTRIB_MASK","DEF_LIGHT_DIR","DEF_LIGHT_COLOR","PRECISION_REGEX","RegExp","VERTEX_SHADER_SINGLE_ENTRY","VERTEX_SHADER_MULTI_ENTRY","FRAGMENT_SHADER_ENTRY","isPowerOfTwo","n","glAttribs","alpha","webglCanvas","document","createElement","contextTypes","webgl2","context","contextType","getContext","webglType","RenderView","projectionMatrix","viewMatrix","viewport","eye","_eye","_eyeIndex","RenderBuffer","target","usage","_target","_usage","_buffer","_promise","resolve","RenderPrimitiveAttribute","primitiveAttribute","_attrib_index","_componentCount","_componentType","_stride","_byteOffset","_normalized","RenderPrimitiveAttributeBuffer","_attributes","RenderPrimitive","_material","setPrimitive","_mode","_elementCount","_vao","_complete","_attributeBuffers","_attributeMask","attribute","renderAttribute","foundBuffer","attributeBuffer","_indexBuffer","_indexByteOffset","_indexType","material","reject","completionPromises","_samplerDictionary","_uniform_dictionary","RenderTexture","texture","_activeCallback","inverseMatrix","setCap","glEnum","cap","prevState","change","enable","disable","RenderMaterialSampler","materialSampler","_renderTexture","_getRenderTexture","_index","RenderMaterialUniform","materialUniform","_uniform","RenderMaterial","_program","_completeForActiveFrame","renderSampler","renderUniform","_firstBind","_renderOrder","activeTexture","TEXTURE0","bindTexture","TEXTURE_2D","uniform1fv","uniform2fv","uniform3fv","uniform4fv","otherState","Renderer","_frameId","_programCache","_textureCache","_cameraPositions","_vaoExt","getExtension","fragHighPrecision","getShaderPrecisionFormat","HIGH_FLOAT","_defaultFragPrecision","precision","_depthMaskNeedsReset","_colorMaskNeedsReset","_globalLightColor","_globalLightDir","data","STATIC_DRAW","glBuffer","createBuffer","renderBuffer","bindBuffer","bufferData","byteLength","offset","bufferSubData","updateRenderBuffer","_getMaterialProgram","renderMaterial","setRenderMaterial","meshNode","createRenderPrimitive","views","rootNode","vp","width","height","cameraPosition","set","renderPrimitives","_drawRenderPrimitiveSet","bindVertexArrayOES","depthMask","colorMask","attribMask","use","LIGHT_DIRECTION","LIGHT_COLOR","uniformMatrix4fv","PROJECTION_MATRIX","VIEW_MATRIX","CAMERA_POSITION","uniform1i","EYE_INDEX","eyeIndex","_bindMaterialState","bind","createVertexArrayOES","_bindPrimitive","view","instance","MODEL_MATRIX","drawElements","drawArrays","key","textureKey","Error","textureHandle","createTexture","renderTexture","DataTexture","texImage2D","format","_type","_data","_setSamplerParameters","UNSIGNED_BYTE","source","VideoTexture","_video","addEventListener","paused","waiting","powerOfTwo","mipmap","generateMipmap","minFilter","LINEAR_MIPMAP_LINEAR","LINEAR","wrapS","REPEAT","CLAMP_TO_EDGE","wrapT","texParameteri","TEXTURE_MAG_FILTER","magFilter","TEXTURE_MIN_FILTER","TEXTURE_WRAP_S","TEXTURE_WRAP_T","materialName","vertexSource","fragmentSource","getProgramDefines","_getProgramKey","multiview","fullVertexSource","precisionMatch","match","fragPrecisionHeader","fullFragmentSource","onNextUse","enableVertexAttribArray","disableVertexAttribArray","ARRAY_BUFFER","vertexAttribPointer","ELEMENT_ARRAY_BUFFER","prevMaterial","_capsDiff","colorMaskChange","depthMaskChange","stencilMaskChange","stencilMask","_blendDiff","blendFunc","_depthFuncDiff","TextureSampler","Texture","RGBA","ImageTexture","img","_img","_imgBitmap","src","complete","naturalWidth","_finishImage","window","createImageBitmap","imgBitmap","UrlTexture","url","Image","BlobTexture","blob","URL","createObjectURL","video","readyState","videoWidth","videoHeight","nextDataTextureIndex","type","_width","_height","_format","_key","ColorTexture","r","g","b","a","colorData","Uint8Array","PrimitiveStream","BoxBuilder","PbrMaterial","mat3","vec4","BoundsRenderer","ButtonNode","DropShadowNode","CubeSeaNode","Gltf2Node","SkyboxNode","VideoNode","WebXRView","Scene","FallbackHelper","QueryArgs","stream","primitiveStream","w","h","d","wh","hh","dh","cx","cy","cz","startGeometry","idx","nextVertexIndex","pushTriangle","pushVertex","endGeometry","center","size","hs","pushBox","GeometryBuilderBase","tempVec3","options","_vertices","_indices","_geometryStarted","_vertexOffset","_vertexIndex","_highIndex","_flipWinding","_invertNormals","_transform","_normalTransform","u","v","nx","ny","nz","transformMat3","Math","idxA","idxB","idxC","vertexBuffer","createRenderBuffer","Uint16Array","attribs","FLOAT","setIndexBuffer","setBounds","fromMat4","_stream","finishPrimitive","clear","GLB_MAGIC","CHUNK_TYPE","JSON","BIN","isAbsoluteUri","uri","absRegEx","location","protocol","isDataUri","dataRegEx","resolveUri","baseUrl","getComponentCount","Gltf2Loader","fetch","response","lastIndexOf","substring","endsWith","json","loadFromJson","arrayBuffer","loadFromBinary","headerView","DataView","magic","getUint32","version","chunks","chunkOffset","chunkHeaderView","chunkLength","chunkType","slice","decoder","TextDecoder","jsonString","decode","parse","binaryChunk","asset","minVersion","buffers","Gltf2Resource","bufferViews","bufferView","Gltf2BufferView","images","image","textures","glTexture","getTexture","textureInfo","materials","glMaterial","pbr","pbrMetallicRoughness","baseColorFactor","baseColor","baseColorTexture","metallicRoughnessFactor","metallicFactor","roughnessFactor","metallicRoughness","metallicRoughnessTexture","normal","normalTexture","occlusion","occlusionTexture","occlusionStrength","strength","emissiveFactor","emissive","emissiveTexture","alphaMode","blend","cullFace","doubleSided","accessors","meshes","mesh","glMesh","Gltf2Mesh","primitives","accessor","count","glAttribute","byteStride","glPrimitive","indices","sceneNode","scene","scenes","nodes","nodeId","processNodes","glNode","matrix","translation","rotation","scale","_viewPromise","_renderBuffer","dataView","_dataPromise","base64String","binaryArray","from","atob","c","charCodeAt","Blob","mimeType","VERTEX_SOURCE","EPIC_PBR_FUNCTIONS","FRAGMENT_SOURCE","defineSampler","defineUniform","programDefines","glMatrix","mat2","mat2d","quat2","vec2","normalMat","RAY_INTERSECTION_OFFSET","_dir","dir","bounds","tmin","sign","inv_dir","tmax","tymin","tymax","tzmin","tzmax","t","intersectionPoint","add","normalize","BoundsMaterial","ONE","depthTest","_stageBounds","stageBounds","verts","pointCount","geometry","point","BUTTON_SIZE","BUTTON_CORNER_RADIUS","BUTTON_CORNER_SEGMENTS","BUTTON_ICON_SIZE","BUTTON_LAYER_DISTANCE","BUTTON_COLOR","BUTTON_ALPHA","BUTTON_HOVER_COLOR","BUTTON_HOVER_ALPHA","BUTTON_HOVER_SCALE","BUTTON_HOVER_TRANSITION_TIME_MS","ButtonMaterial","ButtonIconMaterial","icon","iconTexture","_iconTexture","_hovered","_hoverT","hd","ihs","segments","rad","PI","cos","sin","section","floor","buttonPrimitive","_buttonRenderPrimitive","iconPrimitive","iconMaterial","_iconRenderPrimitive","hoverAmount","uniforms","_updateHoverState","samplers","CubeSeaMaterial","heavy","heavyGpu","cubeCount","cubeScale","halfOnly","autoRotate","imageUrl","_renderPrimitive","boxBuilder","pushCube","heroPrimitive","heroNode","createMesh","rebuildCubes","cubeSeaNode","halfGrid","pos","cubeSeaPrimitive","fromRotation","SHADOW_SEGMENTS","SHADOW_GROUND_OFFSET","SHADOW_CENTER_ALPHA","SHADOW_INNER_ALPHA","SHADOW_OUTER_ALPHA","SHADOW_INNER_RADIUS","SHADOW_OUTER_RADIUS","DropShadowMaterial","LEQUAL","segRad","shadowPrimitive","_shadowRenderPrimitive","gltfLoaderMap","WeakMap","_url","_resolver","_rejecter","loader","get","_ensurePromise","loadFromUrl","catch","err","LASER_TEXTURE_DATA","LASER_LENGTH","LASER_DIAMETER","LASER_FADE_END","LASER_FADE_POINT","LASER_DEFAULT_COLOR","CURSOR_RADIUS","CURSOR_SHADOW_RADIUS","CURSOR_SHADOW_INNER_LUMINANCE","CURSOR_SHADOW_OUTER_LUMINANCE","CURSOR_SHADOW_INNER_OPACITY","CURSOR_SHADOW_OUTER_OPACITY","CURSOR_OPACITY","CURSOR_SEGMENTS","CURSOR_DEFAULT_COLOR","CURSOR_DEFAULT_HIDDEN_COLOR","DEFAULT_RESET_OPTIONS","controllers","lasers","cursors","LaserMaterial","laser","laserColor","CURSOR_VERTEX_SHADER","CURSOR_FRAGMENT_SHADER","CursorMaterial","cursorColor","CursorHiddenMaterial","GEQUAL","InputRenderer","_maxInputElements","_controllers","_controllerNode","_controllerNodeHandedness","_lasers","_cursors","_activeControllers","_activeLasers","_activeCursors","controllerNode","handedness","gripMatrix","controller","targetRay","_createLaserMesh","cursorPos","_createCursorMesh","cursor","lr","ll","laserVerts","laserIndices","laserVertexBuffer","laserIndexBuffer","laserIndexCount","laserAttribs","laserPrimitive","laserMaterial","laserRenderPrimitive","cursorVerts","cursorIndices","indexOffset","cursorVertexBuffer","cursorIndexBuffer","cursorIndexCount","cursorAttribs","cursorPrimitive","cursorMaterial","cursorHiddenMaterial","cursorRenderPrimitive","cursorHiddenRenderPrimitive","TEXT_KERNING","SevenSegmentMaterial","SevenSegmentText","_text","_charNodes","clearNodes","vertices","segmentIndices","thickness","defineSegment","id","left","top","right","bottom","characters","defineCharacter","character","segment","vertexAttribs","_charPrimitives","char","charDef","text","charPrimitive","SkyboxMaterial","texCoordScaleOffset","_displayMode","displayMode","_rotationY","rotationY","latSegments","lonSegments","theta","sinTheta","cosTheta","idxOffsetA","idxOffsetB","j","phi","SEGMENTS","MAX_FPS","StatsMaterial","segmentToX","fpsToY","fpsToRGB","now","performance","Date","StatsViewer","_performanceMonitoring","_startTime","_prevFrameTime","_prevGraphUpdateTime","_frames","_fpsAverage","_fpsMin","_fpsStep","_lastSegment","_fpsVertexBuffer","_fpsRenderPrimitive","_fpsNode","_sevenSegmentNode","fpsVerts","fpsIndices","addBGSquare","DYNAMIC_DRAW","fpsIndexBuffer","fpsAttribs","fpsPrimitive","time","frameFps","intervalTime","round","_updateGraph","log","valueLow","valueHigh","color","y0","y1","updateVerts","VideoMaterial","_video_texture","pose","layer","getViewMatrix","getViewport","_timestamp","_frameDelta","_statsStanding","_stats","_statsEnabled","enableStats","_inputRenderer","_resetInputEndFrame","_lastTimestamp","_hoverFrame","_hoveredNodes","frame","frameOfRef","session","getInputSources","inputSources","newHoveredNodes","lastHoverFrame","inputSource","inputPose","getInputPose","inputRenderer","addController","targetRayMode","addLaserPointer","hitResult","addCursor","onHoverStart","cursorDistance","direction","hoverNode","onHoverEnd","handleSelectPointer","handleSelect","fromEuler","drawViewArray","xrFrame","baseLayer","bindFramebuffer","FRAMEBUFFER","framebuffer","COLOR_BUFFER_BIT","DEPTH_BUFFER_BIT","drawViews","prevTimestamp","begin","reset","end","LOOK_SPEED","_emulateStage","lookYaw","lookPitch","identity","onResize","canvas","offsetWidth","devicePixelRatio","offsetHeight","perspective","drawingBufferWidth","drawingBufferHeight","lastTouchX","lastTouchY","ev","touches","pageX","pageY","onLook","buttons","movementX","movementY","preventDefault","boundOnFrame","onFrame","requestAnimationFrame","yaw","pitch","updateView","startFrame","draw","endFrame","rotateX","rotateY","translate","urlArgs","onhashchange","ensureArgsCached","query","search","hash","vars","split","pair","toLowerCase","decodeURIComponent","lcaseName","parseInt","parseFloat"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;ACVA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA,yDAAiD,cAAc;AAC/D;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;;AAGA;AACA;;;;;;;;;;;;;;;;;;;ACnEA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7DA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChbA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjdA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,UAAU,KAAK;AACf,UAAU,KAAK;AACf;AACA,YAAY,KAAK;AACjB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,UAAU,KAAK;AACf,UAAU,KAAK;AACf;AACA,YAAY,KAAK;AACjB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;AAIA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5vBA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,YAAY,WAAW,WAAW;AAClC;AACA;AACA;AACA;;AAEA,YAAY,WAAW,YAAY;AACnC;AACA;AACA;AACA;;AAEA,aAAa,YAAY,YAAY;AACrC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH,eAAe,YAAY,YAAY;AACvC,eAAe,YAAY,YAAY;AACvC,eAAe,YAAY,aAAa;;AAExC,iBAAiB,cAAc,cAAc;AAC7C,iBAAiB,cAAc,cAAc;AAC7C,iBAAiB,cAAc,eAAe;;AAE9C;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,2EAAyC,aAAa;;AAEtD;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,aAAa,YAAY,YAAY;AACrC,aAAa,YAAY,YAAY;AACrC,aAAa,YAAY,aAAa;;AAEtC;AACA,sBAAsB,yBAAyB;AAC/C,0BAA0B,qBAAqB;AAC/C,0BAA0B,yBAAyB;;AAEnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;;AAEA,2EAAyC,aAAa;;AAEtD;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,YAAY,KAAK;AACjB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB;AACA,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9rDA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB,YAAY,OAAO;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,oCAAoC;AACpC;AACA,sBAAsB;AACtB;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,EAAE;AACb,WAAW,EAAE;AACb,WAAW,EAAE;AACb,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjnBD;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,MAAM;AAClB,YAAY,KAAK;AACjB;AACA;;AAEA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,MAAM;AAClB,YAAY,KAAK;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,MAAM;AAClB,YAAY,KAAK;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC11BA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA,mBAAmB,OAAO;AAC1B,oBAAoB;AACpB;AACA,oBAAoB;AACpB;;AAEA;AACA;AACA,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvkBD;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA,mBAAmB,OAAO;AAC1B,oBAAoB,iBAAiB;AACrC;AACA,oBAAoB,iBAAiB;AACrC;;AAEA;AACA;AACA,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClxBD;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA,cA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","file":"cottontail.debug.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse {\n\t\tvar a = factory();\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/cottontail.js\");\n","/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. */\r\n\r\n/**\r\n * Common utilities\r\n * @module glMatrix\r\n */\r\n\r\n// Configuration Constants\r\nexport const EPSILON = 0.000001;\r\nexport let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;\r\nexport const RANDOM = Math.random;\r\n\r\n/**\r\n * Sets the type of array used when creating new vectors and matrices\r\n *\r\n * @param {Type} type Array type, such as Float32Array or Array\r\n */\r\nexport function setMatrixArrayType(type) {\r\n ARRAY_TYPE = type;\r\n}\r\n\r\nconst degree = Math.PI / 180;\r\n\r\n/**\r\n * Convert Degree To Radian\r\n *\r\n * @param {Number} a Angle in Degrees\r\n */\r\nexport function toRadian(a) {\r\n return a * degree;\r\n}\r\n\r\n/**\r\n * Tests whether or not the arguments have approximately the same value, within an absolute\r\n * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less\r\n * than or equal to 1.0, and a relative tolerance is used for larger values)\r\n *\r\n * @param {Number} a The first number to test.\r\n * @param {Number} b The second number to test.\r\n * @returns {Boolean} True if the numbers are approximately equal, false otherwise.\r\n */\r\nexport function equals(a, b) {\r\n return Math.abs(a - b) <= EPSILON*Math.max(1.0, Math.abs(a), Math.abs(b));\r\n}\r\n","/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. */\r\n\r\nimport * as glMatrix from \"./common.js\"\r\n\r\n/**\r\n * 2x2 Matrix\r\n * @module mat2\r\n */\r\n\r\n/**\r\n * Creates a new identity mat2\r\n *\r\n * @returns {mat2} a new 2x2 matrix\r\n */\r\nexport function create() {\r\n let out = new glMatrix.ARRAY_TYPE(4);\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a new mat2 initialized with values from an existing matrix\r\n *\r\n * @param {mat2} a matrix to clone\r\n * @returns {mat2} a new 2x2 matrix\r\n */\r\nexport function clone(a) {\r\n let out = new glMatrix.ARRAY_TYPE(4);\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Copy the values from one mat2 to another\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @param {mat2} a the source matrix\r\n * @returns {mat2} out\r\n */\r\nexport function copy(out, a) {\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Set a mat2 to the identity matrix\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @returns {mat2} out\r\n */\r\nexport function identity(out) {\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Create a new mat2 with the given values\r\n *\r\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n * @param {Number} m10 Component in column 1, row 0 position (index 2)\r\n * @param {Number} m11 Component in column 1, row 1 position (index 3)\r\n * @returns {mat2} out A new 2x2 matrix\r\n */\r\nexport function fromValues(m00, m01, m10, m11) {\r\n let out = new glMatrix.ARRAY_TYPE(4);\r\n out[0] = m00;\r\n out[1] = m01;\r\n out[2] = m10;\r\n out[3] = m11;\r\n return out;\r\n}\r\n\r\n/**\r\n * Set the components of a mat2 to the given values\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n * @param {Number} m10 Component in column 1, row 0 position (index 2)\r\n * @param {Number} m11 Component in column 1, row 1 position (index 3)\r\n * @returns {mat2} out\r\n */\r\nexport function set(out, m00, m01, m10, m11) {\r\n out[0] = m00;\r\n out[1] = m01;\r\n out[2] = m10;\r\n out[3] = m11;\r\n return out;\r\n}\r\n\r\n/**\r\n * Transpose the values of a mat2\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @param {mat2} a the source matrix\r\n * @returns {mat2} out\r\n */\r\nexport function transpose(out, a) {\r\n // If we are transposing ourselves we can skip a few steps but have to cache\r\n // some values\r\n if (out === a) {\r\n let a1 = a[1];\r\n out[1] = a[2];\r\n out[2] = a1;\r\n } else {\r\n out[0] = a[0];\r\n out[1] = a[2];\r\n out[2] = a[1];\r\n out[3] = a[3];\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Inverts a mat2\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @param {mat2} a the source matrix\r\n * @returns {mat2} out\r\n */\r\nexport function invert(out, a) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\r\n\r\n // Calculate the determinant\r\n let det = a0 * a3 - a2 * a1;\r\n\r\n if (!det) {\r\n return null;\r\n }\r\n det = 1.0 / det;\r\n\r\n out[0] = a3 * det;\r\n out[1] = -a1 * det;\r\n out[2] = -a2 * det;\r\n out[3] = a0 * det;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the adjugate of a mat2\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @param {mat2} a the source matrix\r\n * @returns {mat2} out\r\n */\r\nexport function adjoint(out, a) {\r\n // Caching this value is nessecary if out == a\r\n let a0 = a[0];\r\n out[0] = a[3];\r\n out[1] = -a[1];\r\n out[2] = -a[2];\r\n out[3] = a0;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the determinant of a mat2\r\n *\r\n * @param {mat2} a the source matrix\r\n * @returns {Number} determinant of a\r\n */\r\nexport function determinant(a) {\r\n return a[0] * a[3] - a[2] * a[1];\r\n}\r\n\r\n/**\r\n * Multiplies two mat2's\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @param {mat2} a the first operand\r\n * @param {mat2} b the second operand\r\n * @returns {mat2} out\r\n */\r\nexport function multiply(out, a, b) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\r\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\r\n out[0] = a0 * b0 + a2 * b1;\r\n out[1] = a1 * b0 + a3 * b1;\r\n out[2] = a0 * b2 + a2 * b3;\r\n out[3] = a1 * b2 + a3 * b3;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a mat2 by the given angle\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @param {mat2} a the matrix to rotate\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat2} out\r\n */\r\nexport function rotate(out, a, rad) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\r\n let s = Math.sin(rad);\r\n let c = Math.cos(rad);\r\n out[0] = a0 * c + a2 * s;\r\n out[1] = a1 * c + a3 * s;\r\n out[2] = a0 * -s + a2 * c;\r\n out[3] = a1 * -s + a3 * c;\r\n return out;\r\n}\r\n\r\n/**\r\n * Scales the mat2 by the dimensions in the given vec2\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @param {mat2} a the matrix to rotate\r\n * @param {vec2} v the vec2 to scale the matrix by\r\n * @returns {mat2} out\r\n **/\r\nexport function scale(out, a, v) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\r\n let v0 = v[0], v1 = v[1];\r\n out[0] = a0 * v0;\r\n out[1] = a1 * v0;\r\n out[2] = a2 * v1;\r\n out[3] = a3 * v1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a given angle\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat2.identity(dest);\r\n * mat2.rotate(dest, dest, rad);\r\n *\r\n * @param {mat2} out mat2 receiving operation result\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat2} out\r\n */\r\nexport function fromRotation(out, rad) {\r\n let s = Math.sin(rad);\r\n let c = Math.cos(rad);\r\n out[0] = c;\r\n out[1] = s;\r\n out[2] = -s;\r\n out[3] = c;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a vector scaling\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat2.identity(dest);\r\n * mat2.scale(dest, dest, vec);\r\n *\r\n * @param {mat2} out mat2 receiving operation result\r\n * @param {vec2} v Scaling vector\r\n * @returns {mat2} out\r\n */\r\nexport function fromScaling(out, v) {\r\n out[0] = v[0];\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = v[1];\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns a string representation of a mat2\r\n *\r\n * @param {mat2} a matrix to represent as a string\r\n * @returns {String} string representation of the matrix\r\n */\r\nexport function str(a) {\r\n return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\r\n}\r\n\r\n/**\r\n * Returns Frobenius norm of a mat2\r\n *\r\n * @param {mat2} a the matrix to calculate Frobenius norm of\r\n * @returns {Number} Frobenius norm\r\n */\r\nexport function frob(a) {\r\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)))\r\n}\r\n\r\n/**\r\n * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix\r\n * @param {mat2} L the lower triangular matrix\r\n * @param {mat2} D the diagonal matrix\r\n * @param {mat2} U the upper triangular matrix\r\n * @param {mat2} a the input matrix to factorize\r\n */\r\n\r\nexport function LDU(L, D, U, a) {\r\n L[2] = a[2]/a[0];\r\n U[0] = a[0];\r\n U[1] = a[1];\r\n U[3] = a[3] - L[2] * U[1];\r\n return [L, D, U];\r\n}\r\n\r\n/**\r\n * Adds two mat2's\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @param {mat2} a the first operand\r\n * @param {mat2} b the second operand\r\n * @returns {mat2} out\r\n */\r\nexport function add(out, a, b) {\r\n out[0] = a[0] + b[0];\r\n out[1] = a[1] + b[1];\r\n out[2] = a[2] + b[2];\r\n out[3] = a[3] + b[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Subtracts matrix b from matrix a\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @param {mat2} a the first operand\r\n * @param {mat2} b the second operand\r\n * @returns {mat2} out\r\n */\r\nexport function subtract(out, a, b) {\r\n out[0] = a[0] - b[0];\r\n out[1] = a[1] - b[1];\r\n out[2] = a[2] - b[2];\r\n out[3] = a[3] - b[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\r\n *\r\n * @param {mat2} a The first matrix.\r\n * @param {mat2} b The second matrix.\r\n * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n */\r\nexport function exactEquals(a, b) {\r\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];\r\n}\r\n\r\n/**\r\n * Returns whether or not the matrices have approximately the same elements in the same position.\r\n *\r\n * @param {mat2} a The first matrix.\r\n * @param {mat2} b The second matrix.\r\n * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n */\r\nexport function equals(a, b) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\r\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\r\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\r\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));\r\n}\r\n\r\n/**\r\n * Multiply each element of the matrix by a scalar.\r\n *\r\n * @param {mat2} out the receiving matrix\r\n * @param {mat2} a the matrix to scale\r\n * @param {Number} b amount to scale the matrix's elements by\r\n * @returns {mat2} out\r\n */\r\nexport function multiplyScalar(out, a, b) {\r\n out[0] = a[0] * b;\r\n out[1] = a[1] * b;\r\n out[2] = a[2] * b;\r\n out[3] = a[3] * b;\r\n return out;\r\n}\r\n\r\n/**\r\n * Adds two mat2's after multiplying each element of the second operand by a scalar value.\r\n *\r\n * @param {mat2} out the receiving vector\r\n * @param {mat2} a the first operand\r\n * @param {mat2} b the second operand\r\n * @param {Number} scale the amount to scale b's elements by before adding\r\n * @returns {mat2} out\r\n */\r\nexport function multiplyScalarAndAdd(out, a, b, scale) {\r\n out[0] = a[0] + (b[0] * scale);\r\n out[1] = a[1] + (b[1] * scale);\r\n out[2] = a[2] + (b[2] * scale);\r\n out[3] = a[3] + (b[3] * scale);\r\n return out;\r\n}\r\n\r\n/**\r\n * Alias for {@link mat2.multiply}\r\n * @function\r\n */\r\nexport const mul = multiply;\r\n\r\n/**\r\n * Alias for {@link mat2.subtract}\r\n * @function\r\n */\r\nexport const sub = subtract;\r\n","/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. */\r\n\r\nimport * as glMatrix from \"./common.js\";\r\n\r\n/**\r\n * 2x3 Matrix\r\n * @module mat2d\r\n *\r\n * @description\r\n * A mat2d contains six elements defined as:\r\n * <pre>\r\n * [a, c, tx,\r\n * b, d, ty]\r\n * </pre>\r\n * This is a short form for the 3x3 matrix:\r\n * <pre>\r\n * [a, c, tx,\r\n * b, d, ty,\r\n * 0, 0, 1]\r\n * </pre>\r\n * The last row is ignored so the array is shorter and operations are faster.\r\n */\r\n\r\n/**\r\n * Creates a new identity mat2d\r\n *\r\n * @returns {mat2d} a new 2x3 matrix\r\n */\r\nexport function create() {\r\n let out = new glMatrix.ARRAY_TYPE(6);\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 1;\r\n out[4] = 0;\r\n out[5] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a new mat2d initialized with values from an existing matrix\r\n *\r\n * @param {mat2d} a matrix to clone\r\n * @returns {mat2d} a new 2x3 matrix\r\n */\r\nexport function clone(a) {\r\n let out = new glMatrix.ARRAY_TYPE(6);\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n out[4] = a[4];\r\n out[5] = a[5];\r\n return out;\r\n}\r\n\r\n/**\r\n * Copy the values from one mat2d to another\r\n *\r\n * @param {mat2d} out the receiving matrix\r\n * @param {mat2d} a the source matrix\r\n * @returns {mat2d} out\r\n */\r\nexport function copy(out, a) {\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n out[4] = a[4];\r\n out[5] = a[5];\r\n return out;\r\n}\r\n\r\n/**\r\n * Set a mat2d to the identity matrix\r\n *\r\n * @param {mat2d} out the receiving matrix\r\n * @returns {mat2d} out\r\n */\r\nexport function identity(out) {\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 1;\r\n out[4] = 0;\r\n out[5] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Create a new mat2d with the given values\r\n *\r\n * @param {Number} a Component A (index 0)\r\n * @param {Number} b Component B (index 1)\r\n * @param {Number} c Component C (index 2)\r\n * @param {Number} d Component D (index 3)\r\n * @param {Number} tx Component TX (index 4)\r\n * @param {Number} ty Component TY (index 5)\r\n * @returns {mat2d} A new mat2d\r\n */\r\nexport function fromValues(a, b, c, d, tx, ty) {\r\n let out = new glMatrix.ARRAY_TYPE(6);\r\n out[0] = a;\r\n out[1] = b;\r\n out[2] = c;\r\n out[3] = d;\r\n out[4] = tx;\r\n out[5] = ty;\r\n return out;\r\n}\r\n\r\n/**\r\n * Set the components of a mat2d to the given values\r\n *\r\n * @param {mat2d} out the receiving matrix\r\n * @param {Number} a Component A (index 0)\r\n * @param {Number} b Component B (index 1)\r\n * @param {Number} c Component C (index 2)\r\n * @param {Number} d Component D (index 3)\r\n * @param {Number} tx Component TX (index 4)\r\n * @param {Number} ty Component TY (index 5)\r\n * @returns {mat2d} out\r\n */\r\nexport function set(out, a, b, c, d, tx, ty) {\r\n out[0] = a;\r\n out[1] = b;\r\n out[2] = c;\r\n out[3] = d;\r\n out[4] = tx;\r\n out[5] = ty;\r\n return out;\r\n}\r\n\r\n/**\r\n * Inverts a mat2d\r\n *\r\n * @param {mat2d} out the receiving matrix\r\n * @param {mat2d} a the source matrix\r\n * @returns {mat2d} out\r\n */\r\nexport function invert(out, a) {\r\n let aa = a[0], ab = a[1], ac = a[2], ad = a[3];\r\n let atx = a[4], aty = a[5];\r\n\r\n let det = aa * ad - ab * ac;\r\n if(!det){\r\n return null;\r\n }\r\n det = 1.0 / det;\r\n\r\n out[0] = ad * det;\r\n out[1] = -ab * det;\r\n out[2] = -ac * det;\r\n out[3] = aa * det;\r\n out[4] = (ac * aty - ad * atx) * det;\r\n out[5] = (ab * atx - aa * aty) * det;\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the determinant of a mat2d\r\n *\r\n * @param {mat2d} a the source matrix\r\n * @returns {Number} determinant of a\r\n */\r\nexport function determinant(a) {\r\n return a[0] * a[3] - a[1] * a[2];\r\n}\r\n\r\n/**\r\n * Multiplies two mat2d's\r\n *\r\n * @param {mat2d} out the receiving matrix\r\n * @param {mat2d} a the first operand\r\n * @param {mat2d} b the second operand\r\n * @returns {mat2d} out\r\n */\r\nexport function multiply(out, a, b) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\r\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];\r\n out[0] = a0 * b0 + a2 * b1;\r\n out[1] = a1 * b0 + a3 * b1;\r\n out[2] = a0 * b2 + a2 * b3;\r\n out[3] = a1 * b2 + a3 * b3;\r\n out[4] = a0 * b4 + a2 * b5 + a4;\r\n out[5] = a1 * b4 + a3 * b5 + a5;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a mat2d by the given angle\r\n *\r\n * @param {mat2d} out the receiving matrix\r\n * @param {mat2d} a the matrix to rotate\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat2d} out\r\n */\r\nexport function rotate(out, a, rad) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\r\n let s = Math.sin(rad);\r\n let c = Math.cos(rad);\r\n out[0] = a0 * c + a2 * s;\r\n out[1] = a1 * c + a3 * s;\r\n out[2] = a0 * -s + a2 * c;\r\n out[3] = a1 * -s + a3 * c;\r\n out[4] = a4;\r\n out[5] = a5;\r\n return out;\r\n}\r\n\r\n/**\r\n * Scales the mat2d by the dimensions in the given vec2\r\n *\r\n * @param {mat2d} out the receiving matrix\r\n * @param {mat2d} a the matrix to translate\r\n * @param {vec2} v the vec2 to scale the matrix by\r\n * @returns {mat2d} out\r\n **/\r\nexport function scale(out, a, v) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\r\n let v0 = v[0], v1 = v[1];\r\n out[0] = a0 * v0;\r\n out[1] = a1 * v0;\r\n out[2] = a2 * v1;\r\n out[3] = a3 * v1;\r\n out[4] = a4;\r\n out[5] = a5;\r\n return out;\r\n}\r\n\r\n/**\r\n * Translates the mat2d by the dimensions in the given vec2\r\n *\r\n * @param {mat2d} out the receiving matrix\r\n * @param {mat2d} a the matrix to translate\r\n * @param {vec2} v the vec2 to translate the matrix by\r\n * @returns {mat2d} out\r\n **/\r\nexport function translate(out, a, v) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\r\n let v0 = v[0], v1 = v[1];\r\n out[0] = a0;\r\n out[1] = a1;\r\n out[2] = a2;\r\n out[3] = a3;\r\n out[4] = a0 * v0 + a2 * v1 + a4;\r\n out[5] = a1 * v0 + a3 * v1 + a5;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a given angle\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat2d.identity(dest);\r\n * mat2d.rotate(dest, dest, rad);\r\n *\r\n * @param {mat2d} out mat2d receiving operation result\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat2d} out\r\n */\r\nexport function fromRotation(out, rad) {\r\n let s = Math.sin(rad), c = Math.cos(rad);\r\n out[0] = c;\r\n out[1] = s;\r\n out[2] = -s;\r\n out[3] = c;\r\n out[4] = 0;\r\n out[5] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a vector scaling\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat2d.identity(dest);\r\n * mat2d.scale(dest, dest, vec);\r\n *\r\n * @param {mat2d} out mat2d receiving operation result\r\n * @param {vec2} v Scaling vector\r\n * @returns {mat2d} out\r\n */\r\nexport function fromScaling(out, v) {\r\n out[0] = v[0];\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = v[1];\r\n out[4] = 0;\r\n out[5] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a vector translation\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat2d.identity(dest);\r\n * mat2d.translate(dest, dest, vec);\r\n *\r\n * @param {mat2d} out mat2d receiving operation result\r\n * @param {vec2} v Translation vector\r\n * @returns {mat2d} out\r\n */\r\nexport function fromTranslation(out, v) {\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 1;\r\n out[4] = v[0];\r\n out[5] = v[1];\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns a string representation of a mat2d\r\n *\r\n * @param {mat2d} a matrix to represent as a string\r\n * @returns {String} string representation of the matrix\r\n */\r\nexport function str(a) {\r\n return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +\r\n a[3] + ', ' + a[4] + ', ' + a[5] + ')';\r\n}\r\n\r\n/**\r\n * Returns Frobenius norm of a mat2d\r\n *\r\n * @param {mat2d} a the matrix to calculate Frobenius norm of\r\n * @returns {Number} Frobenius norm\r\n */\r\nexport function frob(a) {\r\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1))\r\n}\r\n\r\n/**\r\n * Adds two mat2d's\r\n *\r\n * @param {mat2d} out the receiving matrix\r\n * @param {mat2d} a the first operand\r\n * @param {mat2d} b the second operand\r\n * @returns {mat2d} out\r\n */\r\nexport function add(out, a, b) {\r\n out[0] = a[0] + b[0];\r\n out[1] = a[1] + b[1];\r\n out[2] = a[2] + b[2];\r\n out[3] = a[3] + b[3];\r\n out[4] = a[4] + b[4];\r\n out[5] = a[5] + b[5];\r\n return out;\r\n}\r\n\r\n/**\r\n * Subtracts matrix b from matrix a\r\n *\r\n * @param {mat2d} out the receiving matrix\r\n * @param {mat2d} a the first operand\r\n * @param {mat2d} b the second operand\r\n * @returns {mat2d} out\r\n */\r\nexport function subtract(out, a, b) {\r\n out[0] = a[0] - b[0];\r\n out[1] = a[1] - b[1];\r\n out[2] = a[2] - b[2];\r\n out[3] = a[3] - b[3];\r\n out[4] = a[4] - b[4];\r\n out[5] = a[5] - b[5];\r\n return out;\r\n}\r\n\r\n/**\r\n * Multiply each element of the matrix by a scalar.\r\n *\r\n * @param {mat2d} out the receiving matrix\r\n * @param {mat2d} a the matrix to scale\r\n * @param {Number} b amount to scale the matrix's elements by\r\n * @returns {mat2d} out\r\n */\r\nexport function multiplyScalar(out, a, b) {\r\n out[0] = a[0] * b;\r\n out[1] = a[1] * b;\r\n out[2] = a[2] * b;\r\n out[3] = a[3] * b;\r\n out[4] = a[4] * b;\r\n out[5] = a[5] * b;\r\n return out;\r\n}\r\n\r\n/**\r\n * Adds two mat2d's after multiplying each element of the second operand by a scalar value.\r\n *\r\n * @param {mat2d} out the receiving vector\r\n * @param {mat2d} a the first operand\r\n * @param {mat2d} b the second operand\r\n * @param {Number} scale the amount to scale b's elements by before adding\r\n * @returns {mat2d} out\r\n */\r\nexport function multiplyScalarAndAdd(out, a, b, scale) {\r\n out[0] = a[0] + (b[0] * scale);\r\n out[1] = a[1] + (b[1] * scale);\r\n out[2] = a[2] + (b[2] * scale);\r\n out[3] = a[3] + (b[3] * scale);\r\n out[4] = a[4] + (b[4] * scale);\r\n out[5] = a[5] + (b[5] * scale);\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\r\n *\r\n * @param {mat2d} a The first matrix.\r\n * @param {mat2d} b The second matrix.\r\n * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n */\r\nexport function exactEquals(a, b) {\r\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];\r\n}\r\n\r\n/**\r\n * Returns whether or not the matrices have approximately the same elements in the same position.\r\n *\r\n * @param {mat2d} a The first matrix.\r\n * @param {mat2d} b The second matrix.\r\n * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n */\r\nexport function equals(a, b) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\r\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];\r\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\r\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\r\n Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\r\n Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)));\r\n}\r\n\r\n/**\r\n * Alias for {@link mat2d.multiply}\r\n * @function\r\n */\r\nexport const mul = multiply;\r\n\r\n/**\r\n * Alias for {@link mat2d.subtract}\r\n * @function\r\n */\r\nexport const sub = subtract;\r\n","/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. */\r\n\r\nimport * as glMatrix from \"./common.js\";\r\n\r\n/**\r\n * 3x3 Matrix\r\n * @module mat3\r\n */\r\n\r\n/**\r\n * Creates a new identity mat3\r\n *\r\n * @returns {mat3} a new 3x3 matrix\r\n */\r\nexport function create() {\r\n let out = new glMatrix.ARRAY_TYPE(9);\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = 1;\r\n out[5] = 0;\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Copies the upper-left 3x3 values into the given mat3.\r\n *\r\n * @param {mat3} out the receiving 3x3 matrix\r\n * @param {mat4} a the source 4x4 matrix\r\n * @returns {mat3} out\r\n */\r\nexport function fromMat4(out, a) {\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[4];\r\n out[4] = a[5];\r\n out[5] = a[6];\r\n out[6] = a[8];\r\n out[7] = a[9];\r\n out[8] = a[10];\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a new mat3 initialized with values from an existing matrix\r\n *\r\n * @param {mat3} a matrix to clone\r\n * @returns {mat3} a new 3x3 matrix\r\n */\r\nexport function clone(a) {\r\n let out = new glMatrix.ARRAY_TYPE(9);\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n out[4] = a[4];\r\n out[5] = a[5];\r\n out[6] = a[6];\r\n out[7] = a[7];\r\n out[8] = a[8];\r\n return out;\r\n}\r\n\r\n/**\r\n * Copy the values from one mat3 to another\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat3} a the source matrix\r\n * @returns {mat3} out\r\n */\r\nexport function copy(out, a) {\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n out[4] = a[4];\r\n out[5] = a[5];\r\n out[6] = a[6];\r\n out[7] = a[7];\r\n out[8] = a[8];\r\n return out;\r\n}\r\n\r\n/**\r\n * Create a new mat3 with the given values\r\n *\r\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\r\n * @param {Number} m10 Component in column 1, row 0 position (index 3)\r\n * @param {Number} m11 Component in column 1, row 1 position (index 4)\r\n * @param {Number} m12 Component in column 1, row 2 position (index 5)\r\n * @param {Number} m20 Component in column 2, row 0 position (index 6)\r\n * @param {Number} m21 Component in column 2, row 1 position (index 7)\r\n * @param {Number} m22 Component in column 2, row 2 position (index 8)\r\n * @returns {mat3} A new mat3\r\n */\r\nexport function fromValues(m00, m01, m02, m10, m11, m12, m20, m21, m22) {\r\n let out = new glMatrix.ARRAY_TYPE(9);\r\n out[0] = m00;\r\n out[1] = m01;\r\n out[2] = m02;\r\n out[3] = m10;\r\n out[4] = m11;\r\n out[5] = m12;\r\n out[6] = m20;\r\n out[7] = m21;\r\n out[8] = m22;\r\n return out;\r\n}\r\n\r\n/**\r\n * Set the components of a mat3 to the given values\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\r\n * @param {Number} m10 Component in column 1, row 0 position (index 3)\r\n * @param {Number} m11 Component in column 1, row 1 position (index 4)\r\n * @param {Number} m12 Component in column 1, row 2 position (index 5)\r\n * @param {Number} m20 Component in column 2, row 0 position (index 6)\r\n * @param {Number} m21 Component in column 2, row 1 position (index 7)\r\n * @param {Number} m22 Component in column 2, row 2 position (index 8)\r\n * @returns {mat3} out\r\n */\r\nexport function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {\r\n out[0] = m00;\r\n out[1] = m01;\r\n out[2] = m02;\r\n out[3] = m10;\r\n out[4] = m11;\r\n out[5] = m12;\r\n out[6] = m20;\r\n out[7] = m21;\r\n out[8] = m22;\r\n return out;\r\n}\r\n\r\n/**\r\n * Set a mat3 to the identity matrix\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @returns {mat3} out\r\n */\r\nexport function identity(out) {\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = 1;\r\n out[5] = 0;\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Transpose the values of a mat3\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat3} a the source matrix\r\n * @returns {mat3} out\r\n */\r\nexport function transpose(out, a) {\r\n // If we are transposing ourselves we can skip a few steps but have to cache some values\r\n if (out === a) {\r\n let a01 = a[1], a02 = a[2], a12 = a[5];\r\n out[1] = a[3];\r\n out[2] = a[6];\r\n out[3] = a01;\r\n out[5] = a[7];\r\n out[6] = a02;\r\n out[7] = a12;\r\n } else {\r\n out[0] = a[0];\r\n out[1] = a[3];\r\n out[2] = a[6];\r\n out[3] = a[1];\r\n out[4] = a[4];\r\n out[5] = a[7];\r\n out[6] = a[2];\r\n out[7] = a[5];\r\n out[8] = a[8];\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Inverts a mat3\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat3} a the source matrix\r\n * @returns {mat3} out\r\n */\r\nexport function invert(out, a) {\r\n let a00 = a[0], a01 = a[1], a02 = a[2];\r\n let a10 = a[3], a11 = a[4], a12 = a[5];\r\n let a20 = a[6], a21 = a[7], a22 = a[8];\r\n\r\n let b01 = a22 * a11 - a12 * a21;\r\n let b11 = -a22 * a10 + a12 * a20;\r\n let b21 = a21 * a10 - a11 * a20;\r\n\r\n // Calculate the determinant\r\n let det = a00 * b01 + a01 * b11 + a02 * b21;\r\n\r\n if (!det) {\r\n return null;\r\n }\r\n det = 1.0 / det;\r\n\r\n out[0] = b01 * det;\r\n out[1] = (-a22 * a01 + a02 * a21) * det;\r\n out[2] = (a12 * a01 - a02 * a11) * det;\r\n out[3] = b11 * det;\r\n out[4] = (a22 * a00 - a02 * a20) * det;\r\n out[5] = (-a12 * a00 + a02 * a10) * det;\r\n out[6] = b21 * det;\r\n out[7] = (-a21 * a00 + a01 * a20) * det;\r\n out[8] = (a11 * a00 - a01 * a10) * det;\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the adjugate of a mat3\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat3} a the source matrix\r\n * @returns {mat3} out\r\n */\r\nexport function adjoint(out, a) {\r\n let a00 = a[0], a01 = a[1], a02 = a[2];\r\n let a10 = a[3], a11 = a[4], a12 = a[5];\r\n let a20 = a[6], a21 = a[7], a22 = a[8];\r\n\r\n out[0] = (a11 * a22 - a12 * a21);\r\n out[1] = (a02 * a21 - a01 * a22);\r\n out[2] = (a01 * a12 - a02 * a11);\r\n out[3] = (a12 * a20 - a10 * a22);\r\n out[4] = (a00 * a22 - a02 * a20);\r\n out[5] = (a02 * a10 - a00 * a12);\r\n out[6] = (a10 * a21 - a11 * a20);\r\n out[7] = (a01 * a20 - a00 * a21);\r\n out[8] = (a00 * a11 - a01 * a10);\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the determinant of a mat3\r\n *\r\n * @param {mat3} a the source matrix\r\n * @returns {Number} determinant of a\r\n */\r\nexport function determinant(a) {\r\n let a00 = a[0], a01 = a[1], a02 = a[2];\r\n let a10 = a[3], a11 = a[4], a12 = a[5];\r\n let a20 = a[6], a21 = a[7], a22 = a[8];\r\n\r\n return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);\r\n}\r\n\r\n/**\r\n * Multiplies two mat3's\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat3} a the first operand\r\n * @param {mat3} b the second operand\r\n * @returns {mat3} out\r\n */\r\nexport function multiply(out, a, b) {\r\n let a00 = a[0], a01 = a[1], a02 = a[2];\r\n let a10 = a[3], a11 = a[4], a12 = a[5];\r\n let a20 = a[6], a21 = a[7], a22 = a[8];\r\n\r\n let b00 = b[0], b01 = b[1], b02 = b[2];\r\n let b10 = b[3], b11 = b[4], b12 = b[5];\r\n let b20 = b[6], b21 = b[7], b22 = b[8];\r\n\r\n out[0] = b00 * a00 + b01 * a10 + b02 * a20;\r\n out[1] = b00 * a01 + b01 * a11 + b02 * a21;\r\n out[2] = b00 * a02 + b01 * a12 + b02 * a22;\r\n\r\n out[3] = b10 * a00 + b11 * a10 + b12 * a20;\r\n out[4] = b10 * a01 + b11 * a11 + b12 * a21;\r\n out[5] = b10 * a02 + b11 * a12 + b12 * a22;\r\n\r\n out[6] = b20 * a00 + b21 * a10 + b22 * a20;\r\n out[7] = b20 * a01 + b21 * a11 + b22 * a21;\r\n out[8] = b20 * a02 + b21 * a12 + b22 * a22;\r\n return out;\r\n}\r\n\r\n/**\r\n * Translate a mat3 by the given vector\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat3} a the matrix to translate\r\n * @param {vec2} v vector to translate by\r\n * @returns {mat3} out\r\n */\r\nexport function translate(out, a, v) {\r\n let a00 = a[0], a01 = a[1], a02 = a[2],\r\n a10 = a[3], a11 = a[4], a12 = a[5],\r\n a20 = a[6], a21 = a[7], a22 = a[8],\r\n x = v[0], y = v[1];\r\n\r\n out[0] = a00;\r\n out[1] = a01;\r\n out[2] = a02;\r\n\r\n out[3] = a10;\r\n out[4] = a11;\r\n out[5] = a12;\r\n\r\n out[6] = x * a00 + y * a10 + a20;\r\n out[7] = x * a01 + y * a11 + a21;\r\n out[8] = x * a02 + y * a12 + a22;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a mat3 by the given angle\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat3} a the matrix to rotate\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat3} out\r\n */\r\nexport function rotate(out, a, rad) {\r\n let a00 = a[0], a01 = a[1], a02 = a[2],\r\n a10 = a[3], a11 = a[4], a12 = a[5],\r\n a20 = a[6], a21 = a[7], a22 = a[8],\r\n\r\n s = Math.sin(rad),\r\n c = Math.cos(rad);\r\n\r\n out[0] = c * a00 + s * a10;\r\n out[1] = c * a01 + s * a11;\r\n out[2] = c * a02 + s * a12;\r\n\r\n out[3] = c * a10 - s * a00;\r\n out[4] = c * a11 - s * a01;\r\n out[5] = c * a12 - s * a02;\r\n\r\n out[6] = a20;\r\n out[7] = a21;\r\n out[8] = a22;\r\n return out;\r\n};\r\n\r\n/**\r\n * Scales the mat3 by the dimensions in the given vec2\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat3} a the matrix to rotate\r\n * @param {vec2} v the vec2 to scale the matrix by\r\n * @returns {mat3} out\r\n **/\r\nexport function scale(out, a, v) {\r\n let x = v[0], y = v[1];\r\n\r\n out[0] = x * a[0];\r\n out[1] = x * a[1];\r\n out[2] = x * a[2];\r\n\r\n out[3] = y * a[3];\r\n out[4] = y * a[4];\r\n out[5] = y * a[5];\r\n\r\n out[6] = a[6];\r\n out[7] = a[7];\r\n out[8] = a[8];\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a vector translation\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat3.identity(dest);\r\n * mat3.translate(dest, dest, vec);\r\n *\r\n * @param {mat3} out mat3 receiving operation result\r\n * @param {vec2} v Translation vector\r\n * @returns {mat3} out\r\n */\r\nexport function fromTranslation(out, v) {\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = 1;\r\n out[5] = 0;\r\n out[6] = v[0];\r\n out[7] = v[1];\r\n out[8] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a given angle\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat3.identity(dest);\r\n * mat3.rotate(dest, dest, rad);\r\n *\r\n * @param {mat3} out mat3 receiving operation result\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat3} out\r\n */\r\nexport function fromRotation(out, rad) {\r\n let s = Math.sin(rad), c = Math.cos(rad);\r\n\r\n out[0] = c;\r\n out[1] = s;\r\n out[2] = 0;\r\n\r\n out[3] = -s;\r\n out[4] = c;\r\n out[5] = 0;\r\n\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a vector scaling\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat3.identity(dest);\r\n * mat3.scale(dest, dest, vec);\r\n *\r\n * @param {mat3} out mat3 receiving operation result\r\n * @param {vec2} v Scaling vector\r\n * @returns {mat3} out\r\n */\r\nexport function fromScaling(out, v) {\r\n out[0] = v[0];\r\n out[1] = 0;\r\n out[2] = 0;\r\n\r\n out[3] = 0;\r\n out[4] = v[1];\r\n out[5] = 0;\r\n\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Copies the values from a mat2d into a mat3\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat2d} a the matrix to copy\r\n * @returns {mat3} out\r\n **/\r\nexport function fromMat2d(out, a) {\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = 0;\r\n\r\n out[3] = a[2];\r\n out[4] = a[3];\r\n out[5] = 0;\r\n\r\n out[6] = a[4];\r\n out[7] = a[5];\r\n out[8] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n* Calculates a 3x3 matrix from the given quaternion\r\n*\r\n* @param {mat3} out mat3 receiving operation result\r\n* @param {quat} q Quaternion to create matrix from\r\n*\r\n* @returns {mat3} out\r\n*/\r\nexport function fromQuat(out, q) {\r\n let x = q[0], y = q[1], z = q[2], w = q[3];\r\n let x2 = x + x;\r\n let y2 = y + y;\r\n let z2 = z + z;\r\n\r\n let xx = x * x2;\r\n let yx = y * x2;\r\n let yy = y * y2;\r\n let zx = z * x2;\r\n let zy = z * y2;\r\n let zz = z * z2;\r\n let wx = w * x2;\r\n let wy = w * y2;\r\n let wz = w * z2;\r\n\r\n out[0] = 1 - yy - zz;\r\n out[3] = yx - wz;\r\n out[6] = zx + wy;\r\n\r\n out[1] = yx + wz;\r\n out[4] = 1 - xx - zz;\r\n out[7] = zy - wx;\r\n\r\n out[2] = zx - wy;\r\n out[5] = zy + wx;\r\n out[8] = 1 - xx - yy;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix\r\n*\r\n* @param {mat3} out mat3 receiving operation result\r\n* @param {mat4} a Mat4 to derive the normal matrix from\r\n*\r\n* @returns {mat3} out\r\n*/\r\nexport function normalFromMat4(out, a) {\r\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\r\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\r\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\r\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\r\n\r\n let b00 = a00 * a11 - a01 * a10;\r\n let b01 = a00 * a12 - a02 * a10;\r\n let b02 = a00 * a13 - a03 * a10;\r\n let b03 = a01 * a12 - a02 * a11;\r\n let b04 = a01 * a13 - a03 * a11;\r\n let b05 = a02 * a13 - a03 * a12;\r\n let b06 = a20 * a31 - a21 * a30;\r\n let b07 = a20 * a32 - a22 * a30;\r\n let b08 = a20 * a33 - a23 * a30;\r\n let b09 = a21 * a32 - a22 * a31;\r\n let b10 = a21 * a33 - a23 * a31;\r\n let b11 = a22 * a33 - a23 * a32;\r\n\r\n // Calculate the determinant\r\n let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\r\n\r\n if (!det) {\r\n return null;\r\n }\r\n det = 1.0 / det;\r\n\r\n out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;\r\n out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;\r\n out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;\r\n\r\n out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;\r\n out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;\r\n out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;\r\n\r\n out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;\r\n out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;\r\n out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Generates a 2D projection matrix with the given bounds\r\n *\r\n * @param {mat3} out mat3 frustum matrix will be written into\r\n * @param {number} width Width of your gl context\r\n * @param {number} height Height of gl context\r\n * @returns {mat3} out\r\n */\r\nexport function projection(out, width, height) {\r\n out[0] = 2 / width;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = -2 / height;\r\n out[5] = 0;\r\n out[6] = -1;\r\n out[7] = 1;\r\n out[8] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns a string representation of a mat3\r\n *\r\n * @param {mat3} a matrix to represent as a string\r\n * @returns {String} string representation of the matrix\r\n */\r\nexport function str(a) {\r\n return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +\r\n a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +\r\n a[6] + ', ' + a[7] + ', ' + a[8] + ')';\r\n}\r\n\r\n/**\r\n * Returns Frobenius norm of a mat3\r\n *\r\n * @param {mat3} a the matrix to calculate Frobenius norm of\r\n * @returns {Number} Frobenius norm\r\n */\r\nexport function frob(a) {\r\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2)))\r\n}\r\n\r\n/**\r\n * Adds two mat3's\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat3} a the first operand\r\n * @param {mat3} b the second operand\r\n * @returns {mat3} out\r\n */\r\nexport function add(out, a, b) {\r\n out[0] = a[0] + b[0];\r\n out[1] = a[1] + b[1];\r\n out[2] = a[2] + b[2];\r\n out[3] = a[3] + b[3];\r\n out[4] = a[4] + b[4];\r\n out[5] = a[5] + b[5];\r\n out[6] = a[6] + b[6];\r\n out[7] = a[7] + b[7];\r\n out[8] = a[8] + b[8];\r\n return out;\r\n}\r\n\r\n/**\r\n * Subtracts matrix b from matrix a\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat3} a the first operand\r\n * @param {mat3} b the second operand\r\n * @returns {mat3} out\r\n */\r\nexport function subtract(out, a, b) {\r\n out[0] = a[0] - b[0];\r\n out[1] = a[1] - b[1];\r\n out[2] = a[2] - b[2];\r\n out[3] = a[3] - b[3];\r\n out[4] = a[4] - b[4];\r\n out[5] = a[5] - b[5];\r\n out[6] = a[6] - b[6];\r\n out[7] = a[7] - b[7];\r\n out[8] = a[8] - b[8];\r\n return out;\r\n}\r\n\r\n\r\n\r\n/**\r\n * Multiply each element of the matrix by a scalar.\r\n *\r\n * @param {mat3} out the receiving matrix\r\n * @param {mat3} a the matrix to scale\r\n * @param {Number} b amount to scale the matrix's elements by\r\n * @returns {mat3} out\r\n */\r\nexport function multiplyScalar(out, a, b) {\r\n out[0] = a[0] * b;\r\n out[1] = a[1] * b;\r\n out[2] = a[2] * b;\r\n out[3] = a[3] * b;\r\n out[4] = a[4] * b;\r\n out[5] = a[5] * b;\r\n out[6] = a[6] * b;\r\n out[7] = a[7] * b;\r\n out[8] = a[8] * b;\r\n return out;\r\n}\r\n\r\n/**\r\n * Adds two mat3's after multiplying each element of the second operand by a scalar value.\r\n *\r\n * @param {mat3} out the receiving vector\r\n * @param {mat3} a the first operand\r\n * @param {mat3} b the second operand\r\n * @param {Number} scale the amount to scale b's elements by before adding\r\n * @returns {mat3} out\r\n */\r\nexport function multiplyScalarAndAdd(out, a, b, scale) {\r\n out[0] = a[0] + (b[0] * scale);\r\n out[1] = a[1] + (b[1] * scale);\r\n out[2] = a[2] + (b[2] * scale);\r\n out[3] = a[3] + (b[3] * scale);\r\n out[4] = a[4] + (b[4] * scale);\r\n out[5] = a[5] + (b[5] * scale);\r\n out[6] = a[6] + (b[6] * scale);\r\n out[7] = a[7] + (b[7] * scale);\r\n out[8] = a[8] + (b[8] * scale);\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\r\n *\r\n * @param {mat3} a The first matrix.\r\n * @param {mat3} b The second matrix.\r\n * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n */\r\nexport function exactEquals(a, b) {\r\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] &&\r\n a[3] === b[3] && a[4] === b[4] && a[5] === b[5] &&\r\n a[6] === b[6] && a[7] === b[7] && a[8] === b[8];\r\n}\r\n\r\n/**\r\n * Returns whether or not the matrices have approximately the same elements in the same position.\r\n *\r\n * @param {mat3} a The first matrix.\r\n * @param {mat3} b The second matrix.\r\n * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n */\r\nexport function equals(a, b) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], a8 = a[8];\r\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], b8 = b[8];\r\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\r\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\r\n Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\r\n Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&\r\n Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&\r\n Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&\r\n Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)));\r\n}\r\n\r\n/**\r\n * Alias for {@link mat3.multiply}\r\n * @function\r\n */\r\nexport const mul = multiply;\r\n\r\n/**\r\n * Alias for {@link mat3.subtract}\r\n * @function\r\n */\r\nexport const sub = subtract;\r\n","/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. */\r\n\r\nimport * as glMatrix from \"./common.js\";\r\n\r\n/**\r\n * @class 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.\r\n * @name mat4\r\n */\r\n\r\n/**\r\n * Creates a new identity mat4\r\n *\r\n * @returns {mat4} a new 4x4 matrix\r\n */\r\nexport function create() {\r\n let out = new glMatrix.ARRAY_TYPE(16);\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = 0;\r\n out[5] = 1;\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = 0;\r\n out[9] = 0;\r\n out[10] = 1;\r\n out[11] = 0;\r\n out[12] = 0;\r\n out[13] = 0;\r\n out[14] = 0;\r\n out[15] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a new mat4 initialized with values from an existing matrix\r\n *\r\n * @param {mat4} a matrix to clone\r\n * @returns {mat4} a new 4x4 matrix\r\n */\r\nexport function clone(a) {\r\n let out = new glMatrix.ARRAY_TYPE(16);\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n out[4] = a[4];\r\n out[5] = a[5];\r\n out[6] = a[6];\r\n out[7] = a[7];\r\n out[8] = a[8];\r\n out[9] = a[9];\r\n out[10] = a[10];\r\n out[11] = a[11];\r\n out[12] = a[12];\r\n out[13] = a[13];\r\n out[14] = a[14];\r\n out[15] = a[15];\r\n return out;\r\n}\r\n\r\n/**\r\n * Copy the values from one mat4 to another\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the source matrix\r\n * @returns {mat4} out\r\n */\r\nexport function copy(out, a) {\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n out[4] = a[4];\r\n out[5] = a[5];\r\n out[6] = a[6];\r\n out[7] = a[7];\r\n out[8] = a[8];\r\n out[9] = a[9];\r\n out[10] = a[10];\r\n out[11] = a[11];\r\n out[12] = a[12];\r\n out[13] = a[13];\r\n out[14] = a[14];\r\n out[15] = a[15];\r\n return out;\r\n}\r\n\r\n/**\r\n * Create a new mat4 with the given values\r\n *\r\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\r\n * @param {Number} m03 Component in column 0, row 3 position (index 3)\r\n * @param {Number} m10 Component in column 1, row 0 position (index 4)\r\n * @param {Number} m11 Component in column 1, row 1 position (index 5)\r\n * @param {Number} m12 Component in column 1, row 2 position (index 6)\r\n * @param {Number} m13 Component in column 1, row 3 position (index 7)\r\n * @param {Number} m20 Component in column 2, row 0 position (index 8)\r\n * @param {Number} m21 Component in column 2, row 1 position (index 9)\r\n * @param {Number} m22 Component in column 2, row 2 position (index 10)\r\n * @param {Number} m23 Component in column 2, row 3 position (index 11)\r\n * @param {Number} m30 Component in column 3, row 0 position (index 12)\r\n * @param {Number} m31 Component in column 3, row 1 position (index 13)\r\n * @param {Number} m32 Component in column 3, row 2 position (index 14)\r\n * @param {Number} m33 Component in column 3, row 3 position (index 15)\r\n * @returns {mat4} A new mat4\r\n */\r\nexport function fromValues(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {\r\n let out = new glMatrix.ARRAY_TYPE(16);\r\n out[0] = m00;\r\n out[1] = m01;\r\n out[2] = m02;\r\n out[3] = m03;\r\n out[4] = m10;\r\n out[5] = m11;\r\n out[6] = m12;\r\n out[7] = m13;\r\n out[8] = m20;\r\n out[9] = m21;\r\n out[10] = m22;\r\n out[11] = m23;\r\n out[12] = m30;\r\n out[13] = m31;\r\n out[14] = m32;\r\n out[15] = m33;\r\n return out;\r\n}\r\n\r\n/**\r\n * Set the components of a mat4 to the given values\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\r\n * @param {Number} m03 Component in column 0, row 3 position (index 3)\r\n * @param {Number} m10 Component in column 1, row 0 position (index 4)\r\n * @param {Number} m11 Component in column 1, row 1 position (index 5)\r\n * @param {Number} m12 Component in column 1, row 2 position (index 6)\r\n * @param {Number} m13 Component in column 1, row 3 position (index 7)\r\n * @param {Number} m20 Component in column 2, row 0 position (index 8)\r\n * @param {Number} m21 Component in column 2, row 1 position (index 9)\r\n * @param {Number} m22 Component in column 2, row 2 position (index 10)\r\n * @param {Number} m23 Component in column 2, row 3 position (index 11)\r\n * @param {Number} m30 Component in column 3, row 0 position (index 12)\r\n * @param {Number} m31 Component in column 3, row 1 position (index 13)\r\n * @param {Number} m32 Component in column 3, row 2 position (index 14)\r\n * @param {Number} m33 Component in column 3, row 3 position (index 15)\r\n * @returns {mat4} out\r\n */\r\nexport function set(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {\r\n out[0] = m00;\r\n out[1] = m01;\r\n out[2] = m02;\r\n out[3] = m03;\r\n out[4] = m10;\r\n out[5] = m11;\r\n out[6] = m12;\r\n out[7] = m13;\r\n out[8] = m20;\r\n out[9] = m21;\r\n out[10] = m22;\r\n out[11] = m23;\r\n out[12] = m30;\r\n out[13] = m31;\r\n out[14] = m32;\r\n out[15] = m33;\r\n return out;\r\n}\r\n\r\n\r\n/**\r\n * Set a mat4 to the identity matrix\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @returns {mat4} out\r\n */\r\nexport function identity(out) {\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = 0;\r\n out[5] = 1;\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = 0;\r\n out[9] = 0;\r\n out[10] = 1;\r\n out[11] = 0;\r\n out[12] = 0;\r\n out[13] = 0;\r\n out[14] = 0;\r\n out[15] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Transpose the values of a mat4\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the source matrix\r\n * @returns {mat4} out\r\n */\r\nexport function transpose(out, a) {\r\n // If we are transposing ourselves we can skip a few steps but have to cache some values\r\n if (out === a) {\r\n let a01 = a[1], a02 = a[2], a03 = a[3];\r\n let a12 = a[6], a13 = a[7];\r\n let a23 = a[11];\r\n\r\n out[1] = a[4];\r\n out[2] = a[8];\r\n out[3] = a[12];\r\n out[4] = a01;\r\n out[6] = a[9];\r\n out[7] = a[13];\r\n out[8] = a02;\r\n out[9] = a12;\r\n out[11] = a[14];\r\n out[12] = a03;\r\n out[13] = a13;\r\n out[14] = a23;\r\n } else {\r\n out[0] = a[0];\r\n out[1] = a[4];\r\n out[2] = a[8];\r\n out[3] = a[12];\r\n out[4] = a[1];\r\n out[5] = a[5];\r\n out[6] = a[9];\r\n out[7] = a[13];\r\n out[8] = a[2];\r\n out[9] = a[6];\r\n out[10] = a[10];\r\n out[11] = a[14];\r\n out[12] = a[3];\r\n out[13] = a[7];\r\n out[14] = a[11];\r\n out[15] = a[15];\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Inverts a mat4\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the source matrix\r\n * @returns {mat4} out\r\n */\r\nexport function invert(out, a) {\r\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\r\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\r\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\r\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\r\n\r\n let b00 = a00 * a11 - a01 * a10;\r\n let b01 = a00 * a12 - a02 * a10;\r\n let b02 = a00 * a13 - a03 * a10;\r\n let b03 = a01 * a12 - a02 * a11;\r\n let b04 = a01 * a13 - a03 * a11;\r\n let b05 = a02 * a13 - a03 * a12;\r\n let b06 = a20 * a31 - a21 * a30;\r\n let b07 = a20 * a32 - a22 * a30;\r\n let b08 = a20 * a33 - a23 * a30;\r\n let b09 = a21 * a32 - a22 * a31;\r\n let b10 = a21 * a33 - a23 * a31;\r\n let b11 = a22 * a33 - a23 * a32;\r\n\r\n // Calculate the determinant\r\n let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\r\n\r\n if (!det) {\r\n return null;\r\n }\r\n det = 1.0 / det;\r\n\r\n out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;\r\n out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;\r\n out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;\r\n out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;\r\n out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;\r\n out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;\r\n out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;\r\n out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;\r\n out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;\r\n out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;\r\n out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;\r\n out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;\r\n out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;\r\n out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;\r\n out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;\r\n out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the adjugate of a mat4\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the source matrix\r\n * @returns {mat4} out\r\n */\r\nexport function adjoint(out, a) {\r\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\r\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\r\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\r\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\r\n\r\n out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));\r\n out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));\r\n out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));\r\n out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));\r\n out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));\r\n out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));\r\n out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));\r\n out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));\r\n out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));\r\n out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));\r\n out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));\r\n out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));\r\n out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));\r\n out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));\r\n out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));\r\n out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the determinant of a mat4\r\n *\r\n * @param {mat4} a the source matrix\r\n * @returns {Number} determinant of a\r\n */\r\nexport function determinant(a) {\r\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\r\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\r\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\r\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\r\n\r\n let b00 = a00 * a11 - a01 * a10;\r\n let b01 = a00 * a12 - a02 * a10;\r\n let b02 = a00 * a13 - a03 * a10;\r\n let b03 = a01 * a12 - a02 * a11;\r\n let b04 = a01 * a13 - a03 * a11;\r\n let b05 = a02 * a13 - a03 * a12;\r\n let b06 = a20 * a31 - a21 * a30;\r\n let b07 = a20 * a32 - a22 * a30;\r\n let b08 = a20 * a33 - a23 * a30;\r\n let b09 = a21 * a32 - a22 * a31;\r\n let b10 = a21 * a33 - a23 * a31;\r\n let b11 = a22 * a33 - a23 * a32;\r\n\r\n // Calculate the determinant\r\n return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\r\n}\r\n\r\n/**\r\n * Multiplies two mat4s\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the first operand\r\n * @param {mat4} b the second operand\r\n * @returns {mat4} out\r\n */\r\nexport function multiply(out, a, b) {\r\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\r\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\r\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\r\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\r\n\r\n // Cache only the current line of the second matrix\r\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\r\n out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\r\n out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\r\n out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\r\n out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\r\n\r\n b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];\r\n out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\r\n out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\r\n out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\r\n out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\r\n\r\n b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];\r\n out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\r\n out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\r\n out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\r\n out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\r\n\r\n b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];\r\n out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\r\n out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\r\n out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\r\n out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\r\n return out;\r\n}\r\n\r\n/**\r\n * Translate a mat4 by the given vector\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the matrix to translate\r\n * @param {vec3} v vector to translate by\r\n * @returns {mat4} out\r\n */\r\nexport function translate(out, a, v) {\r\n let x = v[0], y = v[1], z = v[2];\r\n let a00, a01, a02, a03;\r\n let a10, a11, a12, a13;\r\n let a20, a21, a22, a23;\r\n\r\n if (a === out) {\r\n out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];\r\n out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];\r\n out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];\r\n out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];\r\n } else {\r\n a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];\r\n a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];\r\n a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];\r\n\r\n out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03;\r\n out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13;\r\n out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23;\r\n\r\n out[12] = a00 * x + a10 * y + a20 * z + a[12];\r\n out[13] = a01 * x + a11 * y + a21 * z + a[13];\r\n out[14] = a02 * x + a12 * y + a22 * z + a[14];\r\n out[15] = a03 * x + a13 * y + a23 * z + a[15];\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Scales the mat4 by the dimensions in the given vec3 not using vectorization\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the matrix to scale\r\n * @param {vec3} v the vec3 to scale the matrix by\r\n * @returns {mat4} out\r\n **/\r\nexport function scale(out, a, v) {\r\n let x = v[0], y = v[1], z = v[2];\r\n\r\n out[0] = a[0] * x;\r\n out[1] = a[1] * x;\r\n out[2] = a[2] * x;\r\n out[3] = a[3] * x;\r\n out[4] = a[4] * y;\r\n out[5] = a[5] * y;\r\n out[6] = a[6] * y;\r\n out[7] = a[7] * y;\r\n out[8] = a[8] * z;\r\n out[9] = a[9] * z;\r\n out[10] = a[10] * z;\r\n out[11] = a[11] * z;\r\n out[12] = a[12];\r\n out[13] = a[13];\r\n out[14] = a[14];\r\n out[15] = a[15];\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a mat4 by the given angle around the given axis\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the matrix to rotate\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @param {vec3} axis the axis to rotate around\r\n * @returns {mat4} out\r\n */\r\nexport function rotate(out, a, rad, axis) {\r\n let x = axis[0], y = axis[1], z = axis[2];\r\n let len = Math.sqrt(x * x + y * y + z * z);\r\n let s, c, t;\r\n let a00, a01, a02, a03;\r\n let a10, a11, a12, a13;\r\n let a20, a21, a22, a23;\r\n let b00, b01, b02;\r\n let b10, b11, b12;\r\n let b20, b21, b22;\r\n\r\n if (Math.abs(len) < glMatrix.EPSILON) { return null; }\r\n\r\n len = 1 / len;\r\n x *= len;\r\n y *= len;\r\n z *= len;\r\n\r\n s = Math.sin(rad);\r\n c = Math.cos(rad);\r\n t = 1 - c;\r\n\r\n a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];\r\n a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];\r\n a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];\r\n\r\n // Construct the elements of the rotation matrix\r\n b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;\r\n b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;\r\n b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;\r\n\r\n // Perform rotation-specific matrix multiplication\r\n out[0] = a00 * b00 + a10 * b01 + a20 * b02;\r\n out[1] = a01 * b00 + a11 * b01 + a21 * b02;\r\n out[2] = a02 * b00 + a12 * b01 + a22 * b02;\r\n out[3] = a03 * b00 + a13 * b01 + a23 * b02;\r\n out[4] = a00 * b10 + a10 * b11 + a20 * b12;\r\n out[5] = a01 * b10 + a11 * b11 + a21 * b12;\r\n out[6] = a02 * b10 + a12 * b11 + a22 * b12;\r\n out[7] = a03 * b10 + a13 * b11 + a23 * b12;\r\n out[8] = a00 * b20 + a10 * b21 + a20 * b22;\r\n out[9] = a01 * b20 + a11 * b21 + a21 * b22;\r\n out[10] = a02 * b20 + a12 * b21 + a22 * b22;\r\n out[11] = a03 * b20 + a13 * b21 + a23 * b22;\r\n\r\n if (a !== out) { // If the source and destination differ, copy the unchanged last row\r\n out[12] = a[12];\r\n out[13] = a[13];\r\n out[14] = a[14];\r\n out[15] = a[15];\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a matrix by the given angle around the X axis\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the matrix to rotate\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat4} out\r\n */\r\nexport function rotateX(out, a, rad) {\r\n let s = Math.sin(rad);\r\n let c = Math.cos(rad);\r\n let a10 = a[4];\r\n let a11 = a[5];\r\n let a12 = a[6];\r\n let a13 = a[7];\r\n let a20 = a[8];\r\n let a21 = a[9];\r\n let a22 = a[10];\r\n let a23 = a[11];\r\n\r\n if (a !== out) { // If the source and destination differ, copy the unchanged rows\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n out[12] = a[12];\r\n out[13] = a[13];\r\n out[14] = a[14];\r\n out[15] = a[15];\r\n }\r\n\r\n // Perform axis-specific matrix multiplication\r\n out[4] = a10 * c + a20 * s;\r\n out[5] = a11 * c + a21 * s;\r\n out[6] = a12 * c + a22 * s;\r\n out[7] = a13 * c + a23 * s;\r\n out[8] = a20 * c - a10 * s;\r\n out[9] = a21 * c - a11 * s;\r\n out[10] = a22 * c - a12 * s;\r\n out[11] = a23 * c - a13 * s;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a matrix by the given angle around the Y axis\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the matrix to rotate\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat4} out\r\n */\r\nexport function rotateY(out, a, rad) {\r\n let s = Math.sin(rad);\r\n let c = Math.cos(rad);\r\n let a00 = a[0];\r\n let a01 = a[1];\r\n let a02 = a[2];\r\n let a03 = a[3];\r\n let a20 = a[8];\r\n let a21 = a[9];\r\n let a22 = a[10];\r\n let a23 = a[11];\r\n\r\n if (a !== out) { // If the source and destination differ, copy the unchanged rows\r\n out[4] = a[4];\r\n out[5] = a[5];\r\n out[6] = a[6];\r\n out[7] = a[7];\r\n out[12] = a[12];\r\n out[13] = a[13];\r\n out[14] = a[14];\r\n out[15] = a[15];\r\n }\r\n\r\n // Perform axis-specific matrix multiplication\r\n out[0] = a00 * c - a20 * s;\r\n out[1] = a01 * c - a21 * s;\r\n out[2] = a02 * c - a22 * s;\r\n out[3] = a03 * c - a23 * s;\r\n out[8] = a00 * s + a20 * c;\r\n out[9] = a01 * s + a21 * c;\r\n out[10] = a02 * s + a22 * c;\r\n out[11] = a03 * s + a23 * c;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a matrix by the given angle around the Z axis\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the matrix to rotate\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat4} out\r\n */\r\nexport function rotateZ(out, a, rad) {\r\n let s = Math.sin(rad);\r\n let c = Math.cos(rad);\r\n let a00 = a[0];\r\n let a01 = a[1];\r\n let a02 = a[2];\r\n let a03 = a[3];\r\n let a10 = a[4];\r\n let a11 = a[5];\r\n let a12 = a[6];\r\n let a13 = a[7];\r\n\r\n if (a !== out) { // If the source and destination differ, copy the unchanged last row\r\n out[8] = a[8];\r\n out[9] = a[9];\r\n out[10] = a[10];\r\n out[11] = a[11];\r\n out[12] = a[12];\r\n out[13] = a[13];\r\n out[14] = a[14];\r\n out[15] = a[15];\r\n }\r\n\r\n // Perform axis-specific matrix multiplication\r\n out[0] = a00 * c + a10 * s;\r\n out[1] = a01 * c + a11 * s;\r\n out[2] = a02 * c + a12 * s;\r\n out[3] = a03 * c + a13 * s;\r\n out[4] = a10 * c - a00 * s;\r\n out[5] = a11 * c - a01 * s;\r\n out[6] = a12 * c - a02 * s;\r\n out[7] = a13 * c - a03 * s;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a vector translation\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat4.identity(dest);\r\n * mat4.translate(dest, dest, vec);\r\n *\r\n * @param {mat4} out mat4 receiving operation result\r\n * @param {vec3} v Translation vector\r\n * @returns {mat4} out\r\n */\r\nexport function fromTranslation(out, v) {\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = 0;\r\n out[5] = 1;\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = 0;\r\n out[9] = 0;\r\n out[10] = 1;\r\n out[11] = 0;\r\n out[12] = v[0];\r\n out[13] = v[1];\r\n out[14] = v[2];\r\n out[15] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a vector scaling\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat4.identity(dest);\r\n * mat4.scale(dest, dest, vec);\r\n *\r\n * @param {mat4} out mat4 receiving operation result\r\n * @param {vec3} v Scaling vector\r\n * @returns {mat4} out\r\n */\r\nexport function fromScaling(out, v) {\r\n out[0] = v[0];\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = 0;\r\n out[5] = v[1];\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = 0;\r\n out[9] = 0;\r\n out[10] = v[2];\r\n out[11] = 0;\r\n out[12] = 0;\r\n out[13] = 0;\r\n out[14] = 0;\r\n out[15] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a given angle around a given axis\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat4.identity(dest);\r\n * mat4.rotate(dest, dest, rad, axis);\r\n *\r\n * @param {mat4} out mat4 receiving operation result\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @param {vec3} axis the axis to rotate around\r\n * @returns {mat4} out\r\n */\r\nexport function fromRotation(out, rad, axis) {\r\n let x = axis[0], y = axis[1], z = axis[2];\r\n let len = Math.sqrt(x * x + y * y + z * z);\r\n let s, c, t;\r\n\r\n if (Math.abs(len) < glMatrix.EPSILON) { return null; }\r\n\r\n len = 1 / len;\r\n x *= len;\r\n y *= len;\r\n z *= len;\r\n\r\n s = Math.sin(rad);\r\n c = Math.cos(rad);\r\n t = 1 - c;\r\n\r\n // Perform rotation-specific matrix multiplication\r\n out[0] = x * x * t + c;\r\n out[1] = y * x * t + z * s;\r\n out[2] = z * x * t - y * s;\r\n out[3] = 0;\r\n out[4] = x * y * t - z * s;\r\n out[5] = y * y * t + c;\r\n out[6] = z * y * t + x * s;\r\n out[7] = 0;\r\n out[8] = x * z * t + y * s;\r\n out[9] = y * z * t - x * s;\r\n out[10] = z * z * t + c;\r\n out[11] = 0;\r\n out[12] = 0;\r\n out[13] = 0;\r\n out[14] = 0;\r\n out[15] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from the given angle around the X axis\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat4.identity(dest);\r\n * mat4.rotateX(dest, dest, rad);\r\n *\r\n * @param {mat4} out mat4 receiving operation result\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat4} out\r\n */\r\nexport function fromXRotation(out, rad) {\r\n let s = Math.sin(rad);\r\n let c = Math.cos(rad);\r\n\r\n // Perform axis-specific matrix multiplication\r\n out[0] = 1;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = 0;\r\n out[5] = c;\r\n out[6] = s;\r\n out[7] = 0;\r\n out[8] = 0;\r\n out[9] = -s;\r\n out[10] = c;\r\n out[11] = 0;\r\n out[12] = 0;\r\n out[13] = 0;\r\n out[14] = 0;\r\n out[15] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from the given angle around the Y axis\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat4.identity(dest);\r\n * mat4.rotateY(dest, dest, rad);\r\n *\r\n * @param {mat4} out mat4 receiving operation result\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat4} out\r\n */\r\nexport function fromYRotation(out, rad) {\r\n let s = Math.sin(rad);\r\n let c = Math.cos(rad);\r\n\r\n // Perform axis-specific matrix multiplication\r\n out[0] = c;\r\n out[1] = 0;\r\n out[2] = -s;\r\n out[3] = 0;\r\n out[4] = 0;\r\n out[5] = 1;\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = s;\r\n out[9] = 0;\r\n out[10] = c;\r\n out[11] = 0;\r\n out[12] = 0;\r\n out[13] = 0;\r\n out[14] = 0;\r\n out[15] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from the given angle around the Z axis\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat4.identity(dest);\r\n * mat4.rotateZ(dest, dest, rad);\r\n *\r\n * @param {mat4} out mat4 receiving operation result\r\n * @param {Number} rad the angle to rotate the matrix by\r\n * @returns {mat4} out\r\n */\r\nexport function fromZRotation(out, rad) {\r\n let s = Math.sin(rad);\r\n let c = Math.cos(rad);\r\n\r\n // Perform axis-specific matrix multiplication\r\n out[0] = c;\r\n out[1] = s;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = -s;\r\n out[5] = c;\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = 0;\r\n out[9] = 0;\r\n out[10] = 1;\r\n out[11] = 0;\r\n out[12] = 0;\r\n out[13] = 0;\r\n out[14] = 0;\r\n out[15] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a quaternion rotation and vector translation\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat4.identity(dest);\r\n * mat4.translate(dest, vec);\r\n * let quatMat = mat4.create();\r\n * quat4.toMat4(quat, quatMat);\r\n * mat4.multiply(dest, quatMat);\r\n *\r\n * @param {mat4} out mat4 receiving operation result\r\n * @param {quat4} q Rotation quaternion\r\n * @param {vec3} v Translation vector\r\n * @returns {mat4} out\r\n */\r\nexport function fromRotationTranslation(out, q, v) {\r\n // Quaternion math\r\n let x = q[0], y = q[1], z = q[2], w = q[3];\r\n let x2 = x + x;\r\n let y2 = y + y;\r\n let z2 = z + z;\r\n\r\n let xx = x * x2;\r\n let xy = x * y2;\r\n let xz = x * z2;\r\n let yy = y * y2;\r\n let yz = y * z2;\r\n let zz = z * z2;\r\n let wx = w * x2;\r\n let wy = w * y2;\r\n let wz = w * z2;\r\n\r\n out[0] = 1 - (yy + zz);\r\n out[1] = xy + wz;\r\n out[2] = xz - wy;\r\n out[3] = 0;\r\n out[4] = xy - wz;\r\n out[5] = 1 - (xx + zz);\r\n out[6] = yz + wx;\r\n out[7] = 0;\r\n out[8] = xz + wy;\r\n out[9] = yz - wx;\r\n out[10] = 1 - (xx + yy);\r\n out[11] = 0;\r\n out[12] = v[0];\r\n out[13] = v[1];\r\n out[14] = v[2];\r\n out[15] = 1;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a new mat4 from a dual quat.\r\n *\r\n * @param {mat4} out Matrix\r\n * @param {quat2} a Dual Quaternion\r\n * @returns {mat4} mat4 receiving operation result\r\n */\r\nexport function fromQuat2(out, a) {\r\n let translation = new glMatrix.ARRAY_TYPE(3);\r\n let bx = -a[0], by = -a[1], bz = -a[2], bw = a[3],\r\n ax = a[4], ay = a[5], az = a[6], aw = a[7];\r\n \r\n let magnitude = bx * bx + by * by + bz * bz + bw * bw;\r\n //Only scale if it makes sense\r\n if (magnitude > 0) {\r\n translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;\r\n translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;\r\n translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;\r\n } else {\r\n translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;\r\n translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;\r\n translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;\r\n }\r\n fromRotationTranslation(out, a, translation);\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns the translation vector component of a transformation\r\n * matrix. If a matrix is built with fromRotationTranslation,\r\n * the returned vector will be the same as the translation vector\r\n * originally supplied.\r\n * @param {vec3} out Vector to receive translation component\r\n * @param {mat4} mat Matrix to be decomposed (input)\r\n * @return {vec3} out\r\n */\r\nexport function getTranslation(out, mat) {\r\n out[0] = mat[12];\r\n out[1] = mat[13];\r\n out[2] = mat[14];\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns the scaling factor component of a transformation\r\n * matrix. If a matrix is built with fromRotationTranslationScale\r\n * with a normalized Quaternion paramter, the returned vector will be\r\n * the same as the scaling vector\r\n * originally supplied.\r\n * @param {vec3} out Vector to receive scaling factor component\r\n * @param {mat4} mat Matrix to be decomposed (input)\r\n * @return {vec3} out\r\n */\r\nexport function getScaling(out, mat) {\r\n let m11 = mat[0];\r\n let m12 = mat[1];\r\n let m13 = mat[2];\r\n let m21 = mat[4];\r\n let m22 = mat[5];\r\n let m23 = mat[6];\r\n let m31 = mat[8];\r\n let m32 = mat[9];\r\n let m33 = mat[10];\r\n\r\n out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);\r\n out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);\r\n out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns a quaternion representing the rotational component\r\n * of a transformation matrix. If a matrix is built with\r\n * fromRotationTranslation, the returned quaternion will be the\r\n * same as the quaternion originally supplied.\r\n * @param {quat} out Quaternion to receive the rotation component\r\n * @param {mat4} mat Matrix to be decomposed (input)\r\n * @return {quat} out\r\n */\r\nexport function getRotation(out, mat) {\r\n // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm\r\n let trace = mat[0] + mat[5] + mat[10];\r\n let S = 0;\r\n\r\n if (trace > 0) {\r\n S = Math.sqrt(trace + 1.0) * 2;\r\n out[3] = 0.25 * S;\r\n out[0] = (mat[6] - mat[9]) / S;\r\n out[1] = (mat[8] - mat[2]) / S;\r\n out[2] = (mat[1] - mat[4]) / S;\r\n } else if ((mat[0] > mat[5]) && (mat[0] > mat[10])) {\r\n S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2;\r\n out[3] = (mat[6] - mat[9]) / S;\r\n out[0] = 0.25 * S;\r\n out[1] = (mat[1] + mat[4]) / S;\r\n out[2] = (mat[8] + mat[2]) / S;\r\n } else if (mat[5] > mat[10]) {\r\n S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2;\r\n out[3] = (mat[8] - mat[2]) / S;\r\n out[0] = (mat[1] + mat[4]) / S;\r\n out[1] = 0.25 * S;\r\n out[2] = (mat[6] + mat[9]) / S;\r\n } else {\r\n S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2;\r\n out[3] = (mat[1] - mat[4]) / S;\r\n out[0] = (mat[8] + mat[2]) / S;\r\n out[1] = (mat[6] + mat[9]) / S;\r\n out[2] = 0.25 * S;\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a quaternion rotation, vector translation and vector scale\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat4.identity(dest);\r\n * mat4.translate(dest, vec);\r\n * let quatMat = mat4.create();\r\n * quat4.toMat4(quat, quatMat);\r\n * mat4.multiply(dest, quatMat);\r\n * mat4.scale(dest, scale)\r\n *\r\n * @param {mat4} out mat4 receiving operation result\r\n * @param {quat4} q Rotation quaternion\r\n * @param {vec3} v Translation vector\r\n * @param {vec3} s Scaling vector\r\n * @returns {mat4} out\r\n */\r\nexport function fromRotationTranslationScale(out, q, v, s) {\r\n // Quaternion math\r\n let x = q[0], y = q[1], z = q[2], w = q[3];\r\n let x2 = x + x;\r\n let y2 = y + y;\r\n let z2 = z + z;\r\n\r\n let xx = x * x2;\r\n let xy = x * y2;\r\n let xz = x * z2;\r\n let yy = y * y2;\r\n let yz = y * z2;\r\n let zz = z * z2;\r\n let wx = w * x2;\r\n let wy = w * y2;\r\n let wz = w * z2;\r\n let sx = s[0];\r\n let sy = s[1];\r\n let sz = s[2];\r\n\r\n out[0] = (1 - (yy + zz)) * sx;\r\n out[1] = (xy + wz) * sx;\r\n out[2] = (xz - wy) * sx;\r\n out[3] = 0;\r\n out[4] = (xy - wz) * sy;\r\n out[5] = (1 - (xx + zz)) * sy;\r\n out[6] = (yz + wx) * sy;\r\n out[7] = 0;\r\n out[8] = (xz + wy) * sz;\r\n out[9] = (yz - wx) * sz;\r\n out[10] = (1 - (xx + yy)) * sz;\r\n out[11] = 0;\r\n out[12] = v[0];\r\n out[13] = v[1];\r\n out[14] = v[2];\r\n out[15] = 1;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin\r\n * This is equivalent to (but much faster than):\r\n *\r\n * mat4.identity(dest);\r\n * mat4.translate(dest, vec);\r\n * mat4.translate(dest, origin);\r\n * let quatMat = mat4.create();\r\n * quat4.toMat4(quat, quatMat);\r\n * mat4.multiply(dest, quatMat);\r\n * mat4.scale(dest, scale)\r\n * mat4.translate(dest, negativeOrigin);\r\n *\r\n * @param {mat4} out mat4 receiving operation result\r\n * @param {quat4} q Rotation quaternion\r\n * @param {vec3} v Translation vector\r\n * @param {vec3} s Scaling vector\r\n * @param {vec3} o The origin vector around which to scale and rotate\r\n * @returns {mat4} out\r\n */\r\nexport function fromRotationTranslationScaleOrigin(out, q, v, s, o) {\r\n // Quaternion math\r\n let x = q[0], y = q[1], z = q[2], w = q[3];\r\n let x2 = x + x;\r\n let y2 = y + y;\r\n let z2 = z + z;\r\n\r\n let xx = x * x2;\r\n let xy = x * y2;\r\n let xz = x * z2;\r\n let yy = y * y2;\r\n let yz = y * z2;\r\n let zz = z * z2;\r\n let wx = w * x2;\r\n let wy = w * y2;\r\n let wz = w * z2;\r\n\r\n let sx = s[0];\r\n let sy = s[1];\r\n let sz = s[2];\r\n\r\n let ox = o[0];\r\n let oy = o[1];\r\n let oz = o[2];\r\n\r\n let out0 = (1 - (yy + zz)) * sx;\r\n let out1 = (xy + wz) * sx;\r\n let out2 = (xz - wy) * sx;\r\n let out4 = (xy - wz) * sy;\r\n let out5 = (1 - (xx + zz)) * sy;\r\n let out6 = (yz + wx) * sy;\r\n let out8 = (xz + wy) * sz;\r\n let out9 = (yz - wx) * sz;\r\n let out10 = (1 - (xx + yy)) * sz;\r\n\r\n out[0] = out0;\r\n out[1] = out1;\r\n out[2] = out2;\r\n out[3] = 0;\r\n out[4] = out4;\r\n out[5] = out5;\r\n out[6] = out6;\r\n out[7] = 0;\r\n out[8] = out8;\r\n out[9] = out9;\r\n out[10] = out10;\r\n out[11] = 0;\r\n out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);\r\n out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);\r\n out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);\r\n out[15] = 1;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates a 4x4 matrix from the given quaternion\r\n *\r\n * @param {mat4} out mat4 receiving operation result\r\n * @param {quat} q Quaternion to create matrix from\r\n *\r\n * @returns {mat4} out\r\n */\r\nexport function fromQuat(out, q) {\r\n let x = q[0], y = q[1], z = q[2], w = q[3];\r\n let x2 = x + x;\r\n let y2 = y + y;\r\n let z2 = z + z;\r\n\r\n let xx = x * x2;\r\n let yx = y * x2;\r\n let yy = y * y2;\r\n let zx = z * x2;\r\n let zy = z * y2;\r\n let zz = z * z2;\r\n let wx = w * x2;\r\n let wy = w * y2;\r\n let wz = w * z2;\r\n\r\n out[0] = 1 - yy - zz;\r\n out[1] = yx + wz;\r\n out[2] = zx - wy;\r\n out[3] = 0;\r\n\r\n out[4] = yx - wz;\r\n out[5] = 1 - xx - zz;\r\n out[6] = zy + wx;\r\n out[7] = 0;\r\n\r\n out[8] = zx + wy;\r\n out[9] = zy - wx;\r\n out[10] = 1 - xx - yy;\r\n out[11] = 0;\r\n\r\n out[12] = 0;\r\n out[13] = 0;\r\n out[14] = 0;\r\n out[15] = 1;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Generates a frustum matrix with the given bounds\r\n *\r\n * @param {mat4} out mat4 frustum matrix will be written into\r\n * @param {Number} left Left bound of the frustum\r\n * @param {Number} right Right bound of the frustum\r\n * @param {Number} bottom Bottom bound of the frustum\r\n * @param {Number} top Top bound of the frustum\r\n * @param {Number} near Near bound of the frustum\r\n * @param {Number} far Far bound of the frustum\r\n * @returns {mat4} out\r\n */\r\nexport function frustum(out, left, right, bottom, top, near, far) {\r\n let rl = 1 / (right - left);\r\n let tb = 1 / (top - bottom);\r\n let nf = 1 / (near - far);\r\n out[0] = (near * 2) * rl;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = 0;\r\n out[5] = (near * 2) * tb;\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = (right + left) * rl;\r\n out[9] = (top + bottom) * tb;\r\n out[10] = (far + near) * nf;\r\n out[11] = -1;\r\n out[12] = 0;\r\n out[13] = 0;\r\n out[14] = (far * near * 2) * nf;\r\n out[15] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Generates a perspective projection matrix with the given bounds\r\n *\r\n * @param {mat4} out mat4 frustum matrix will be written into\r\n * @param {number} fovy Vertical field of view in radians\r\n * @param {number} aspect Aspect ratio. typically viewport width/height\r\n * @param {number} near Near bound of the frustum\r\n * @param {number} far Far bound of the frustum\r\n * @returns {mat4} out\r\n */\r\nexport function perspective(out, fovy, aspect, near, far) {\r\n let f = 1.0 / Math.tan(fovy / 2);\r\n let nf = 1 / (near - far);\r\n out[0] = f / aspect;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = 0;\r\n out[5] = f;\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = 0;\r\n out[9] = 0;\r\n out[10] = (far + near) * nf;\r\n out[11] = -1;\r\n out[12] = 0;\r\n out[13] = 0;\r\n out[14] = (2 * far * near) * nf;\r\n out[15] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Generates a perspective projection matrix with the given field of view.\r\n * This is primarily useful for generating projection matrices to be used\r\n * with the still experiemental WebVR API.\r\n *\r\n * @param {mat4} out mat4 frustum matrix will be written into\r\n * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees\r\n * @param {number} near Near bound of the frustum\r\n * @param {number} far Far bound of the frustum\r\n * @returns {mat4} out\r\n */\r\nexport function perspectiveFromFieldOfView(out, fov, near, far) {\r\n let upTan = Math.tan(fov.upDegrees * Math.PI/180.0);\r\n let downTan = Math.tan(fov.downDegrees * Math.PI/180.0);\r\n let leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0);\r\n let rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0);\r\n let xScale = 2.0 / (leftTan + rightTan);\r\n let yScale = 2.0 / (upTan + downTan);\r\n\r\n out[0] = xScale;\r\n out[1] = 0.0;\r\n out[2] = 0.0;\r\n out[3] = 0.0;\r\n out[4] = 0.0;\r\n out[5] = yScale;\r\n out[6] = 0.0;\r\n out[7] = 0.0;\r\n out[8] = -((leftTan - rightTan) * xScale * 0.5);\r\n out[9] = ((upTan - downTan) * yScale * 0.5);\r\n out[10] = far / (near - far);\r\n out[11] = -1.0;\r\n out[12] = 0.0;\r\n out[13] = 0.0;\r\n out[14] = (far * near) / (near - far);\r\n out[15] = 0.0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Generates a orthogonal projection matrix with the given bounds\r\n *\r\n * @param {mat4} out mat4 frustum matrix will be written into\r\n * @param {number} left Left bound of the frustum\r\n * @param {number} right Right bound of the frustum\r\n * @param {number} bottom Bottom bound of the frustum\r\n * @param {number} top Top bound of the frustum\r\n * @param {number} near Near bound of the frustum\r\n * @param {number} far Far bound of the frustum\r\n * @returns {mat4} out\r\n */\r\nexport function ortho(out, left, right, bottom, top, near, far) {\r\n let lr = 1 / (left - right);\r\n let bt = 1 / (bottom - top);\r\n let nf = 1 / (near - far);\r\n out[0] = -2 * lr;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n out[4] = 0;\r\n out[5] = -2 * bt;\r\n out[6] = 0;\r\n out[7] = 0;\r\n out[8] = 0;\r\n out[9] = 0;\r\n out[10] = 2 * nf;\r\n out[11] = 0;\r\n out[12] = (left + right) * lr;\r\n out[13] = (top + bottom) * bt;\r\n out[14] = (far + near) * nf;\r\n out[15] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Generates a look-at matrix with the given eye position, focal point, and up axis. \r\n * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.\r\n *\r\n * @param {mat4} out mat4 frustum matrix will be written into\r\n * @param {vec3} eye Position of the viewer\r\n * @param {vec3} center Point the viewer is looking at\r\n * @param {vec3} up vec3 pointing up\r\n * @returns {mat4} out\r\n */\r\nexport function lookAt(out, eye, center, up) {\r\n let x0, x1, x2, y0, y1, y2, z0, z1, z2, len;\r\n let eyex = eye[0];\r\n let eyey = eye[1];\r\n let eyez = eye[2];\r\n let upx = up[0];\r\n let upy = up[1];\r\n let upz = up[2];\r\n let centerx = center[0];\r\n let centery = center[1];\r\n let centerz = center[2];\r\n\r\n if (Math.abs(eyex - centerx) < glMatrix.EPSILON &&\r\n Math.abs(eyey - centery) < glMatrix.EPSILON &&\r\n Math.abs(eyez - centerz) < glMatrix.EPSILON) {\r\n return identity(out);\r\n }\r\n\r\n z0 = eyex - centerx;\r\n z1 = eyey - centery;\r\n z2 = eyez - centerz;\r\n\r\n len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);\r\n z0 *= len;\r\n z1 *= len;\r\n z2 *= len;\r\n\r\n x0 = upy * z2 - upz * z1;\r\n x1 = upz * z0 - upx * z2;\r\n x2 = upx * z1 - upy * z0;\r\n len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);\r\n if (!len) {\r\n x0 = 0;\r\n x1 = 0;\r\n x2 = 0;\r\n } else {\r\n len = 1 / len;\r\n x0 *= len;\r\n x1 *= len;\r\n x2 *= len;\r\n }\r\n\r\n y0 = z1 * x2 - z2 * x1;\r\n y1 = z2 * x0 - z0 * x2;\r\n y2 = z0 * x1 - z1 * x0;\r\n\r\n len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);\r\n if (!len) {\r\n y0 = 0;\r\n y1 = 0;\r\n y2 = 0;\r\n } else {\r\n len = 1 / len;\r\n y0 *= len;\r\n y1 *= len;\r\n y2 *= len;\r\n }\r\n\r\n out[0] = x0;\r\n out[1] = y0;\r\n out[2] = z0;\r\n out[3] = 0;\r\n out[4] = x1;\r\n out[5] = y1;\r\n out[6] = z1;\r\n out[7] = 0;\r\n out[8] = x2;\r\n out[9] = y2;\r\n out[10] = z2;\r\n out[11] = 0;\r\n out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);\r\n out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);\r\n out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);\r\n out[15] = 1;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Generates a matrix that makes something look at something else.\r\n *\r\n * @param {mat4} out mat4 frustum matrix will be written into\r\n * @param {vec3} eye Position of the viewer\r\n * @param {vec3} center Point the viewer is looking at\r\n * @param {vec3} up vec3 pointing up\r\n * @returns {mat4} out\r\n */\r\nexport function targetTo(out, eye, target, up) {\r\n let eyex = eye[0],\r\n eyey = eye[1],\r\n eyez = eye[2],\r\n upx = up[0],\r\n upy = up[1],\r\n upz = up[2];\r\n\r\n let z0 = eyex - target[0],\r\n z1 = eyey - target[1],\r\n z2 = eyez - target[2];\r\n\r\n let len = z0*z0 + z1*z1 + z2*z2;\r\n if (len > 0) {\r\n len = 1 / Math.sqrt(len);\r\n z0 *= len;\r\n z1 *= len;\r\n z2 *= len;\r\n }\r\n\r\n let x0 = upy * z2 - upz * z1,\r\n x1 = upz * z0 - upx * z2,\r\n x2 = upx * z1 - upy * z0;\r\n\r\n len = x0*x0 + x1*x1 + x2*x2;\r\n if (len > 0) {\r\n len = 1 / Math.sqrt(len);\r\n x0 *= len;\r\n x1 *= len;\r\n x2 *= len;\r\n }\r\n\r\n out[0] = x0;\r\n out[1] = x1;\r\n out[2] = x2;\r\n out[3] = 0;\r\n out[4] = z1 * x2 - z2 * x1;\r\n out[5] = z2 * x0 - z0 * x2;\r\n out[6] = z0 * x1 - z1 * x0;\r\n out[7] = 0;\r\n out[8] = z0;\r\n out[9] = z1;\r\n out[10] = z2;\r\n out[11] = 0;\r\n out[12] = eyex;\r\n out[13] = eyey;\r\n out[14] = eyez;\r\n out[15] = 1;\r\n return out;\r\n};\r\n\r\n/**\r\n * Returns a string representation of a mat4\r\n *\r\n * @param {mat4} a matrix to represent as a string\r\n * @returns {String} string representation of the matrix\r\n */\r\nexport function str(a) {\r\n return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +\r\n a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +\r\n a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +\r\n a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';\r\n}\r\n\r\n/**\r\n * Returns Frobenius norm of a mat4\r\n *\r\n * @param {mat4} a the matrix to calculate Frobenius norm of\r\n * @returns {Number} Frobenius norm\r\n */\r\nexport function frob(a) {\r\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) ))\r\n}\r\n\r\n/**\r\n * Adds two mat4's\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the first operand\r\n * @param {mat4} b the second operand\r\n * @returns {mat4} out\r\n */\r\nexport function add(out, a, b) {\r\n out[0] = a[0] + b[0];\r\n out[1] = a[1] + b[1];\r\n out[2] = a[2] + b[2];\r\n out[3] = a[3] + b[3];\r\n out[4] = a[4] + b[4];\r\n out[5] = a[5] + b[5];\r\n out[6] = a[6] + b[6];\r\n out[7] = a[7] + b[7];\r\n out[8] = a[8] + b[8];\r\n out[9] = a[9] + b[9];\r\n out[10] = a[10] + b[10];\r\n out[11] = a[11] + b[11];\r\n out[12] = a[12] + b[12];\r\n out[13] = a[13] + b[13];\r\n out[14] = a[14] + b[14];\r\n out[15] = a[15] + b[15];\r\n return out;\r\n}\r\n\r\n/**\r\n * Subtracts matrix b from matrix a\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the first operand\r\n * @param {mat4} b the second operand\r\n * @returns {mat4} out\r\n */\r\nexport function subtract(out, a, b) {\r\n out[0] = a[0] - b[0];\r\n out[1] = a[1] - b[1];\r\n out[2] = a[2] - b[2];\r\n out[3] = a[3] - b[3];\r\n out[4] = a[4] - b[4];\r\n out[5] = a[5] - b[5];\r\n out[6] = a[6] - b[6];\r\n out[7] = a[7] - b[7];\r\n out[8] = a[8] - b[8];\r\n out[9] = a[9] - b[9];\r\n out[10] = a[10] - b[10];\r\n out[11] = a[11] - b[11];\r\n out[12] = a[12] - b[12];\r\n out[13] = a[13] - b[13];\r\n out[14] = a[14] - b[14];\r\n out[15] = a[15] - b[15];\r\n return out;\r\n}\r\n\r\n/**\r\n * Multiply each element of the matrix by a scalar.\r\n *\r\n * @param {mat4} out the receiving matrix\r\n * @param {mat4} a the matrix to scale\r\n * @param {Number} b amount to scale the matrix's elements by\r\n * @returns {mat4} out\r\n */\r\nexport function multiplyScalar(out, a, b) {\r\n out[0] = a[0] * b;\r\n out[1] = a[1] * b;\r\n out[2] = a[2] * b;\r\n out[3] = a[3] * b;\r\n out[4] = a[4] * b;\r\n out[5] = a[5] * b;\r\n out[6] = a[6] * b;\r\n out[7] = a[7] * b;\r\n out[8] = a[8] * b;\r\n out[9] = a[9] * b;\r\n out[10] = a[10] * b;\r\n out[11] = a[11] * b;\r\n out[12] = a[12] * b;\r\n out[13] = a[13] * b;\r\n out[14] = a[14] * b;\r\n out[15] = a[15] * b;\r\n return out;\r\n}\r\n\r\n/**\r\n * Adds two mat4's after multiplying each element of the second operand by a scalar value.\r\n *\r\n * @param {mat4} out the receiving vector\r\n * @param {mat4} a the first operand\r\n * @param {mat4} b the second operand\r\n * @param {Number} scale the amount to scale b's elements by before adding\r\n * @returns {mat4} out\r\n */\r\nexport function multiplyScalarAndAdd(out, a, b, scale) {\r\n out[0] = a[0] + (b[0] * scale);\r\n out[1] = a[1] + (b[1] * scale);\r\n out[2] = a[2] + (b[2] * scale);\r\n out[3] = a[3] + (b[3] * scale);\r\n out[4] = a[4] + (b[4] * scale);\r\n out[5] = a[5] + (b[5] * scale);\r\n out[6] = a[6] + (b[6] * scale);\r\n out[7] = a[7] + (b[7] * scale);\r\n out[8] = a[8] + (b[8] * scale);\r\n out[9] = a[9] + (b[9] * scale);\r\n out[10] = a[10] + (b[10] * scale);\r\n out[11] = a[11] + (b[11] * scale);\r\n out[12] = a[12] + (b[12] * scale);\r\n out[13] = a[13] + (b[13] * scale);\r\n out[14] = a[14] + (b[14] * scale);\r\n out[15] = a[15] + (b[15] * scale);\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\r\n *\r\n * @param {mat4} a The first matrix.\r\n * @param {mat4} b The second matrix.\r\n * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n */\r\nexport function exactEquals(a, b) {\r\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] &&\r\n a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] &&\r\n a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] &&\r\n a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];\r\n}\r\n\r\n/**\r\n * Returns whether or not the matrices have approximately the same elements in the same position.\r\n *\r\n * @param {mat4} a The first matrix.\r\n * @param {mat4} b The second matrix.\r\n * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n */\r\nexport function equals(a, b) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\r\n let a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7];\r\n let a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11];\r\n let a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15];\r\n\r\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\r\n let b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7];\r\n let b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11];\r\n let b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];\r\n\r\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\r\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\r\n Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\r\n Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&\r\n Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&\r\n Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&\r\n Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)) &&\r\n Math.abs(a9 - b9) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a9), Math.abs(b9)) &&\r\n Math.abs(a10 - b10) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a10), Math.abs(b10)) &&\r\n Math.abs(a11 - b11) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a11), Math.abs(b11)) &&\r\n Math.abs(a12 - b12) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a12), Math.abs(b12)) &&\r\n Math.abs(a13 - b13) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a13), Math.abs(b13)) &&\r\n Math.abs(a14 - b14) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a14), Math.abs(b14)) &&\r\n Math.abs(a15 - b15) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a15), Math.abs(b15)));\r\n}\r\n\r\n/**\r\n * Alias for {@link mat4.multiply}\r\n * @function\r\n */\r\nexport const mul = multiply;\r\n\r\n/**\r\n * Alias for {@link mat4.subtract}\r\n * @function\r\n */\r\nexport const sub = subtract;\r\n","/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. */\r\n\r\nimport * as glMatrix from \"./common.js\"\r\nimport * as mat3 from \"./mat3.js\"\r\nimport * as vec3 from \"./vec3.js\"\r\nimport * as vec4 from \"./vec4.js\"\r\n\r\n/**\r\n * Quaternion\r\n * @module quat\r\n */\r\n\r\n/**\r\n * Creates a new identity quat\r\n *\r\n * @returns {quat} a new quaternion\r\n */\r\nexport function create() {\r\n let out = new glMatrix.ARRAY_TYPE(4);\r\n out[0] = 0;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Set a quat to the identity quaternion\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @returns {quat} out\r\n */\r\nexport function identity(out) {\r\n out[0] = 0;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 1;\r\n return out;\r\n}\r\n\r\n/**\r\n * Sets a quat from the given angle and rotation axis,\r\n * then returns it.\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {vec3} axis the axis around which to rotate\r\n * @param {Number} rad the angle in radians\r\n * @returns {quat} out\r\n **/\r\nexport function setAxisAngle(out, axis, rad) {\r\n rad = rad * 0.5;\r\n let s = Math.sin(rad);\r\n out[0] = s * axis[0];\r\n out[1] = s * axis[1];\r\n out[2] = s * axis[2];\r\n out[3] = Math.cos(rad);\r\n return out;\r\n}\r\n\r\n/**\r\n * Gets the rotation axis and angle for a given\r\n * quaternion. If a quaternion is created with\r\n * setAxisAngle, this method will return the same\r\n * values as providied in the original parameter list\r\n * OR functionally equivalent values.\r\n * Example: The quaternion formed by axis [0, 0, 1] and\r\n * angle -90 is the same as the quaternion formed by\r\n * [0, 0, 1] and 270. This method favors the latter.\r\n * @param {vec3} out_axis Vector receiving the axis of rotation\r\n * @param {quat} q Quaternion to be decomposed\r\n * @return {Number} Angle, in radians, of the rotation\r\n */\r\nexport function getAxisAngle(out_axis, q) {\r\n let rad = Math.acos(q[3]) * 2.0;\r\n let s = Math.sin(rad / 2.0);\r\n if (s != 0.0) {\r\n out_axis[0] = q[0] / s;\r\n out_axis[1] = q[1] / s;\r\n out_axis[2] = q[2] / s;\r\n } else {\r\n // If s is zero, return any axis (no rotation - axis does not matter)\r\n out_axis[0] = 1;\r\n out_axis[1] = 0;\r\n out_axis[2] = 0;\r\n }\r\n return rad;\r\n}\r\n\r\n/**\r\n * Multiplies two quat's\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {quat} a the first operand\r\n * @param {quat} b the second operand\r\n * @returns {quat} out\r\n */\r\nexport function multiply(out, a, b) {\r\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\r\n let bx = b[0], by = b[1], bz = b[2], bw = b[3];\r\n\r\n out[0] = ax * bw + aw * bx + ay * bz - az * by;\r\n out[1] = ay * bw + aw * by + az * bx - ax * bz;\r\n out[2] = az * bw + aw * bz + ax * by - ay * bx;\r\n out[3] = aw * bw - ax * bx - ay * by - az * bz;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a quaternion by the given angle about the X axis\r\n *\r\n * @param {quat} out quat receiving operation result\r\n * @param {quat} a quat to rotate\r\n * @param {number} rad angle (in radians) to rotate\r\n * @returns {quat} out\r\n */\r\nexport function rotateX(out, a, rad) {\r\n rad *= 0.5;\r\n\r\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\r\n let bx = Math.sin(rad), bw = Math.cos(rad);\r\n\r\n out[0] = ax * bw + aw * bx;\r\n out[1] = ay * bw + az * bx;\r\n out[2] = az * bw - ay * bx;\r\n out[3] = aw * bw - ax * bx;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a quaternion by the given angle about the Y axis\r\n *\r\n * @param {quat} out quat receiving operation result\r\n * @param {quat} a quat to rotate\r\n * @param {number} rad angle (in radians) to rotate\r\n * @returns {quat} out\r\n */\r\nexport function rotateY(out, a, rad) {\r\n rad *= 0.5;\r\n\r\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\r\n let by = Math.sin(rad), bw = Math.cos(rad);\r\n\r\n out[0] = ax * bw - az * by;\r\n out[1] = ay * bw + aw * by;\r\n out[2] = az * bw + ax * by;\r\n out[3] = aw * bw - ay * by;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a quaternion by the given angle about the Z axis\r\n *\r\n * @param {quat} out quat receiving operation result\r\n * @param {quat} a quat to rotate\r\n * @param {number} rad angle (in radians) to rotate\r\n * @returns {quat} out\r\n */\r\nexport function rotateZ(out, a, rad) {\r\n rad *= 0.5;\r\n\r\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\r\n let bz = Math.sin(rad), bw = Math.cos(rad);\r\n\r\n out[0] = ax * bw + ay * bz;\r\n out[1] = ay * bw - ax * bz;\r\n out[2] = az * bw + aw * bz;\r\n out[3] = aw * bw - az * bz;\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the W component of a quat from the X, Y, and Z components.\r\n * Assumes that quaternion is 1 unit in length.\r\n * Any existing W component will be ignored.\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {quat} a quat to calculate W component of\r\n * @returns {quat} out\r\n */\r\nexport function calculateW(out, a) {\r\n let x = a[0], y = a[1], z = a[2];\r\n\r\n out[0] = x;\r\n out[1] = y;\r\n out[2] = z;\r\n out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));\r\n return out;\r\n}\r\n\r\n/**\r\n * Performs a spherical linear interpolation between two quat\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {quat} a the first operand\r\n * @param {quat} b the second operand\r\n * @param {Number} t interpolation amount between the two inputs\r\n * @returns {quat} out\r\n */\r\nexport function slerp(out, a, b, t) {\r\n // benchmarks:\r\n // http://jsperf.com/quaternion-slerp-implementations\r\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\r\n let bx = b[0], by = b[1], bz = b[2], bw = b[3];\r\n\r\n let omega, cosom, sinom, scale0, scale1;\r\n\r\n // calc cosine\r\n cosom = ax * bx + ay * by + az * bz + aw * bw;\r\n // adjust signs (if necessary)\r\n if ( cosom < 0.0 ) {\r\n cosom = -cosom;\r\n bx = - bx;\r\n by = - by;\r\n bz = - bz;\r\n bw = - bw;\r\n }\r\n // calculate coefficients\r\n if ( (1.0 - cosom) > 0.000001 ) {\r\n // standard case (slerp)\r\n omega = Math.acos(cosom);\r\n sinom = Math.sin(omega);\r\n scale0 = Math.sin((1.0 - t) * omega) / sinom;\r\n scale1 = Math.sin(t * omega) / sinom;\r\n } else {\r\n // \"from\" and \"to\" quaternions are very close\r\n // ... so we can do a linear interpolation\r\n scale0 = 1.0 - t;\r\n scale1 = t;\r\n }\r\n // calculate final values\r\n out[0] = scale0 * ax + scale1 * bx;\r\n out[1] = scale0 * ay + scale1 * by;\r\n out[2] = scale0 * az + scale1 * bz;\r\n out[3] = scale0 * aw + scale1 * bw;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the inverse of a quat\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {quat} a quat to calculate inverse of\r\n * @returns {quat} out\r\n */\r\nexport function invert(out, a) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\r\n let dot = a0*a0 + a1*a1 + a2*a2 + a3*a3;\r\n let invDot = dot ? 1.0/dot : 0;\r\n\r\n // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0\r\n\r\n out[0] = -a0*invDot;\r\n out[1] = -a1*invDot;\r\n out[2] = -a2*invDot;\r\n out[3] = a3*invDot;\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the conjugate of a quat\r\n * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {quat} a quat to calculate conjugate of\r\n * @returns {quat} out\r\n */\r\nexport function conjugate(out, a) {\r\n out[0] = -a[0];\r\n out[1] = -a[1];\r\n out[2] = -a[2];\r\n out[3] = a[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a quaternion from the given 3x3 rotation matrix.\r\n *\r\n * NOTE: The resultant quaternion is not normalized, so you should be sure\r\n * to renormalize the quaternion yourself where necessary.\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {mat3} m rotation matrix\r\n * @returns {quat} out\r\n * @function\r\n */\r\nexport function fromMat3(out, m) {\r\n // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes\r\n // article \"Quaternion Calculus and Fast Animation\".\r\n let fTrace = m[0] + m[4] + m[8];\r\n let fRoot;\r\n\r\n if ( fTrace > 0.0 ) {\r\n // |w| > 1/2, may as well choose w > 1/2\r\n fRoot = Math.sqrt(fTrace + 1.0); // 2w\r\n out[3] = 0.5 * fRoot;\r\n fRoot = 0.5/fRoot; // 1/(4w)\r\n out[0] = (m[5]-m[7])*fRoot;\r\n out[1] = (m[6]-m[2])*fRoot;\r\n out[2] = (m[1]-m[3])*fRoot;\r\n } else {\r\n // |w| <= 1/2\r\n let i = 0;\r\n if ( m[4] > m[0] )\r\n i = 1;\r\n if ( m[8] > m[i*3+i] )\r\n i = 2;\r\n let j = (i+1)%3;\r\n let k = (i+2)%3;\r\n\r\n fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);\r\n out[i] = 0.5 * fRoot;\r\n fRoot = 0.5 / fRoot;\r\n out[3] = (m[j*3+k] - m[k*3+j]) * fRoot;\r\n out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;\r\n out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a quaternion from the given euler angle x, y, z.\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {x} Angle to rotate around X axis in degrees.\r\n * @param {y} Angle to rotate around Y axis in degrees.\r\n * @param {z} Angle to rotate around Z axis in degrees.\r\n * @returns {quat} out\r\n * @function\r\n */\r\nexport function fromEuler(out, x, y, z) {\r\n let halfToRad = 0.5 * Math.PI / 180.0;\r\n x *= halfToRad;\r\n y *= halfToRad;\r\n z *= halfToRad;\r\n\r\n let sx = Math.sin(x);\r\n let cx = Math.cos(x);\r\n let sy = Math.sin(y);\r\n let cy = Math.cos(y);\r\n let sz = Math.sin(z);\r\n let cz = Math.cos(z);\r\n\r\n out[0] = sx * cy * cz - cx * sy * sz;\r\n out[1] = cx * sy * cz + sx * cy * sz;\r\n out[2] = cx * cy * sz - sx * sy * cz;\r\n out[3] = cx * cy * cz + sx * sy * sz;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns a string representation of a quatenion\r\n *\r\n * @param {quat} a vector to represent as a string\r\n * @returns {String} string representation of the vector\r\n */\r\nexport function str(a) {\r\n return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\r\n}\r\n\r\n/**\r\n * Creates a new quat initialized with values from an existing quaternion\r\n *\r\n * @param {quat} a quaternion to clone\r\n * @returns {quat} a new quaternion\r\n * @function\r\n */\r\nexport const clone = vec4.clone;\r\n\r\n/**\r\n * Creates a new quat initialized with the given values\r\n *\r\n * @param {Number} x X component\r\n * @param {Number} y Y component\r\n * @param {Number} z Z component\r\n * @param {Number} w W component\r\n * @returns {quat} a new quaternion\r\n * @function\r\n */\r\nexport const fromValues = vec4.fromValues;\r\n\r\n/**\r\n * Copy the values from one quat to another\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {quat} a the source quaternion\r\n * @returns {quat} out\r\n * @function\r\n */\r\nexport const copy = vec4.copy;\r\n\r\n/**\r\n * Set the components of a quat to the given values\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {Number} x X component\r\n * @param {Number} y Y component\r\n * @param {Number} z Z component\r\n * @param {Number} w W component\r\n * @returns {quat} out\r\n * @function\r\n */\r\nexport const set = vec4.set;\r\n\r\n/**\r\n * Adds two quat's\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {quat} a the first operand\r\n * @param {quat} b the second operand\r\n * @returns {quat} out\r\n * @function\r\n */\r\nexport const add = vec4.add;\r\n\r\n/**\r\n * Alias for {@link quat.multiply}\r\n * @function\r\n */\r\nexport const mul = multiply;\r\n\r\n/**\r\n * Scales a quat by a scalar number\r\n *\r\n * @param {quat} out the receiving vector\r\n * @param {quat} a the vector to scale\r\n * @param {Number} b amount to scale the vector by\r\n * @returns {quat} out\r\n * @function\r\n */\r\nexport const scale = vec4.scale;\r\n\r\n/**\r\n * Calculates the dot product of two quat's\r\n *\r\n * @param {quat} a the first operand\r\n * @param {quat} b the second operand\r\n * @returns {Number} dot product of a and b\r\n * @function\r\n */\r\nexport const dot = vec4.dot;\r\n\r\n/**\r\n * Performs a linear interpolation between two quat's\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {quat} a the first operand\r\n * @param {quat} b the second operand\r\n * @param {Number} t interpolation amount between the two inputs\r\n * @returns {quat} out\r\n * @function\r\n */\r\nexport const lerp = vec4.lerp;\r\n\r\n/**\r\n * Calculates the length of a quat\r\n *\r\n * @param {quat} a vector to calculate length of\r\n * @returns {Number} length of a\r\n */\r\nexport const length = vec4.length;\r\n\r\n/**\r\n * Alias for {@link quat.length}\r\n * @function\r\n */\r\nexport const len = length;\r\n\r\n/**\r\n * Calculates the squared length of a quat\r\n *\r\n * @param {quat} a vector to calculate squared length of\r\n * @returns {Number} squared length of a\r\n * @function\r\n */\r\nexport const squaredLength = vec4.squaredLength;\r\n\r\n/**\r\n * Alias for {@link quat.squaredLength}\r\n * @function\r\n */\r\nexport const sqrLen = squaredLength;\r\n\r\n/**\r\n * Normalize a quat\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {quat} a quaternion to normalize\r\n * @returns {quat} out\r\n * @function\r\n */\r\nexport const normalize = vec4.normalize;\r\n\r\n/**\r\n * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)\r\n *\r\n * @param {quat} a The first quaternion.\r\n * @param {quat} b The second quaternion.\r\n * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n */\r\nexport const exactEquals = vec4.exactEquals;\r\n\r\n/**\r\n * Returns whether or not the quaternions have approximately the same elements in the same position.\r\n *\r\n * @param {quat} a The first vector.\r\n * @param {quat} b The second vector.\r\n * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n */\r\nexport const equals = vec4.equals;\r\n\r\n/**\r\n * Sets a quaternion to represent the shortest rotation from one\r\n * vector to another.\r\n *\r\n * Both vectors are assumed to be unit length.\r\n *\r\n * @param {quat} out the receiving quaternion.\r\n * @param {vec3} a the initial vector\r\n * @param {vec3} b the destination vector\r\n * @returns {quat} out\r\n */\r\nexport const rotationTo = (function() {\r\n let tmpvec3 = vec3.create();\r\n let xUnitVec3 = vec3.fromValues(1,0,0);\r\n let yUnitVec3 = vec3.fromValues(0,1,0);\r\n\r\n return function(out, a, b) {\r\n let dot = vec3.dot(a, b);\r\n if (dot < -0.999999) {\r\n vec3.cross(tmpvec3, xUnitVec3, a);\r\n if (vec3.len(tmpvec3) < 0.000001)\r\n vec3.cross(tmpvec3, yUnitVec3, a);\r\n vec3.normalize(tmpvec3, tmpvec3);\r\n setAxisAngle(out, tmpvec3, Math.PI);\r\n return out;\r\n } else if (dot > 0.999999) {\r\n out[0] = 0;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 1;\r\n return out;\r\n } else {\r\n vec3.cross(tmpvec3, a, b);\r\n out[0] = tmpvec3[0];\r\n out[1] = tmpvec3[1];\r\n out[2] = tmpvec3[2];\r\n out[3] = 1 + dot;\r\n return normalize(out, out);\r\n }\r\n };\r\n})();\r\n\r\n/**\r\n * Performs a spherical linear interpolation with two control points\r\n *\r\n * @param {quat} out the receiving quaternion\r\n * @param {quat} a the first operand\r\n * @param {quat} b the second operand\r\n * @param {quat} c the third operand\r\n * @param {quat} d the fourth operand\r\n * @param {Number} t interpolation amount\r\n * @returns {quat} out\r\n */\r\nexport const sqlerp = (function () {\r\n let temp1 = create();\r\n let temp2 = create();\r\n\r\n return function (out, a, b, c, d, t) {\r\n slerp(temp1, a, d, t);\r\n slerp(temp2, b, c, t);\r\n slerp(out, temp1, temp2, 2 * t * (1 - t));\r\n\r\n return out;\r\n };\r\n}());\r\n\r\n/**\r\n * Sets the specified quaternion with values corresponding to the given\r\n * axes. Each axis is a vec3 and is expected to be unit length and\r\n * perpendicular to all other specified axes.\r\n *\r\n * @param {vec3} view the vector representing the viewing direction\r\n * @param {vec3} right the vector representing the local \"right\" direction\r\n * @param {vec3} up the vector representing the local \"up\" direction\r\n * @returns {quat} out\r\n */\r\nexport const setAxes = (function() {\r\n let matr = mat3.create();\r\n\r\n return function(out, view, right, up) {\r\n matr[0] = right[0];\r\n matr[3] = right[1];\r\n matr[6] = right[2];\r\n\r\n matr[1] = up[0];\r\n matr[4] = up[1];\r\n matr[7] = up[2];\r\n\r\n matr[2] = -view[0];\r\n matr[5] = -view[1];\r\n matr[8] = -view[2];\r\n\r\n return normalize(out, fromMat3(out, matr));\r\n };\r\n})();\r\n","/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. */\r\n\r\n\r\nimport * as glMatrix from \"./common.js\";\r\nimport * as quat from \"./quat.js\";\r\nimport * as mat4 from \"./mat4.js\";\r\n\r\n/**\r\n * Dual Quaternion<br>\r\n * Format: [real, dual]<br>\r\n * Quaternion format: XYZW<br>\r\n * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>\r\n * @module quat2\r\n */\r\n\r\n\r\n/**\r\n * Creates a new identity dual quat\r\n *\r\n * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]\r\n */\r\nexport function create() {\r\n let dq = new glMatrix.ARRAY_TYPE(8);\r\n dq[0] = 0;\r\n dq[1] = 0;\r\n dq[2] = 0;\r\n dq[3] = 1;\r\n dq[4] = 0;\r\n dq[5] = 0;\r\n dq[6] = 0;\r\n dq[7] = 0;\r\n return dq;\r\n}\r\n\r\n/**\r\n * Creates a new quat initialized with values from an existing quaternion\r\n *\r\n * @param {quat2} a dual quaternion to clone\r\n * @returns {quat2} new dual quaternion\r\n * @function\r\n */\r\nexport function clone(a) {\r\n let dq = new glMatrix.ARRAY_TYPE(8);\r\n dq[0] = a[0];\r\n dq[1] = a[1];\r\n dq[2] = a[2];\r\n dq[3] = a[3];\r\n dq[4] = a[4];\r\n dq[5] = a[5];\r\n dq[6] = a[6];\r\n dq[7] = a[7];\r\n return dq;\r\n}\r\n\r\n/**\r\n * Creates a new dual quat initialized with the given values\r\n *\r\n * @param {Number} x1 X component\r\n * @param {Number} y1 Y component\r\n * @param {Number} z1 Z component\r\n * @param {Number} w1 W component\r\n * @param {Number} x2 X component\r\n * @param {Number} y2 Y component\r\n * @param {Number} z2 Z component\r\n * @param {Number} w2 W component\r\n * @returns {quat2} new dual quaternion\r\n * @function\r\n */\r\nexport function fromValues(x1, y1, z1, w1, x2, y2, z2, w2) {\r\n let dq = new glMatrix.ARRAY_TYPE(8);\r\n dq[0] = x1;\r\n dq[1] = y1;\r\n dq[2] = z1;\r\n dq[3] = w1;\r\n dq[4] = x2;\r\n dq[5] = y2;\r\n dq[6] = z2;\r\n dq[7] = w2;\r\n return dq;\r\n}\r\n\r\n/**\r\n * Creates a new dual quat from the given values (quat and translation)\r\n *\r\n * @param {Number} x1 X component\r\n * @param {Number} y1 Y component\r\n * @param {Number} z1 Z component\r\n * @param {Number} w1 W component\r\n * @param {Number} x2 X component (translation)\r\n * @param {Number} y2 Y component (translation)\r\n * @param {Number} z2 Z component (translation)\r\n * @returns {quat2} new dual quaternion\r\n * @function\r\n */\r\nexport function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {\r\n let dq = new glMatrix.ARRAY_TYPE(8);\r\n dq[0] = x1;\r\n dq[1] = y1;\r\n dq[2] = z1;\r\n dq[3] = w1;\r\n let ax = x2 * 0.5,\r\n ay = y2 * 0.5,\r\n az = z2 * 0.5;\r\n dq[4] = ax * w1 + ay * z1 - az * y1;\r\n dq[5] = ay * w1 + az * x1 - ax * z1;\r\n dq[6] = az * w1 + ax * y1 - ay * x1;\r\n dq[7] = -ax * x1 - ay * y1 - az * z1;\r\n return dq;\r\n}\r\n\r\n/**\r\n * Creates a dual quat from a quaternion and a translation\r\n *\r\n * @param {quat2} dual quaternion receiving operation result\r\n * @param {quat} q quaternion\r\n * @param {vec3} t tranlation vector\r\n * @returns {quat2} dual quaternion receiving operation result\r\n * @function\r\n */\r\nexport function fromRotationTranslation(out, q, t) {\r\n let ax = t[0] * 0.5,\r\n ay = t[1] * 0.5,\r\n az = t[2] * 0.5,\r\n bx = q[0],\r\n by = q[1],\r\n bz = q[2],\r\n bw = q[3];\r\n out[0] = bx;\r\n out[1] = by;\r\n out[2] = bz;\r\n out[3] = bw;\r\n out[4] = ax * bw + ay * bz - az * by;\r\n out[5] = ay * bw + az * bx - ax * bz;\r\n out[6] = az * bw + ax * by - ay * bx;\r\n out[7] = -ax * bx - ay * by - az * bz;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a dual quat from a translation\r\n *\r\n * @param {quat2} dual quaternion receiving operation result\r\n * @param {vec3} t translation vector\r\n * @returns {quat2} dual quaternion receiving operation result\r\n * @function\r\n */\r\nexport function fromTranslation(out, t) {\r\n out[0] = 0;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 1;\r\n out[4] = t[0] * 0.5;\r\n out[5] = t[1] * 0.5;\r\n out[6] = t[2] * 0.5;\r\n out[7] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a dual quat from a quaternion\r\n *\r\n * @param {quat2} dual quaternion receiving operation result\r\n * @param {quat} q the quaternion\r\n * @returns {quat2} dual quaternion receiving operation result\r\n * @function\r\n */\r\nexport function fromRotation(out, q) {\r\n out[0] = q[0];\r\n out[1] = q[1];\r\n out[2] = q[2];\r\n out[3] = q[3];\r\n out[4] = 0;\r\n out[5] = 0;\r\n out[6] = 0;\r\n out[7] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a new dual quat from a matrix (4x4)\r\n * \r\n * @param {quat2} out the dual quaternion\r\n * @param {mat4} a the matrix\r\n * @returns {quat2} dual quat receiving operation result\r\n * @function\r\n */\r\nexport function fromMat4(out, a) {\r\n //TODO Optimize this \r\n let outer = quat.create();\r\n mat4.getRotation(outer, a);\r\n let t = new glMatrix.ARRAY_TYPE(3);\r\n mat4.getTranslation(t, a);\r\n fromRotationTranslation(out, outer, t);\r\n return out;\r\n}\r\n\r\n/**\r\n * Copy the values from one dual quat to another\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat2} a the source dual quaternion\r\n * @returns {quat2} out\r\n * @function\r\n */\r\nexport function copy(out, a) {\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n out[4] = a[4];\r\n out[5] = a[5];\r\n out[6] = a[6];\r\n out[7] = a[7];\r\n return out;\r\n}\r\n\r\n/**\r\n * Set a dual quat to the identity dual quaternion\r\n *\r\n * @param {quat2} out the receiving quaternion\r\n * @returns {quat2} out\r\n */\r\nexport function identity(out) {\r\n out[0] = 0;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 1;\r\n out[4] = 0;\r\n out[5] = 0;\r\n out[6] = 0;\r\n out[7] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Set the components of a dual quat to the given values\r\n *\r\n * @param {quat2} out the receiving quaternion\r\n * @param {Number} x1 X component\r\n * @param {Number} y1 Y component\r\n * @param {Number} z1 Z component\r\n * @param {Number} w1 W component\r\n * @param {Number} x2 X component\r\n * @param {Number} y2 Y component\r\n * @param {Number} z2 Z component\r\n * @param {Number} w2 W component\r\n * @returns {quat2} out\r\n * @function\r\n */\r\nexport function set(out, x1, y1, z1, w1, x2, y2, z2, w2) {\r\n out[0] = x1;\r\n out[1] = y1;\r\n out[2] = z1;\r\n out[3] = w1;\r\n\r\n out[4] = x2;\r\n out[5] = y2;\r\n out[6] = z2;\r\n out[7] = w2;\r\n return out;\r\n}\r\n\r\n/**\r\n * Gets the real part of a dual quat\r\n * @param {quat} out real part\r\n * @param {quat2} a Dual Quaternion\r\n * @return {quat} real part\r\n */\r\nexport const getReal = quat.copy;\r\n\r\n/**\r\n * Gets the dual part of a dual quat\r\n * @param {quat} out dual part\r\n * @param {quat2} a Dual Quaternion\r\n * @return {quat} dual part\r\n */\r\nexport function getDual(out, a) {\r\n out[0] = a[4];\r\n out[1] = a[5];\r\n out[2] = a[6];\r\n out[3] = a[7];\r\n return out;\r\n}\r\n\r\n/**\r\n * Set the real component of a dual quat to the given quaternion\r\n *\r\n * @param {quat2} out the receiving quaternion\r\n * @param {quat} q a quaternion representing the real part\r\n * @returns {quat2} out\r\n * @function\r\n */\r\nexport const setReal = quat.copy;\r\n\r\n/**\r\n * Set the dual component of a dual quat to the given quaternion\r\n *\r\n * @param {quat2} out the receiving quaternion\r\n * @param {quat} q a quaternion representing the dual part\r\n * @returns {quat2} out\r\n * @function\r\n */\r\nexport function setDual(out, q) {\r\n out[4] = q[0];\r\n out[5] = q[1];\r\n out[6] = q[2];\r\n out[7] = q[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Gets the translation of a normalized dual quat\r\n * @param {vec3} out translation\r\n * @param {quat2} a Dual Quaternion to be decomposed\r\n * @return {vec3} translation\r\n */\r\nexport function getTranslation(out, a) {\r\n let ax = a[4],\r\n ay = a[5],\r\n az = a[6],\r\n aw = a[7],\r\n bx = -a[0],\r\n by = -a[1],\r\n bz = -a[2],\r\n bw = a[3];\r\n out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;\r\n out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;\r\n out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;\r\n return out;\r\n}\r\n\r\n/**\r\n * Translates a dual quat by the given vector\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat2} a the dual quaternion to translate\r\n * @param {vec3} v vector to translate by\r\n * @returns {quat2} out\r\n */\r\nexport function translate(out, a, v) {\r\n let ax1 = a[0],\r\n ay1 = a[1],\r\n az1 = a[2],\r\n aw1 = a[3],\r\n bx1 = v[0] * 0.5,\r\n by1 = v[1] * 0.5,\r\n bz1 = v[2] * 0.5,\r\n ax2 = a[4],\r\n ay2 = a[5],\r\n az2 = a[6],\r\n aw2 = a[7];\r\n out[0] = ax1;\r\n out[1] = ay1;\r\n out[2] = az1;\r\n out[3] = aw1;\r\n out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;\r\n out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;\r\n out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;\r\n out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a dual quat around the X axis\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat2} a the dual quaternion to rotate\r\n * @param {number} rad how far should the rotation be\r\n * @returns {quat2} out\r\n */\r\nexport function rotateX(out, a, rad) {\r\n let bx = -a[0],\r\n by = -a[1],\r\n bz = -a[2],\r\n bw = a[3],\r\n ax = a[4],\r\n ay = a[5],\r\n az = a[6],\r\n aw = a[7],\r\n ax1 = ax * bw + aw * bx + ay * bz - az * by,\r\n ay1 = ay * bw + aw * by + az * bx - ax * bz,\r\n az1 = az * bw + aw * bz + ax * by - ay * bx,\r\n aw1 = aw * bw - ax * bx - ay * by - az * bz;\r\n quat.rotateX(out, a, rad);\r\n bx = out[0];\r\n by = out[1];\r\n bz = out[2];\r\n bw = out[3];\r\n out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\r\n out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\r\n out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\r\n out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a dual quat around the Y axis\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat2} a the dual quaternion to rotate\r\n * @param {number} rad how far should the rotation be\r\n * @returns {quat2} out\r\n */\r\nexport function rotateY(out, a, rad) {\r\n let bx = -a[0],\r\n by = -a[1],\r\n bz = -a[2],\r\n bw = a[3],\r\n ax = a[4],\r\n ay = a[5],\r\n az = a[6],\r\n aw = a[7],\r\n ax1 = ax * bw + aw * bx + ay * bz - az * by,\r\n ay1 = ay * bw + aw * by + az * bx - ax * bz,\r\n az1 = az * bw + aw * bz + ax * by - ay * bx,\r\n aw1 = aw * bw - ax * bx - ay * by - az * bz;\r\n quat.rotateY(out, a, rad);\r\n bx = out[0];\r\n by = out[1];\r\n bz = out[2];\r\n bw = out[3];\r\n out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\r\n out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\r\n out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\r\n out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a dual quat around the Z axis\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat2} a the dual quaternion to rotate\r\n * @param {number} rad how far should the rotation be\r\n * @returns {quat2} out\r\n */\r\nexport function rotateZ(out, a, rad) {\r\n let bx = -a[0],\r\n by = -a[1],\r\n bz = -a[2],\r\n bw = a[3],\r\n ax = a[4],\r\n ay = a[5],\r\n az = a[6],\r\n aw = a[7],\r\n ax1 = ax * bw + aw * bx + ay * bz - az * by,\r\n ay1 = ay * bw + aw * by + az * bx - ax * bz,\r\n az1 = az * bw + aw * bz + ax * by - ay * bx,\r\n aw1 = aw * bw - ax * bx - ay * by - az * bz;\r\n quat.rotateZ(out, a, rad);\r\n bx = out[0];\r\n by = out[1];\r\n bz = out[2];\r\n bw = out[3];\r\n out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\r\n out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\r\n out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\r\n out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a dual quat by a given quaternion (a * q)\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat2} a the dual quaternion to rotate\r\n * @param {quat} q quaternion to rotate by\r\n * @returns {quat2} out\r\n */\r\nexport function rotateByQuatAppend(out, a, q) {\r\n let qx = q[0],\r\n qy = q[1],\r\n qz = q[2],\r\n qw = q[3],\r\n ax = a[0],\r\n ay = a[1],\r\n az = a[2],\r\n aw = a[3];\r\n\r\n out[0] = ax * qw + aw * qx + ay * qz - az * qy;\r\n out[1] = ay * qw + aw * qy + az * qx - ax * qz;\r\n out[2] = az * qw + aw * qz + ax * qy - ay * qx;\r\n out[3] = aw * qw - ax * qx - ay * qy - az * qz;\r\n ax = a[4];\r\n ay = a[5];\r\n az = a[6];\r\n aw = a[7];\r\n out[4] = ax * qw + aw * qx + ay * qz - az * qy;\r\n out[5] = ay * qw + aw * qy + az * qx - ax * qz;\r\n out[6] = az * qw + aw * qz + ax * qy - ay * qx;\r\n out[7] = aw * qw - ax * qx - ay * qy - az * qz;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a dual quat by a given quaternion (q * a)\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat} q quaternion to rotate by\r\n * @param {quat2} a the dual quaternion to rotate\r\n * @returns {quat2} out\r\n */\r\nexport function rotateByQuatPrepend(out, q, a) {\r\n let qx = q[0],\r\n qy = q[1],\r\n qz = q[2],\r\n qw = q[3],\r\n bx = a[0],\r\n by = a[1],\r\n bz = a[2],\r\n bw = a[3];\r\n\r\n out[0] = qx * bw + qw * bx + qy * bz - qz * by;\r\n out[1] = qy * bw + qw * by + qz * bx - qx * bz;\r\n out[2] = qz * bw + qw * bz + qx * by - qy * bx;\r\n out[3] = qw * bw - qx * bx - qy * by - qz * bz;\r\n bx = a[4];\r\n by = a[5];\r\n bz = a[6];\r\n bw = a[7];\r\n out[4] = qx * bw + qw * bx + qy * bz - qz * by;\r\n out[5] = qy * bw + qw * by + qz * bx - qx * bz;\r\n out[6] = qz * bw + qw * bz + qx * by - qy * bx;\r\n out[7] = qw * bw - qx * bx - qy * by - qz * bz;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotates a dual quat around a given axis. Does the normalisation automatically\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat2} a the dual quaternion to rotate\r\n * @param {vec3} axis the axis to rotate around\r\n * @param {Number} rad how far the rotation should be\r\n * @returns {quat2} out\r\n */\r\nexport function rotateAroundAxis(out, a, axis, rad) {\r\n //Special case for rad = 0\r\n if (Math.abs(rad) < glMatrix.EPSILON) {\r\n return copy(out, a);\r\n }\r\n let axisLength = Math.sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);\r\n\r\n rad = rad * 0.5;\r\n let s = Math.sin(rad);\r\n let bx = s * axis[0] / axisLength;\r\n let by = s * axis[1] / axisLength;\r\n let bz = s * axis[2] / axisLength;\r\n let bw = Math.cos(rad);\r\n\r\n let ax1 = a[0],\r\n ay1 = a[1],\r\n az1 = a[2],\r\n aw1 = a[3];\r\n out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\r\n out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\r\n out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\r\n out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\r\n\r\n let ax = a[4],\r\n ay = a[5],\r\n az = a[6],\r\n aw = a[7];\r\n out[4] = ax * bw + aw * bx + ay * bz - az * by;\r\n out[5] = ay * bw + aw * by + az * bx - ax * bz;\r\n out[6] = az * bw + aw * bz + ax * by - ay * bx;\r\n out[7] = aw * bw - ax * bx - ay * by - az * bz;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Adds two dual quat's\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat2} a the first operand\r\n * @param {quat2} b the second operand\r\n * @returns {quat2} out\r\n * @function\r\n */\r\nexport function add(out, a, b) {\r\n out[0] = a[0] + b[0];\r\n out[1] = a[1] + b[1];\r\n out[2] = a[2] + b[2];\r\n out[3] = a[3] + b[3];\r\n out[4] = a[4] + b[4];\r\n out[5] = a[5] + b[5];\r\n out[6] = a[6] + b[6];\r\n out[7] = a[7] + b[7];\r\n return out;\r\n}\r\n\r\n/**\r\n * Multiplies two dual quat's\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat2} a the first operand\r\n * @param {quat2} b the second operand\r\n * @returns {quat2} out\r\n */\r\nexport function multiply(out, a, b) {\r\n let ax0 = a[0],\r\n ay0 = a[1],\r\n az0 = a[2],\r\n aw0 = a[3],\r\n bx1 = b[4],\r\n by1 = b[5],\r\n bz1 = b[6],\r\n bw1 = b[7],\r\n ax1 = a[4],\r\n ay1 = a[5],\r\n az1 = a[6],\r\n aw1 = a[7],\r\n bx0 = b[0],\r\n by0 = b[1],\r\n bz0 = b[2],\r\n bw0 = b[3];\r\n out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;\r\n out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;\r\n out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;\r\n out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;\r\n out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;\r\n out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;\r\n out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;\r\n out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Alias for {@link quat2.multiply}\r\n * @function\r\n */\r\nexport const mul = multiply;\r\n\r\n/**\r\n * Scales a dual quat by a scalar number\r\n *\r\n * @param {quat2} out the receiving dual quat\r\n * @param {quat2} a the dual quat to scale\r\n * @param {Number} b amount to scale the dual quat by\r\n * @returns {quat2} out\r\n * @function\r\n */\r\nexport function scale(out, a, b) {\r\n out[0] = a[0] * b;\r\n out[1] = a[1] * b;\r\n out[2] = a[2] * b;\r\n out[3] = a[3] * b;\r\n out[4] = a[4] * b;\r\n out[5] = a[5] * b;\r\n out[6] = a[6] * b;\r\n out[7] = a[7] * b;\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the dot product of two dual quat's (The dot product of the real parts)\r\n *\r\n * @param {quat2} a the first operand\r\n * @param {quat2} b the second operand\r\n * @returns {Number} dot product of a and b\r\n * @function\r\n */\r\nexport const dot = quat.dot;\r\n\r\n/**\r\n * Performs a linear interpolation between two dual quats's\r\n * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)\r\n *\r\n * @param {quat2} out the receiving dual quat\r\n * @param {quat2} a the first operand\r\n * @param {quat2} b the second operand\r\n * @param {Number} t interpolation amount between the two inputs\r\n * @returns {quat2} out\r\n */\r\nexport function lerp(out, a, b, t) {\r\n let mt = 1 - t;\r\n if (dot(a, b) < 0) t = -t;\r\n\r\n out[0] = a[0] * mt + b[0] * t;\r\n out[1] = a[1] * mt + b[1] * t;\r\n out[2] = a[2] * mt + b[2] * t;\r\n out[3] = a[3] * mt + b[3] * t;\r\n out[4] = a[4] * mt + b[4] * t;\r\n out[5] = a[5] * mt + b[5] * t;\r\n out[6] = a[6] * mt + b[6] * t;\r\n out[7] = a[7] * mt + b[7] * t;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat2} a dual quat to calculate inverse of\r\n * @returns {quat2} out\r\n */\r\nexport function invert(out, a) {\r\n let sqlen = squaredLength(a);\r\n out[0] = -a[0] / sqlen;\r\n out[1] = -a[1] / sqlen;\r\n out[2] = -a[2] / sqlen;\r\n out[3] = a[3] / sqlen;\r\n out[4] = -a[4] / sqlen;\r\n out[5] = -a[5] / sqlen;\r\n out[6] = -a[6] / sqlen;\r\n out[7] = a[7] / sqlen;\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the conjugate of a dual quat\r\n * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.\r\n *\r\n * @param {quat2} out the receiving quaternion\r\n * @param {quat2} a quat to calculate conjugate of\r\n * @returns {quat2} out\r\n */\r\nexport function conjugate(out, a) {\r\n out[0] = -a[0];\r\n out[1] = -a[1];\r\n out[2] = -a[2];\r\n out[3] = a[3];\r\n out[4] = -a[4];\r\n out[5] = -a[5];\r\n out[6] = -a[6];\r\n out[7] = a[7];\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the length of a dual quat\r\n *\r\n * @param {quat2} a dual quat to calculate length of\r\n * @returns {Number} length of a\r\n * @function\r\n */\r\nexport const length = quat.length;\r\n\r\n/**\r\n * Alias for {@link quat2.length}\r\n * @function\r\n */\r\nexport const len = length;\r\n\r\n/**\r\n * Calculates the squared length of a dual quat\r\n *\r\n * @param {quat2} a dual quat to calculate squared length of\r\n * @returns {Number} squared length of a\r\n * @function\r\n */\r\nexport const squaredLength = quat.squaredLength;\r\n\r\n/**\r\n * Alias for {@link quat2.squaredLength}\r\n * @function\r\n */\r\nexport const sqrLen = squaredLength;\r\n\r\n/**\r\n * Normalize a dual quat\r\n *\r\n * @param {quat2} out the receiving dual quaternion\r\n * @param {quat2} a dual quaternion to normalize\r\n * @returns {quat2} out\r\n * @function\r\n */\r\nexport function normalize(out, a) {\r\n let magnitude = squaredLength(a);\r\n if (magnitude > 0) {\r\n magnitude = Math.sqrt(magnitude);\r\n out[0] = a[0] / magnitude;\r\n out[1] = a[1] / magnitude;\r\n out[2] = a[2] / magnitude;\r\n out[3] = a[3] / magnitude;\r\n out[4] = a[4] / magnitude;\r\n out[5] = a[5] / magnitude;\r\n out[6] = a[6] / magnitude;\r\n out[7] = a[7] / magnitude;\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns a string representation of a dual quatenion\r\n *\r\n * @param {quat2} a dual quaternion to represent as a string\r\n * @returns {String} string representation of the dual quat\r\n */\r\nexport function str(a) {\r\n return 'quat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +\r\n a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ')';\r\n}\r\n\r\n/**\r\n * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)\r\n *\r\n * @param {quat2} a the first dual quaternion.\r\n * @param {quat2} b the second dual quaternion.\r\n * @returns {Boolean} true if the dual quaternions are equal, false otherwise.\r\n */\r\nexport function exactEquals(a, b) {\r\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] &&\r\n a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];\r\n}\r\n\r\n/**\r\n * Returns whether or not the dual quaternions have approximately the same elements in the same position.\r\n *\r\n * @param {quat2} a the first dual quat.\r\n * @param {quat2} b the second dual quat.\r\n * @returns {Boolean} true if the dual quats are equal, false otherwise.\r\n */\r\nexport function equals(a, b) {\r\n let a0 = a[0],\r\n a1 = a[1],\r\n a2 = a[2],\r\n a3 = a[3],\r\n a4 = a[4],\r\n a5 = a[5],\r\n a6 = a[6],\r\n a7 = a[7];\r\n let b0 = b[0],\r\n b1 = b[1],\r\n b2 = b[2],\r\n b3 = b[3],\r\n b4 = b[4],\r\n b5 = b[5],\r\n b6 = b[6],\r\n b7 = b[7];\r\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\r\n Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\r\n Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\r\n Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&\r\n Math.abs(a6 - b6) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&\r\n Math.abs(a7 - b7) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)));\r\n}\r\n","/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. */\r\n\r\nimport * as glMatrix from \"./common.js\";\r\n\r\n/**\r\n * 2 Dimensional Vector\r\n * @module vec2\r\n */\r\n\r\n/**\r\n * Creates a new, empty vec2\r\n *\r\n * @returns {vec2} a new 2D vector\r\n */\r\nexport function create() {\r\n let out = new glMatrix.ARRAY_TYPE(2);\r\n out[0] = 0;\r\n out[1] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a new vec2 initialized with values from an existing vector\r\n *\r\n * @param {vec2} a vector to clone\r\n * @returns {vec2} a new 2D vector\r\n */\r\nexport function clone(a) {\r\n let out = new glMatrix.ARRAY_TYPE(2);\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a new vec2 initialized with the given values\r\n *\r\n * @param {Number} x X component\r\n * @param {Number} y Y component\r\n * @returns {vec2} a new 2D vector\r\n */\r\nexport function fromValues(x, y) {\r\n let out = new glMatrix.ARRAY_TYPE(2);\r\n out[0] = x;\r\n out[1] = y;\r\n return out;\r\n}\r\n\r\n/**\r\n * Copy the values from one vec2 to another\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the source vector\r\n * @returns {vec2} out\r\n */\r\nexport function copy(out, a) {\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n return out;\r\n}\r\n\r\n/**\r\n * Set the components of a vec2 to the given values\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {Number} x X component\r\n * @param {Number} y Y component\r\n * @returns {vec2} out\r\n */\r\nexport function set(out, x, y) {\r\n out[0] = x;\r\n out[1] = y;\r\n return out;\r\n}\r\n\r\n/**\r\n * Adds two vec2's\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @returns {vec2} out\r\n */\r\nexport function add(out, a, b) {\r\n out[0] = a[0] + b[0];\r\n out[1] = a[1] + b[1];\r\n return out;\r\n}\r\n\r\n/**\r\n * Subtracts vector b from vector a\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @returns {vec2} out\r\n */\r\nexport function subtract(out, a, b) {\r\n out[0] = a[0] - b[0];\r\n out[1] = a[1] - b[1];\r\n return out;\r\n}\r\n\r\n/**\r\n * Multiplies two vec2's\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @returns {vec2} out\r\n */\r\nexport function multiply(out, a, b) {\r\n out[0] = a[0] * b[0];\r\n out[1] = a[1] * b[1];\r\n return out;\r\n};\r\n\r\n/**\r\n * Divides two vec2's\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @returns {vec2} out\r\n */\r\nexport function divide(out, a, b) {\r\n out[0] = a[0] / b[0];\r\n out[1] = a[1] / b[1];\r\n return out;\r\n};\r\n\r\n/**\r\n * Math.ceil the components of a vec2\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a vector to ceil\r\n * @returns {vec2} out\r\n */\r\nexport function ceil(out, a) {\r\n out[0] = Math.ceil(a[0]);\r\n out[1] = Math.ceil(a[1]);\r\n return out;\r\n};\r\n\r\n/**\r\n * Math.floor the components of a vec2\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a vector to floor\r\n * @returns {vec2} out\r\n */\r\nexport function floor(out, a) {\r\n out[0] = Math.floor(a[0]);\r\n out[1] = Math.floor(a[1]);\r\n return out;\r\n};\r\n\r\n/**\r\n * Returns the minimum of two vec2's\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @returns {vec2} out\r\n */\r\nexport function min(out, a, b) {\r\n out[0] = Math.min(a[0], b[0]);\r\n out[1] = Math.min(a[1], b[1]);\r\n return out;\r\n};\r\n\r\n/**\r\n * Returns the maximum of two vec2's\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @returns {vec2} out\r\n */\r\nexport function max(out, a, b) {\r\n out[0] = Math.max(a[0], b[0]);\r\n out[1] = Math.max(a[1], b[1]);\r\n return out;\r\n};\r\n\r\n/**\r\n * Math.round the components of a vec2\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a vector to round\r\n * @returns {vec2} out\r\n */\r\nexport function round (out, a) {\r\n out[0] = Math.round(a[0]);\r\n out[1] = Math.round(a[1]);\r\n return out;\r\n};\r\n\r\n/**\r\n * Scales a vec2 by a scalar number\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the vector to scale\r\n * @param {Number} b amount to scale the vector by\r\n * @returns {vec2} out\r\n */\r\nexport function scale(out, a, b) {\r\n out[0] = a[0] * b;\r\n out[1] = a[1] * b;\r\n return out;\r\n};\r\n\r\n/**\r\n * Adds two vec2's after scaling the second operand by a scalar value\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @param {Number} scale the amount to scale b by before adding\r\n * @returns {vec2} out\r\n */\r\nexport function scaleAndAdd(out, a, b, scale) {\r\n out[0] = a[0] + (b[0] * scale);\r\n out[1] = a[1] + (b[1] * scale);\r\n return out;\r\n};\r\n\r\n/**\r\n * Calculates the euclidian distance between two vec2's\r\n *\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @returns {Number} distance between a and b\r\n */\r\nexport function distance(a, b) {\r\n var x = b[0] - a[0],\r\n y = b[1] - a[1];\r\n return Math.sqrt(x*x + y*y);\r\n};\r\n\r\n/**\r\n * Calculates the squared euclidian distance between two vec2's\r\n *\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @returns {Number} squared distance between a and b\r\n */\r\nexport function squaredDistance(a, b) {\r\n var x = b[0] - a[0],\r\n y = b[1] - a[1];\r\n return x*x + y*y;\r\n};\r\n\r\n/**\r\n * Calculates the length of a vec2\r\n *\r\n * @param {vec2} a vector to calculate length of\r\n * @returns {Number} length of a\r\n */\r\nexport function length(a) {\r\n var x = a[0],\r\n y = a[1];\r\n return Math.sqrt(x*x + y*y);\r\n};\r\n\r\n/**\r\n * Calculates the squared length of a vec2\r\n *\r\n * @param {vec2} a vector to calculate squared length of\r\n * @returns {Number} squared length of a\r\n */\r\nexport function squaredLength (a) {\r\n var x = a[0],\r\n y = a[1];\r\n return x*x + y*y;\r\n};\r\n\r\n/**\r\n * Negates the components of a vec2\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a vector to negate\r\n * @returns {vec2} out\r\n */\r\nexport function negate(out, a) {\r\n out[0] = -a[0];\r\n out[1] = -a[1];\r\n return out;\r\n};\r\n\r\n/**\r\n * Returns the inverse of the components of a vec2\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a vector to invert\r\n * @returns {vec2} out\r\n */\r\nexport function inverse(out, a) {\r\n out[0] = 1.0 / a[0];\r\n out[1] = 1.0 / a[1];\r\n return out;\r\n};\r\n\r\n/**\r\n * Normalize a vec2\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a vector to normalize\r\n * @returns {vec2} out\r\n */\r\nexport function normalize(out, a) {\r\n var x = a[0],\r\n y = a[1];\r\n var len = x*x + y*y;\r\n if (len > 0) {\r\n //TODO: evaluate use of glm_invsqrt here?\r\n len = 1 / Math.sqrt(len);\r\n out[0] = a[0] * len;\r\n out[1] = a[1] * len;\r\n }\r\n return out;\r\n};\r\n\r\n/**\r\n * Calculates the dot product of two vec2's\r\n *\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @returns {Number} dot product of a and b\r\n */\r\nexport function dot(a, b) {\r\n return a[0] * b[0] + a[1] * b[1];\r\n};\r\n\r\n/**\r\n * Computes the cross product of two vec2's\r\n * Note that the cross product must by definition produce a 3D vector\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @returns {vec3} out\r\n */\r\nexport function cross(out, a, b) {\r\n var z = a[0] * b[1] - a[1] * b[0];\r\n out[0] = out[1] = 0;\r\n out[2] = z;\r\n return out;\r\n};\r\n\r\n/**\r\n * Performs a linear interpolation between two vec2's\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the first operand\r\n * @param {vec2} b the second operand\r\n * @param {Number} t interpolation amount between the two inputs\r\n * @returns {vec2} out\r\n */\r\nexport function lerp(out, a, b, t) {\r\n var ax = a[0],\r\n ay = a[1];\r\n out[0] = ax + t * (b[0] - ax);\r\n out[1] = ay + t * (b[1] - ay);\r\n return out;\r\n};\r\n\r\n/**\r\n * Generates a random vector with the given scale\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\r\n * @returns {vec2} out\r\n */\r\nexport function random(out, scale) {\r\n scale = scale || 1.0;\r\n var r = glMatrix.RANDOM() * 2.0 * Math.PI;\r\n out[0] = Math.cos(r) * scale;\r\n out[1] = Math.sin(r) * scale;\r\n return out;\r\n};\r\n\r\n/**\r\n * Transforms the vec2 with a mat2\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the vector to transform\r\n * @param {mat2} m matrix to transform with\r\n * @returns {vec2} out\r\n */\r\nexport function transformMat2(out, a, m) {\r\n var x = a[0],\r\n y = a[1];\r\n out[0] = m[0] * x + m[2] * y;\r\n out[1] = m[1] * x + m[3] * y;\r\n return out;\r\n};\r\n\r\n/**\r\n * Transforms the vec2 with a mat2d\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the vector to transform\r\n * @param {mat2d} m matrix to transform with\r\n * @returns {vec2} out\r\n */\r\nexport function transformMat2d(out, a, m) {\r\n var x = a[0],\r\n y = a[1];\r\n out[0] = m[0] * x + m[2] * y + m[4];\r\n out[1] = m[1] * x + m[3] * y + m[5];\r\n return out;\r\n};\r\n\r\n/**\r\n * Transforms the vec2 with a mat3\r\n * 3rd vector component is implicitly '1'\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the vector to transform\r\n * @param {mat3} m matrix to transform with\r\n * @returns {vec2} out\r\n */\r\nexport function transformMat3(out, a, m) {\r\n var x = a[0],\r\n y = a[1];\r\n out[0] = m[0] * x + m[3] * y + m[6];\r\n out[1] = m[1] * x + m[4] * y + m[7];\r\n return out;\r\n};\r\n\r\n/**\r\n * Transforms the vec2 with a mat4\r\n * 3rd vector component is implicitly '0'\r\n * 4th vector component is implicitly '1'\r\n *\r\n * @param {vec2} out the receiving vector\r\n * @param {vec2} a the vector to transform\r\n * @param {mat4} m matrix to transform with\r\n * @returns {vec2} out\r\n */\r\nexport function transformMat4(out, a, m) {\r\n let x = a[0];\r\n let y = a[1];\r\n out[0] = m[0] * x + m[4] * y + m[12];\r\n out[1] = m[1] * x + m[5] * y + m[13];\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns a string representation of a vector\r\n *\r\n * @param {vec2} a vector to represent as a string\r\n * @returns {String} string representation of the vector\r\n */\r\nexport function str(a) {\r\n return 'vec2(' + a[0] + ', ' + a[1] + ')';\r\n}\r\n\r\n/**\r\n * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)\r\n *\r\n * @param {vec2} a The first vector.\r\n * @param {vec2} b The second vector.\r\n * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n */\r\nexport function exactEquals(a, b) {\r\n return a[0] === b[0] && a[1] === b[1];\r\n}\r\n\r\n/**\r\n * Returns whether or not the vectors have approximately the same elements in the same position.\r\n *\r\n * @param {vec2} a The first vector.\r\n * @param {vec2} b The second vector.\r\n * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n */\r\nexport function equals(a, b) {\r\n let a0 = a[0], a1 = a[1];\r\n let b0 = b[0], b1 = b[1];\r\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)));\r\n}\r\n\r\n/**\r\n * Alias for {@link vec2.length}\r\n * @function\r\n */\r\nexport const len = length;\r\n\r\n/**\r\n * Alias for {@link vec2.subtract}\r\n * @function\r\n */\r\nexport const sub = subtract;\r\n\r\n/**\r\n * Alias for {@link vec2.multiply}\r\n * @function\r\n */\r\nexport const mul = multiply;\r\n\r\n/**\r\n * Alias for {@link vec2.divide}\r\n * @function\r\n */\r\nexport const div = divide;\r\n\r\n/**\r\n * Alias for {@link vec2.distance}\r\n * @function\r\n */\r\nexport const dist = distance;\r\n\r\n/**\r\n * Alias for {@link vec2.squaredDistance}\r\n * @function\r\n */\r\nexport const sqrDist = squaredDistance;\r\n\r\n/**\r\n * Alias for {@link vec2.squaredLength}\r\n * @function\r\n */\r\nexport const sqrLen = squaredLength;\r\n\r\n/**\r\n * Perform some operation over an array of vec2s.\r\n *\r\n * @param {Array} a the array of vectors to iterate over\r\n * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed\r\n * @param {Number} offset Number of elements to skip at the beginning of the array\r\n * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array\r\n * @param {Function} fn Function to call for each vector in the array\r\n * @param {Object} [arg] additional argument to pass to fn\r\n * @returns {Array} a\r\n * @function\r\n */\r\nexport const forEach = (function() {\r\n let vec = create();\r\n\r\n return function(a, stride, offset, count, fn, arg) {\r\n let i, l;\r\n if(!stride) {\r\n stride = 2;\r\n }\r\n\r\n if(!offset) {\r\n offset = 0;\r\n }\r\n\r\n if(count) {\r\n l = Math.min((count * stride) + offset, a.length);\r\n } else {\r\n l = a.length;\r\n }\r\n\r\n for(i = offset; i < l; i += stride) {\r\n vec[0] = a[i]; vec[1] = a[i+1];\r\n fn(vec, vec, arg);\r\n a[i] = vec[0]; a[i+1] = vec[1];\r\n }\r\n\r\n return a;\r\n };\r\n})();\r\n","/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. */\r\n\r\nimport * as glMatrix from \"./common.js\";\r\n\r\n/**\r\n * 3 Dimensional Vector\r\n * @module vec3\r\n */\r\n\r\n/**\r\n * Creates a new, empty vec3\r\n *\r\n * @returns {vec3} a new 3D vector\r\n */\r\nexport function create() {\r\n let out = new glMatrix.ARRAY_TYPE(3);\r\n out[0] = 0;\r\n out[1] = 0;\r\n out[2] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a new vec3 initialized with values from an existing vector\r\n *\r\n * @param {vec3} a vector to clone\r\n * @returns {vec3} a new 3D vector\r\n */\r\nexport function clone(a) {\r\n var out = new glMatrix.ARRAY_TYPE(3);\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the length of a vec3\r\n *\r\n * @param {vec3} a vector to calculate length of\r\n * @returns {Number} length of a\r\n */\r\nexport function length(a) {\r\n let x = a[0];\r\n let y = a[1];\r\n let z = a[2];\r\n return Math.sqrt(x*x + y*y + z*z);\r\n}\r\n\r\n/**\r\n * Creates a new vec3 initialized with the given values\r\n *\r\n * @param {Number} x X component\r\n * @param {Number} y Y component\r\n * @param {Number} z Z component\r\n * @returns {vec3} a new 3D vector\r\n */\r\nexport function fromValues(x, y, z) {\r\n let out = new glMatrix.ARRAY_TYPE(3);\r\n out[0] = x;\r\n out[1] = y;\r\n out[2] = z;\r\n return out;\r\n}\r\n\r\n/**\r\n * Copy the values from one vec3 to another\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the source vector\r\n * @returns {vec3} out\r\n */\r\nexport function copy(out, a) {\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n return out;\r\n}\r\n\r\n/**\r\n * Set the components of a vec3 to the given values\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {Number} x X component\r\n * @param {Number} y Y component\r\n * @param {Number} z Z component\r\n * @returns {vec3} out\r\n */\r\nexport function set(out, x, y, z) {\r\n out[0] = x;\r\n out[1] = y;\r\n out[2] = z;\r\n return out;\r\n}\r\n\r\n/**\r\n * Adds two vec3's\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @returns {vec3} out\r\n */\r\nexport function add(out, a, b) {\r\n out[0] = a[0] + b[0];\r\n out[1] = a[1] + b[1];\r\n out[2] = a[2] + b[2];\r\n return out;\r\n}\r\n\r\n/**\r\n * Subtracts vector b from vector a\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @returns {vec3} out\r\n */\r\nexport function subtract(out, a, b) {\r\n out[0] = a[0] - b[0];\r\n out[1] = a[1] - b[1];\r\n out[2] = a[2] - b[2];\r\n return out;\r\n}\r\n\r\n/**\r\n * Multiplies two vec3's\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @returns {vec3} out\r\n */\r\nexport function multiply(out, a, b) {\r\n out[0] = a[0] * b[0];\r\n out[1] = a[1] * b[1];\r\n out[2] = a[2] * b[2];\r\n return out;\r\n}\r\n\r\n/**\r\n * Divides two vec3's\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @returns {vec3} out\r\n */\r\nexport function divide(out, a, b) {\r\n out[0] = a[0] / b[0];\r\n out[1] = a[1] / b[1];\r\n out[2] = a[2] / b[2];\r\n return out;\r\n}\r\n\r\n/**\r\n * Math.ceil the components of a vec3\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a vector to ceil\r\n * @returns {vec3} out\r\n */\r\nexport function ceil(out, a) {\r\n out[0] = Math.ceil(a[0]);\r\n out[1] = Math.ceil(a[1]);\r\n out[2] = Math.ceil(a[2]);\r\n return out;\r\n}\r\n\r\n/**\r\n * Math.floor the components of a vec3\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a vector to floor\r\n * @returns {vec3} out\r\n */\r\nexport function floor(out, a) {\r\n out[0] = Math.floor(a[0]);\r\n out[1] = Math.floor(a[1]);\r\n out[2] = Math.floor(a[2]);\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns the minimum of two vec3's\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @returns {vec3} out\r\n */\r\nexport function min(out, a, b) {\r\n out[0] = Math.min(a[0], b[0]);\r\n out[1] = Math.min(a[1], b[1]);\r\n out[2] = Math.min(a[2], b[2]);\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns the maximum of two vec3's\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @returns {vec3} out\r\n */\r\nexport function max(out, a, b) {\r\n out[0] = Math.max(a[0], b[0]);\r\n out[1] = Math.max(a[1], b[1]);\r\n out[2] = Math.max(a[2], b[2]);\r\n return out;\r\n}\r\n\r\n/**\r\n * Math.round the components of a vec3\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a vector to round\r\n * @returns {vec3} out\r\n */\r\nexport function round(out, a) {\r\n out[0] = Math.round(a[0]);\r\n out[1] = Math.round(a[1]);\r\n out[2] = Math.round(a[2]);\r\n return out;\r\n}\r\n\r\n/**\r\n * Scales a vec3 by a scalar number\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the vector to scale\r\n * @param {Number} b amount to scale the vector by\r\n * @returns {vec3} out\r\n */\r\nexport function scale(out, a, b) {\r\n out[0] = a[0] * b;\r\n out[1] = a[1] * b;\r\n out[2] = a[2] * b;\r\n return out;\r\n}\r\n\r\n/**\r\n * Adds two vec3's after scaling the second operand by a scalar value\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @param {Number} scale the amount to scale b by before adding\r\n * @returns {vec3} out\r\n */\r\nexport function scaleAndAdd(out, a, b, scale) {\r\n out[0] = a[0] + (b[0] * scale);\r\n out[1] = a[1] + (b[1] * scale);\r\n out[2] = a[2] + (b[2] * scale);\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the euclidian distance between two vec3's\r\n *\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @returns {Number} distance between a and b\r\n */\r\nexport function distance(a, b) {\r\n let x = b[0] - a[0];\r\n let y = b[1] - a[1];\r\n let z = b[2] - a[2];\r\n return Math.sqrt(x*x + y*y + z*z);\r\n}\r\n\r\n/**\r\n * Calculates the squared euclidian distance between two vec3's\r\n *\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @returns {Number} squared distance between a and b\r\n */\r\nexport function squaredDistance(a, b) {\r\n let x = b[0] - a[0];\r\n let y = b[1] - a[1];\r\n let z = b[2] - a[2];\r\n return x*x + y*y + z*z;\r\n}\r\n\r\n/**\r\n * Calculates the squared length of a vec3\r\n *\r\n * @param {vec3} a vector to calculate squared length of\r\n * @returns {Number} squared length of a\r\n */\r\nexport function squaredLength(a) {\r\n let x = a[0];\r\n let y = a[1];\r\n let z = a[2];\r\n return x*x + y*y + z*z;\r\n}\r\n\r\n/**\r\n * Negates the components of a vec3\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a vector to negate\r\n * @returns {vec3} out\r\n */\r\nexport function negate(out, a) {\r\n out[0] = -a[0];\r\n out[1] = -a[1];\r\n out[2] = -a[2];\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns the inverse of the components of a vec3\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a vector to invert\r\n * @returns {vec3} out\r\n */\r\nexport function inverse(out, a) {\r\n out[0] = 1.0 / a[0];\r\n out[1] = 1.0 / a[1];\r\n out[2] = 1.0 / a[2];\r\n return out;\r\n}\r\n\r\n/**\r\n * Normalize a vec3\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a vector to normalize\r\n * @returns {vec3} out\r\n */\r\nexport function normalize(out, a) {\r\n let x = a[0];\r\n let y = a[1];\r\n let z = a[2];\r\n let len = x*x + y*y + z*z;\r\n if (len > 0) {\r\n //TODO: evaluate use of glm_invsqrt here?\r\n len = 1 / Math.sqrt(len);\r\n out[0] = a[0] * len;\r\n out[1] = a[1] * len;\r\n out[2] = a[2] * len;\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the dot product of two vec3's\r\n *\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @returns {Number} dot product of a and b\r\n */\r\nexport function dot(a, b) {\r\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\r\n}\r\n\r\n/**\r\n * Computes the cross product of two vec3's\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @returns {vec3} out\r\n */\r\nexport function cross(out, a, b) {\r\n let ax = a[0], ay = a[1], az = a[2];\r\n let bx = b[0], by = b[1], bz = b[2];\r\n\r\n out[0] = ay * bz - az * by;\r\n out[1] = az * bx - ax * bz;\r\n out[2] = ax * by - ay * bx;\r\n return out;\r\n}\r\n\r\n/**\r\n * Performs a linear interpolation between two vec3's\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @param {Number} t interpolation amount between the two inputs\r\n * @returns {vec3} out\r\n */\r\nexport function lerp(out, a, b, t) {\r\n let ax = a[0];\r\n let ay = a[1];\r\n let az = a[2];\r\n out[0] = ax + t * (b[0] - ax);\r\n out[1] = ay + t * (b[1] - ay);\r\n out[2] = az + t * (b[2] - az);\r\n return out;\r\n}\r\n\r\n/**\r\n * Performs a hermite interpolation with two control points\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @param {vec3} c the third operand\r\n * @param {vec3} d the fourth operand\r\n * @param {Number} t interpolation amount between the two inputs\r\n * @returns {vec3} out\r\n */\r\nexport function hermite(out, a, b, c, d, t) {\r\n let factorTimes2 = t * t;\r\n let factor1 = factorTimes2 * (2 * t - 3) + 1;\r\n let factor2 = factorTimes2 * (t - 2) + t;\r\n let factor3 = factorTimes2 * (t - 1);\r\n let factor4 = factorTimes2 * (3 - 2 * t);\r\n\r\n out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;\r\n out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;\r\n out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Performs a bezier interpolation with two control points\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the first operand\r\n * @param {vec3} b the second operand\r\n * @param {vec3} c the third operand\r\n * @param {vec3} d the fourth operand\r\n * @param {Number} t interpolation amount between the two inputs\r\n * @returns {vec3} out\r\n */\r\nexport function bezier(out, a, b, c, d, t) {\r\n let inverseFactor = 1 - t;\r\n let inverseFactorTimesTwo = inverseFactor * inverseFactor;\r\n let factorTimes2 = t * t;\r\n let factor1 = inverseFactorTimesTwo * inverseFactor;\r\n let factor2 = 3 * t * inverseFactorTimesTwo;\r\n let factor3 = 3 * factorTimes2 * inverseFactor;\r\n let factor4 = factorTimes2 * t;\r\n\r\n out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;\r\n out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;\r\n out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Generates a random vector with the given scale\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\r\n * @returns {vec3} out\r\n */\r\nexport function random(out, scale) {\r\n scale = scale || 1.0;\r\n\r\n let r = glMatrix.RANDOM() * 2.0 * Math.PI;\r\n let z = (glMatrix.RANDOM() * 2.0) - 1.0;\r\n let zScale = Math.sqrt(1.0-z*z) * scale;\r\n\r\n out[0] = Math.cos(r) * zScale;\r\n out[1] = Math.sin(r) * zScale;\r\n out[2] = z * scale;\r\n return out;\r\n}\r\n\r\n/**\r\n * Transforms the vec3 with a mat4.\r\n * 4th vector component is implicitly '1'\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the vector to transform\r\n * @param {mat4} m matrix to transform with\r\n * @returns {vec3} out\r\n */\r\nexport function transformMat4(out, a, m) {\r\n let x = a[0], y = a[1], z = a[2];\r\n let w = m[3] * x + m[7] * y + m[11] * z + m[15];\r\n w = w || 1.0;\r\n out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;\r\n out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;\r\n out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;\r\n return out;\r\n}\r\n\r\n/**\r\n * Transforms the vec3 with a mat3.\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the vector to transform\r\n * @param {mat3} m the 3x3 matrix to transform with\r\n * @returns {vec3} out\r\n */\r\nexport function transformMat3(out, a, m) {\r\n let x = a[0], y = a[1], z = a[2];\r\n out[0] = x * m[0] + y * m[3] + z * m[6];\r\n out[1] = x * m[1] + y * m[4] + z * m[7];\r\n out[2] = x * m[2] + y * m[5] + z * m[8];\r\n return out;\r\n}\r\n\r\n/**\r\n * Transforms the vec3 with a quat\r\n * Can also be used for dual quaternions. (Multiply it with the real part)\r\n *\r\n * @param {vec3} out the receiving vector\r\n * @param {vec3} a the vector to transform\r\n * @param {quat} q quaternion to transform with\r\n * @returns {vec3} out\r\n */\r\nexport function transformQuat(out, a, q) {\r\n // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed\r\n let qx = q[0], qy = q[1], qz = q[2], qw = q[3];\r\n let x = a[0], y = a[1], z = a[2];\r\n // var qvec = [qx, qy, qz];\r\n // var uv = vec3.cross([], qvec, a);\r\n let uvx = qy * z - qz * y,\r\n uvy = qz * x - qx * z,\r\n uvz = qx * y - qy * x;\r\n // var uuv = vec3.cross([], qvec, uv);\r\n let uuvx = qy * uvz - qz * uvy,\r\n uuvy = qz * uvx - qx * uvz,\r\n uuvz = qx * uvy - qy * uvx;\r\n // vec3.scale(uv, uv, 2 * w);\r\n let w2 = qw * 2;\r\n uvx *= w2;\r\n uvy *= w2;\r\n uvz *= w2;\r\n // vec3.scale(uuv, uuv, 2);\r\n uuvx *= 2;\r\n uuvy *= 2;\r\n uuvz *= 2;\r\n // return vec3.add(out, a, vec3.add(out, uv, uuv));\r\n out[0] = x + uvx + uuvx;\r\n out[1] = y + uvy + uuvy;\r\n out[2] = z + uvz + uuvz;\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotate a 3D vector around the x-axis\r\n * @param {vec3} out The receiving vec3\r\n * @param {vec3} a The vec3 point to rotate\r\n * @param {vec3} b The origin of the rotation\r\n * @param {Number} c The angle of rotation\r\n * @returns {vec3} out\r\n */\r\nexport function rotateX(out, a, b, c){\r\n let p = [], r=[];\r\n //Translate point to the origin\r\n p[0] = a[0] - b[0];\r\n p[1] = a[1] - b[1];\r\n p[2] = a[2] - b[2];\r\n\r\n //perform rotation\r\n r[0] = p[0];\r\n r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c);\r\n r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c);\r\n\r\n //translate to correct position\r\n out[0] = r[0] + b[0];\r\n out[1] = r[1] + b[1];\r\n out[2] = r[2] + b[2];\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotate a 3D vector around the y-axis\r\n * @param {vec3} out The receiving vec3\r\n * @param {vec3} a The vec3 point to rotate\r\n * @param {vec3} b The origin of the rotation\r\n * @param {Number} c The angle of rotation\r\n * @returns {vec3} out\r\n */\r\nexport function rotateY(out, a, b, c){\r\n let p = [], r=[];\r\n //Translate point to the origin\r\n p[0] = a[0] - b[0];\r\n p[1] = a[1] - b[1];\r\n p[2] = a[2] - b[2];\r\n\r\n //perform rotation\r\n r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c);\r\n r[1] = p[1];\r\n r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c);\r\n\r\n //translate to correct position\r\n out[0] = r[0] + b[0];\r\n out[1] = r[1] + b[1];\r\n out[2] = r[2] + b[2];\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Rotate a 3D vector around the z-axis\r\n * @param {vec3} out The receiving vec3\r\n * @param {vec3} a The vec3 point to rotate\r\n * @param {vec3} b The origin of the rotation\r\n * @param {Number} c The angle of rotation\r\n * @returns {vec3} out\r\n */\r\nexport function rotateZ(out, a, b, c){\r\n let p = [], r=[];\r\n //Translate point to the origin\r\n p[0] = a[0] - b[0];\r\n p[1] = a[1] - b[1];\r\n p[2] = a[2] - b[2];\r\n\r\n //perform rotation\r\n r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c);\r\n r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c);\r\n r[2] = p[2];\r\n\r\n //translate to correct position\r\n out[0] = r[0] + b[0];\r\n out[1] = r[1] + b[1];\r\n out[2] = r[2] + b[2];\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Get the angle between two 3D vectors\r\n * @param {vec3} a The first operand\r\n * @param {vec3} b The second operand\r\n * @returns {Number} The angle in radians\r\n */\r\nexport function angle(a, b) {\r\n let tempA = fromValues(a[0], a[1], a[2]);\r\n let tempB = fromValues(b[0], b[1], b[2]);\r\n\r\n normalize(tempA, tempA);\r\n normalize(tempB, tempB);\r\n\r\n let cosine = dot(tempA, tempB);\r\n\r\n if(cosine > 1.0) {\r\n return 0;\r\n }\r\n else if(cosine < -1.0) {\r\n return Math.PI;\r\n } else {\r\n return Math.acos(cosine);\r\n }\r\n}\r\n\r\n/**\r\n * Returns a string representation of a vector\r\n *\r\n * @param {vec3} a vector to represent as a string\r\n * @returns {String} string representation of the vector\r\n */\r\nexport function str(a) {\r\n return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';\r\n}\r\n\r\n/**\r\n * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)\r\n *\r\n * @param {vec3} a The first vector.\r\n * @param {vec3} b The second vector.\r\n * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n */\r\nexport function exactEquals(a, b) {\r\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];\r\n}\r\n\r\n/**\r\n * Returns whether or not the vectors have approximately the same elements in the same position.\r\n *\r\n * @param {vec3} a The first vector.\r\n * @param {vec3} b The second vector.\r\n * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n */\r\nexport function equals(a, b) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2];\r\n let b0 = b[0], b1 = b[1], b2 = b[2];\r\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)));\r\n}\r\n\r\n/**\r\n * Alias for {@link vec3.subtract}\r\n * @function\r\n */\r\nexport const sub = subtract;\r\n\r\n/**\r\n * Alias for {@link vec3.multiply}\r\n * @function\r\n */\r\nexport const mul = multiply;\r\n\r\n/**\r\n * Alias for {@link vec3.divide}\r\n * @function\r\n */\r\nexport const div = divide;\r\n\r\n/**\r\n * Alias for {@link vec3.distance}\r\n * @function\r\n */\r\nexport const dist = distance;\r\n\r\n/**\r\n * Alias for {@link vec3.squaredDistance}\r\n * @function\r\n */\r\nexport const sqrDist = squaredDistance;\r\n\r\n/**\r\n * Alias for {@link vec3.length}\r\n * @function\r\n */\r\nexport const len = length;\r\n\r\n/**\r\n * Alias for {@link vec3.squaredLength}\r\n * @function\r\n */\r\nexport const sqrLen = squaredLength;\r\n\r\n/**\r\n * Perform some operation over an array of vec3s.\r\n *\r\n * @param {Array} a the array of vectors to iterate over\r\n * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed\r\n * @param {Number} offset Number of elements to skip at the beginning of the array\r\n * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array\r\n * @param {Function} fn Function to call for each vector in the array\r\n * @param {Object} [arg] additional argument to pass to fn\r\n * @returns {Array} a\r\n * @function\r\n */\r\nexport const forEach = (function() {\r\n let vec = create();\r\n\r\n return function(a, stride, offset, count, fn, arg) {\r\n let i, l;\r\n if(!stride) {\r\n stride = 3;\r\n }\r\n\r\n if(!offset) {\r\n offset = 0;\r\n }\r\n\r\n if(count) {\r\n l = Math.min((count * stride) + offset, a.length);\r\n } else {\r\n l = a.length;\r\n }\r\n\r\n for(i = offset; i < l; i += stride) {\r\n vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];\r\n fn(vec, vec, arg);\r\n a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];\r\n }\r\n\r\n return a;\r\n };\r\n})();\r\n","/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. */\r\n\r\nimport * as glMatrix from \"./common.js\";\r\n\r\n/**\r\n * 4 Dimensional Vector\r\n * @module vec4\r\n */\r\n\r\n/**\r\n * Creates a new, empty vec4\r\n *\r\n * @returns {vec4} a new 4D vector\r\n */\r\nexport function create() {\r\n let out = new glMatrix.ARRAY_TYPE(4);\r\n out[0] = 0;\r\n out[1] = 0;\r\n out[2] = 0;\r\n out[3] = 0;\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a new vec4 initialized with values from an existing vector\r\n *\r\n * @param {vec4} a vector to clone\r\n * @returns {vec4} a new 4D vector\r\n */\r\nexport function clone(a) {\r\n let out = new glMatrix.ARRAY_TYPE(4);\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Creates a new vec4 initialized with the given values\r\n *\r\n * @param {Number} x X component\r\n * @param {Number} y Y component\r\n * @param {Number} z Z component\r\n * @param {Number} w W component\r\n * @returns {vec4} a new 4D vector\r\n */\r\nexport function fromValues(x, y, z, w) {\r\n let out = new glMatrix.ARRAY_TYPE(4);\r\n out[0] = x;\r\n out[1] = y;\r\n out[2] = z;\r\n out[3] = w;\r\n return out;\r\n}\r\n\r\n/**\r\n * Copy the values from one vec4 to another\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the source vector\r\n * @returns {vec4} out\r\n */\r\nexport function copy(out, a) {\r\n out[0] = a[0];\r\n out[1] = a[1];\r\n out[2] = a[2];\r\n out[3] = a[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Set the components of a vec4 to the given values\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {Number} x X component\r\n * @param {Number} y Y component\r\n * @param {Number} z Z component\r\n * @param {Number} w W component\r\n * @returns {vec4} out\r\n */\r\nexport function set(out, x, y, z, w) {\r\n out[0] = x;\r\n out[1] = y;\r\n out[2] = z;\r\n out[3] = w;\r\n return out;\r\n}\r\n\r\n/**\r\n * Adds two vec4's\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the first operand\r\n * @param {vec4} b the second operand\r\n * @returns {vec4} out\r\n */\r\nexport function add(out, a, b) {\r\n out[0] = a[0] + b[0];\r\n out[1] = a[1] + b[1];\r\n out[2] = a[2] + b[2];\r\n out[3] = a[3] + b[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Subtracts vector b from vector a\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the first operand\r\n * @param {vec4} b the second operand\r\n * @returns {vec4} out\r\n */\r\nexport function subtract(out, a, b) {\r\n out[0] = a[0] - b[0];\r\n out[1] = a[1] - b[1];\r\n out[2] = a[2] - b[2];\r\n out[3] = a[3] - b[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Multiplies two vec4's\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the first operand\r\n * @param {vec4} b the second operand\r\n * @returns {vec4} out\r\n */\r\nexport function multiply(out, a, b) {\r\n out[0] = a[0] * b[0];\r\n out[1] = a[1] * b[1];\r\n out[2] = a[2] * b[2];\r\n out[3] = a[3] * b[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Divides two vec4's\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the first operand\r\n * @param {vec4} b the second operand\r\n * @returns {vec4} out\r\n */\r\nexport function divide(out, a, b) {\r\n out[0] = a[0] / b[0];\r\n out[1] = a[1] / b[1];\r\n out[2] = a[2] / b[2];\r\n out[3] = a[3] / b[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Math.ceil the components of a vec4\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a vector to ceil\r\n * @returns {vec4} out\r\n */\r\nexport function ceil(out, a) {\r\n out[0] = Math.ceil(a[0]);\r\n out[1] = Math.ceil(a[1]);\r\n out[2] = Math.ceil(a[2]);\r\n out[3] = Math.ceil(a[3]);\r\n return out;\r\n}\r\n\r\n/**\r\n * Math.floor the components of a vec4\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a vector to floor\r\n * @returns {vec4} out\r\n */\r\nexport function floor(out, a) {\r\n out[0] = Math.floor(a[0]);\r\n out[1] = Math.floor(a[1]);\r\n out[2] = Math.floor(a[2]);\r\n out[3] = Math.floor(a[3]);\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns the minimum of two vec4's\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the first operand\r\n * @param {vec4} b the second operand\r\n * @returns {vec4} out\r\n */\r\nexport function min(out, a, b) {\r\n out[0] = Math.min(a[0], b[0]);\r\n out[1] = Math.min(a[1], b[1]);\r\n out[2] = Math.min(a[2], b[2]);\r\n out[3] = Math.min(a[3], b[3]);\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns the maximum of two vec4's\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the first operand\r\n * @param {vec4} b the second operand\r\n * @returns {vec4} out\r\n */\r\nexport function max(out, a, b) {\r\n out[0] = Math.max(a[0], b[0]);\r\n out[1] = Math.max(a[1], b[1]);\r\n out[2] = Math.max(a[2], b[2]);\r\n out[3] = Math.max(a[3], b[3]);\r\n return out;\r\n}\r\n\r\n/**\r\n * Math.round the components of a vec4\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a vector to round\r\n * @returns {vec4} out\r\n */\r\nexport function round(out, a) {\r\n out[0] = Math.round(a[0]);\r\n out[1] = Math.round(a[1]);\r\n out[2] = Math.round(a[2]);\r\n out[3] = Math.round(a[3]);\r\n return out;\r\n}\r\n\r\n/**\r\n * Scales a vec4 by a scalar number\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the vector to scale\r\n * @param {Number} b amount to scale the vector by\r\n * @returns {vec4} out\r\n */\r\nexport function scale(out, a, b) {\r\n out[0] = a[0] * b;\r\n out[1] = a[1] * b;\r\n out[2] = a[2] * b;\r\n out[3] = a[3] * b;\r\n return out;\r\n}\r\n\r\n/**\r\n * Adds two vec4's after scaling the second operand by a scalar value\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the first operand\r\n * @param {vec4} b the second operand\r\n * @param {Number} scale the amount to scale b by before adding\r\n * @returns {vec4} out\r\n */\r\nexport function scaleAndAdd(out, a, b, scale) {\r\n out[0] = a[0] + (b[0] * scale);\r\n out[1] = a[1] + (b[1] * scale);\r\n out[2] = a[2] + (b[2] * scale);\r\n out[3] = a[3] + (b[3] * scale);\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the euclidian distance between two vec4's\r\n *\r\n * @param {vec4} a the first operand\r\n * @param {vec4} b the second operand\r\n * @returns {Number} distance between a and b\r\n */\r\nexport function distance(a, b) {\r\n let x = b[0] - a[0];\r\n let y = b[1] - a[1];\r\n let z = b[2] - a[2];\r\n let w = b[3] - a[3];\r\n return Math.sqrt(x*x + y*y + z*z + w*w);\r\n}\r\n\r\n/**\r\n * Calculates the squared euclidian distance between two vec4's\r\n *\r\n * @param {vec4} a the first operand\r\n * @param {vec4} b the second operand\r\n * @returns {Number} squared distance between a and b\r\n */\r\nexport function squaredDistance(a, b) {\r\n let x = b[0] - a[0];\r\n let y = b[1] - a[1];\r\n let z = b[2] - a[2];\r\n let w = b[3] - a[3];\r\n return x*x + y*y + z*z + w*w;\r\n}\r\n\r\n/**\r\n * Calculates the length of a vec4\r\n *\r\n * @param {vec4} a vector to calculate length of\r\n * @returns {Number} length of a\r\n */\r\nexport function length(a) {\r\n let x = a[0];\r\n let y = a[1];\r\n let z = a[2];\r\n let w = a[3];\r\n return Math.sqrt(x*x + y*y + z*z + w*w);\r\n}\r\n\r\n/**\r\n * Calculates the squared length of a vec4\r\n *\r\n * @param {vec4} a vector to calculate squared length of\r\n * @returns {Number} squared length of a\r\n */\r\nexport function squaredLength(a) {\r\n let x = a[0];\r\n let y = a[1];\r\n let z = a[2];\r\n let w = a[3];\r\n return x*x + y*y + z*z + w*w;\r\n}\r\n\r\n/**\r\n * Negates the components of a vec4\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a vector to negate\r\n * @returns {vec4} out\r\n */\r\nexport function negate(out, a) {\r\n out[0] = -a[0];\r\n out[1] = -a[1];\r\n out[2] = -a[2];\r\n out[3] = -a[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns the inverse of the components of a vec4\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a vector to invert\r\n * @returns {vec4} out\r\n */\r\nexport function inverse(out, a) {\r\n out[0] = 1.0 / a[0];\r\n out[1] = 1.0 / a[1];\r\n out[2] = 1.0 / a[2];\r\n out[3] = 1.0 / a[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Normalize a vec4\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a vector to normalize\r\n * @returns {vec4} out\r\n */\r\nexport function normalize(out, a) {\r\n let x = a[0];\r\n let y = a[1];\r\n let z = a[2];\r\n let w = a[3];\r\n let len = x*x + y*y + z*z + w*w;\r\n if (len > 0) {\r\n len = 1 / Math.sqrt(len);\r\n out[0] = x * len;\r\n out[1] = y * len;\r\n out[2] = z * len;\r\n out[3] = w * len;\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Calculates the dot product of two vec4's\r\n *\r\n * @param {vec4} a the first operand\r\n * @param {vec4} b the second operand\r\n * @returns {Number} dot product of a and b\r\n */\r\nexport function dot(a, b) {\r\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];\r\n}\r\n\r\n/**\r\n * Performs a linear interpolation between two vec4's\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the first operand\r\n * @param {vec4} b the second operand\r\n * @param {Number} t interpolation amount between the two inputs\r\n * @returns {vec4} out\r\n */\r\nexport function lerp(out, a, b, t) {\r\n let ax = a[0];\r\n let ay = a[1];\r\n let az = a[2];\r\n let aw = a[3];\r\n out[0] = ax + t * (b[0] - ax);\r\n out[1] = ay + t * (b[1] - ay);\r\n out[2] = az + t * (b[2] - az);\r\n out[3] = aw + t * (b[3] - aw);\r\n return out;\r\n}\r\n\r\n/**\r\n * Generates a random vector with the given scale\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\r\n * @returns {vec4} out\r\n */\r\nexport function random(out, vectorScale) {\r\n vectorScale = vectorScale || 1.0;\r\n\r\n //TODO: This is a pretty awful way of doing this. Find something better.\r\n out[0] = glMatrix.RANDOM();\r\n out[1] = glMatrix.RANDOM();\r\n out[2] = glMatrix.RANDOM();\r\n out[3] = glMatrix.RANDOM();\r\n normalize(out, out);\r\n scale(out, out, vectorScale);\r\n return out;\r\n}\r\n\r\n/**\r\n * Transforms the vec4 with a mat4.\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the vector to transform\r\n * @param {mat4} m matrix to transform with\r\n * @returns {vec4} out\r\n */\r\nexport function transformMat4(out, a, m) {\r\n let x = a[0], y = a[1], z = a[2], w = a[3];\r\n out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;\r\n out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;\r\n out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;\r\n out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;\r\n return out;\r\n}\r\n\r\n/**\r\n * Transforms the vec4 with a quat\r\n *\r\n * @param {vec4} out the receiving vector\r\n * @param {vec4} a the vector to transform\r\n * @param {quat} q quaternion to transform with\r\n * @returns {vec4} out\r\n */\r\nexport function transformQuat(out, a, q) {\r\n let x = a[0], y = a[1], z = a[2];\r\n let qx = q[0], qy = q[1], qz = q[2], qw = q[3];\r\n\r\n // calculate quat * vec\r\n let ix = qw * x + qy * z - qz * y;\r\n let iy = qw * y + qz * x - qx * z;\r\n let iz = qw * z + qx * y - qy * x;\r\n let iw = -qx * x - qy * y - qz * z;\r\n\r\n // calculate result * inverse quat\r\n out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;\r\n out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;\r\n out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;\r\n out[3] = a[3];\r\n return out;\r\n}\r\n\r\n/**\r\n * Returns a string representation of a vector\r\n *\r\n * @param {vec4} a vector to represent as a string\r\n * @returns {String} string representation of the vector\r\n */\r\nexport function str(a) {\r\n return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\r\n}\r\n\r\n/**\r\n * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)\r\n *\r\n * @param {vec4} a The first vector.\r\n * @param {vec4} b The second vector.\r\n * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n */\r\nexport function exactEquals(a, b) {\r\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];\r\n}\r\n\r\n/**\r\n * Returns whether or not the vectors have approximately the same elements in the same position.\r\n *\r\n * @param {vec4} a The first vector.\r\n * @param {vec4} b The second vector.\r\n * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n */\r\nexport function equals(a, b) {\r\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\r\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\r\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\r\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));\r\n}\r\n\r\n/**\r\n * Alias for {@link vec4.subtract}\r\n * @function\r\n */\r\nexport const sub = subtract;\r\n\r\n/**\r\n * Alias for {@link vec4.multiply}\r\n * @function\r\n */\r\nexport const mul = multiply;\r\n\r\n/**\r\n * Alias for {@link vec4.divide}\r\n * @function\r\n */\r\nexport const div = divide;\r\n\r\n/**\r\n * Alias for {@link vec4.distance}\r\n * @function\r\n */\r\nexport const dist = distance;\r\n\r\n/**\r\n * Alias for {@link vec4.squaredDistance}\r\n * @function\r\n */\r\nexport const sqrDist = squaredDistance;\r\n\r\n/**\r\n * Alias for {@link vec4.length}\r\n * @function\r\n */\r\nexport const len = length;\r\n\r\n/**\r\n * Alias for {@link vec4.squaredLength}\r\n * @function\r\n */\r\nexport const sqrLen = squaredLength;\r\n\r\n/**\r\n * Perform some operation over an array of vec4s.\r\n *\r\n * @param {Array} a the array of vectors to iterate over\r\n * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed\r\n * @param {Number} offset Number of elements to skip at the beginning of the array\r\n * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array\r\n * @param {Function} fn Function to call for each vector in the array\r\n * @param {Object} [arg] additional argument to pass to fn\r\n * @returns {Array} a\r\n * @function\r\n */\r\nexport const forEach = (function() {\r\n let vec = create();\r\n\r\n return function(a, stride, offset, count, fn, arg) {\r\n let i, l;\r\n if(!stride) {\r\n stride = 4;\r\n }\r\n\r\n if(!offset) {\r\n offset = 0;\r\n }\r\n\r\n if(count) {\r\n l = Math.min((count * stride) + offset, a.length);\r\n } else {\r\n l = a.length;\r\n }\r\n\r\n for(i = offset; i < l; i += stride) {\r\n vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];\r\n fn(vec, vec, arg);\r\n a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];\r\n }\r\n\r\n return a;\r\n };\r\n})();\r\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nconst GL = WebGLRenderingContext; // For enums\n\nexport const CAP = {\n // Enable caps\n CULL_FACE: 0x001,\n BLEND: 0x002,\n DEPTH_TEST: 0x004,\n STENCIL_TEST: 0x008,\n COLOR_MASK: 0x010,\n DEPTH_MASK: 0x020,\n STENCIL_MASK: 0x040,\n};\n\nexport const MAT_STATE = {\n CAPS_RANGE: 0x000000FF,\n BLEND_SRC_SHIFT: 8,\n BLEND_SRC_RANGE: 0x00000F00,\n BLEND_DST_SHIFT: 12,\n BLEND_DST_RANGE: 0x0000F000,\n BLEND_FUNC_RANGE: 0x0000FF00,\n DEPTH_FUNC_SHIFT: 16,\n DEPTH_FUNC_RANGE: 0x000F0000,\n};\n\nexport const RENDER_ORDER = {\n // Render opaque objects first.\n OPAQUE: 0,\n\n // Render the sky after all opaque object to save fill rate.\n SKY: 1,\n\n // Render transparent objects next so that the opaqe objects show through.\n TRANSPARENT: 2,\n\n // Finally render purely additive effects like pointer rays so that they\n // can render without depth mask.\n ADDITIVE: 3,\n\n // Render order will be picked based on the material properties.\n DEFAULT: 4,\n};\n\nexport function stateToBlendFunc(state, mask, shift) {\n let value = (state & mask) >> shift;\n switch (value) {\n case 0:\n case 1:\n return value;\n default:\n return (value - 2) + GL.SRC_COLOR;\n }\n}\n\nexport class MaterialState {\n constructor() {\n this._state = CAP.CULL_FACE |\n CAP.DEPTH_TEST |\n CAP.COLOR_MASK |\n CAP.DEPTH_MASK;\n\n // Use a fairly commonly desired blend func as the default.\n this.blendFuncSrc = GL.SRC_ALPHA;\n this.blendFuncDst = GL.ONE_MINUS_SRC_ALPHA;\n\n this.depthFunc = GL.LESS;\n }\n\n get cullFace() {\n return !!(this._state & CAP.CULL_FACE);\n }\n set cullFace(value) {\n if (value) {\n this._state |= CAP.CULL_FACE;\n } else {\n this._state &= ~CAP.CULL_FACE;\n }\n }\n\n get blend() {\n return !!(this._state & CAP.BLEND);\n }\n set blend(value) {\n if (value) {\n this._state |= CAP.BLEND;\n } else {\n this._state &= ~CAP.BLEND;\n }\n }\n\n get depthTest() {\n return !!(this._state & CAP.DEPTH_TEST);\n }\n set depthTest(value) {\n if (value) {\n this._state |= CAP.DEPTH_TEST;\n } else {\n this._state &= ~CAP.DEPTH_TEST;\n }\n }\n\n get stencilTest() {\n return !!(this._state & CAP.STENCIL_TEST);\n }\n set stencilTest(value) {\n if (value) {\n this._state |= CAP.STENCIL_TEST;\n } else {\n this._state &= ~CAP.STENCIL_TEST;\n }\n }\n\n get colorMask() {\n return !!(this._state & CAP.COLOR_MASK);\n }\n set colorMask(value) {\n if (value) {\n this._state |= CAP.COLOR_MASK;\n } else {\n this._state &= ~CAP.COLOR_MASK;\n }\n }\n\n get depthMask() {\n return !!(this._state & CAP.DEPTH_MASK);\n }\n set depthMask(value) {\n if (value) {\n this._state |= CAP.DEPTH_MASK;\n } else {\n this._state &= ~CAP.DEPTH_MASK;\n }\n }\n\n get depthFunc() {\n return ((this._state & MAT_STATE.DEPTH_FUNC_RANGE) >> MAT_STATE.DEPTH_FUNC_SHIFT) + GL.NEVER;\n }\n set depthFunc(value) {\n value = value - GL.NEVER;\n this._state &= ~MAT_STATE.DEPTH_FUNC_RANGE;\n this._state |= (value << MAT_STATE.DEPTH_FUNC_SHIFT);\n }\n\n get stencilMask() {\n return !!(this._state & CAP.STENCIL_MASK);\n }\n set stencilMask(value) {\n if (value) {\n this._state |= CAP.STENCIL_MASK;\n } else {\n this._state &= ~CAP.STENCIL_MASK;\n }\n }\n\n get blendFuncSrc() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_SRC_RANGE, MAT_STATE.BLEND_SRC_SHIFT);\n }\n set blendFuncSrc(value) {\n switch (value) {\n case 0:\n case 1:\n break;\n default:\n value = (value - GL.SRC_COLOR) + 2;\n }\n this._state &= ~MAT_STATE.BLEND_SRC_RANGE;\n this._state |= (value << MAT_STATE.BLEND_SRC_SHIFT);\n }\n\n get blendFuncDst() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_DST_RANGE, MAT_STATE.BLEND_DST_SHIFT);\n }\n set blendFuncDst(value) {\n switch (value) {\n case 0:\n case 1:\n break;\n default:\n value = (value - GL.SRC_COLOR) + 2;\n }\n this._state &= ~MAT_STATE.BLEND_DST_RANGE;\n this._state |= (value << MAT_STATE.BLEND_DST_SHIFT);\n }\n}\n\nclass MaterialSampler {\n constructor(uniformName) {\n this._uniformName = uniformName;\n this._texture = null;\n }\n\n get texture() {\n return this._texture;\n }\n\n set texture(value) {\n this._texture = value;\n }\n}\n\nclass MaterialUniform {\n constructor(uniformName, defaultValue, length) {\n this._uniformName = uniformName;\n this._value = defaultValue;\n this._length = length;\n if (!this._length) {\n if (defaultValue instanceof Array) {\n this._length = defaultValue.length;\n } else {\n this._length = 1;\n }\n }\n }\n\n get value() {\n return this._value;\n }\n\n set value(value) {\n this._value = value;\n }\n}\n\nexport class Material {\n constructor() {\n this.state = new MaterialState;\n this.renderOrder = RENDER_ORDER.DEFAULT;\n this._samplers = [];\n this._uniforms = [];\n }\n\n defineSampler(uniformName) {\n let sampler = new MaterialSampler(uniformName);\n this._samplers.push(sampler);\n return sampler;\n }\n\n defineUniform(uniformName, defaultValue=null, length=0) {\n let uniform = new MaterialUniform(uniformName, defaultValue, length);\n this._uniforms.push(uniform);\n return uniform;\n }\n\n get materialName() {\n return null;\n }\n\n get vertexSource() {\n return null;\n }\n\n get fragmentSource() {\n return null;\n }\n\n getProgramDefines(renderPrimitive) {\n return {};\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Ray} from '../math/ray.js';\nimport {mat4, vec3, quat} from '../math/gl-matrix.js';\n\nconst DEFAULT_TRANSLATION = new Float32Array([0, 0, 0]);\nconst DEFAULT_ROTATION = new Float32Array([0, 0, 0, 1]);\nconst DEFAULT_SCALE = new Float32Array([1, 1, 1]);\n\nlet tmpRayMatrix = mat4.create();\n\nexport class Node {\n constructor() {\n this.name = null; // Only for debugging\n this.children = [];\n this.parent = null;\n this.visible = true;\n this.selectable = false;\n\n this._matrix = null;\n\n this._dirtyTRS = false;\n this._translation = null;\n this._rotation = null;\n this._scale = null;\n\n this._dirtyWorldMatrix = false;\n this._worldMatrix = null;\n\n this._activeFrameId = -1;\n this._hoverFrameId = -1;\n this._renderPrimitives = null;\n this._renderer = null;\n\n this._selectHandler = null;\n }\n\n _setRenderer(renderer) {\n if (this._renderer == renderer) {\n return;\n }\n\n if (this._renderer) {\n // Changing the renderer removes any previously attached renderPrimitives\n // from a different renderer.\n this.clearRenderPrimitives();\n }\n\n this._renderer = renderer;\n if (renderer) {\n this.onRendererChanged(renderer);\n\n for (let child of this.children) {\n child._setRenderer(renderer);\n }\n }\n }\n\n onRendererChanged(renderer) {\n // Override in other node types to respond to changes in the renderer.\n }\n\n // Create a clone of this node and all of it's children. Does not duplicate\n // RenderPrimitives, the cloned nodes will be treated as new instances of the\n // geometry.\n clone() {\n let cloneNode = new Node();\n cloneNode.name = this.name;\n cloneNode.visible = this.visible;\n cloneNode._renderer = this._renderer;\n\n cloneNode._dirtyTRS = this._dirtyTRS;\n\n if (this._translation) {\n cloneNode._translation = vec3.create();\n vec3.copy(cloneNode._translation, this._translation);\n }\n\n if (this._rotation) {\n cloneNode._rotation = quat.create();\n quat.copy(cloneNode._rotation, this._rotation);\n }\n\n if (this._scale) {\n cloneNode._scale = vec3.create();\n vec3.copy(cloneNode._scale, this._scale);\n }\n\n // Only copy the matrices if they're not already dirty.\n if (!cloneNode._dirtyTRS && this._matrix) {\n cloneNode._matrix = mat4.create();\n mat4.copy(cloneNode._matrix, this._matrix);\n }\n\n cloneNode._dirtyWorldMatrix = this._dirtyWorldMatrix;\n if (!cloneNode._dirtyWorldMatrix && this._worldMatrix) {\n cloneNode._worldMatrix = mat4.create();\n mat4.copy(cloneNode._worldMatrix, this._worldMatrix);\n }\n\n this.waitForComplete().then(() => {\n if (this._renderPrimitives) {\n for (let primitive of this._renderPrimitives) {\n cloneNode.addRenderPrimitive(primitive);\n }\n }\n\n for (let child of this.children) {\n cloneNode.addNode(child.clone());\n }\n });\n\n return cloneNode;\n }\n\n markActive(frameId) {\n if (this.visible && this._renderPrimitives) {\n this._activeFrameId = frameId;\n for (let primitive of this._renderPrimitives) {\n primitive.markActive(frameId);\n }\n }\n\n for (let child of this.children) {\n if (child.visible) {\n child.markActive(frameId);\n }\n }\n }\n\n addNode(value) {\n if (!value || value.parent == this) {\n return;\n }\n\n if (value.parent) {\n value.parent.removeNode(value);\n }\n value.parent = this;\n\n this.children.push(value);\n\n if (this._renderer) {\n value._setRenderer(this._renderer);\n }\n }\n\n removeNode(value) {\n let i = this.children.indexOf(value);\n if (i > -1) {\n this.children.splice(i, 1);\n value.parent = null;\n }\n }\n\n clearNodes() {\n for (let child of this.children) {\n child.parent = null;\n }\n this.children = [];\n }\n\n setMatrixDirty() {\n if (!this._dirtyWorldMatrix) {\n this._dirtyWorldMatrix = true;\n for (let child of this.children) {\n child.setMatrixDirty();\n }\n }\n }\n\n _updateLocalMatrix() {\n if (!this._matrix) {\n this._matrix = mat4.create();\n }\n\n if (this._dirtyTRS) {\n this._dirtyTRS = false;\n mat4.fromRotationTranslationScale(\n this._matrix,\n this._rotation || DEFAULT_ROTATION,\n this._translation || DEFAULT_TRANSLATION,\n this._scale || DEFAULT_SCALE);\n }\n\n return this._matrix;\n }\n\n set matrix(value) {\n if (value) {\n if (!this._matrix) {\n this._matrix = mat4.create();\n }\n mat4.copy(this._matrix, value);\n } else {\n this._matrix = null;\n }\n this.setMatrixDirty();\n this._dirtyTRS = false;\n this._translation = null;\n this._rotation = null;\n this._scale = null;\n }\n\n get matrix() {\n this.setMatrixDirty();\n\n return this._updateLocalMatrix();\n }\n\n get worldMatrix() {\n if (!this._worldMatrix) {\n this._dirtyWorldMatrix = true;\n this._worldMatrix = mat4.create();\n }\n\n if (this._dirtyWorldMatrix || this._dirtyTRS) {\n if (this.parent) {\n // TODO: Some optimizations that could be done here if the node matrix\n // is an identity matrix.\n mat4.mul(this._worldMatrix, this.parent.worldMatrix, this._updateLocalMatrix());\n } else {\n mat4.copy(this._worldMatrix, this._updateLocalMatrix());\n }\n this._dirtyWorldMatrix = false;\n }\n\n return this._worldMatrix;\n }\n\n // TODO: Decompose matrix when fetching these?\n set translation(value) {\n if (value != null) {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n }\n this._translation = value;\n }\n\n get translation() {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n if (!this._translation) {\n this._translation = vec3.clone(DEFAULT_TRANSLATION);\n }\n return this._translation;\n }\n\n set rotation(value) {\n if (value != null) {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n }\n this._rotation = value;\n }\n\n get rotation() {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n if (!this._rotation) {\n this._rotation = quat.clone(DEFAULT_ROTATION);\n }\n return this._rotation;\n }\n\n set scale(value) {\n if (value != null) {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n }\n this._scale = value;\n }\n\n get scale() {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n if (!this._scale) {\n this._scale = vec3.clone(DEFAULT_SCALE);\n }\n return this._scale;\n }\n\n waitForComplete() {\n let childPromises = [];\n for (let child of this.children) {\n childPromises.push(child.waitForComplete());\n }\n if (this._renderPrimitives) {\n for (let primitive of this._renderPrimitives) {\n childPromises.push(primitive.waitForComplete());\n }\n }\n return Promise.all(childPromises).then(() => this);\n }\n\n get renderPrimitives() {\n return this._renderPrimitives;\n }\n\n addRenderPrimitive(primitive) {\n if (!this._renderPrimitives) {\n this._renderPrimitives = [primitive];\n } else {\n this._renderPrimitives.push(primitive);\n }\n primitive._instances.push(this);\n }\n\n removeRenderPrimitive(primitive) {\n if (!this._renderPrimitives) {\n return;\n }\n\n let index = this._renderPrimitives._instances.indexOf(primitive);\n if (index > -1) {\n this._renderPrimitives._instances.splice(index, 1);\n\n index = primitive._instances.indexOf(this);\n if (index > -1) {\n primitive._instances.splice(index, 1);\n }\n\n if (!this._renderPrimitives.length) {\n this._renderPrimitives = null;\n }\n }\n }\n\n clearRenderPrimitives() {\n if (this._renderPrimitives) {\n for (let primitive of this._renderPrimitives) {\n let index = primitive._instances.indexOf(this);\n if (index > -1) {\n primitive._instances.splice(index, 1);\n }\n }\n this._renderPrimitives = null;\n }\n }\n\n _hitTestSelectableNode(ray) {\n if (this._renderPrimitives) {\n let localRay = null;\n for (let primitive of this._renderPrimitives) {\n if (primitive._min) {\n if (!localRay) {\n mat4.invert(tmpRayMatrix, this.worldMatrix);\n mat4.multiply(tmpRayMatrix, tmpRayMatrix, ray.transformMatrix);\n localRay = new Ray(tmpRayMatrix);\n }\n let intersection = localRay.intersectsAABB(primitive._min, primitive._max);\n if (intersection) {\n vec3.transformMat4(intersection, intersection, this.worldMatrix);\n return intersection;\n }\n }\n }\n }\n for (let child of this.children) {\n let intersection = child._hitTestSelectableNode(ray);\n if (intersection) {\n return intersection;\n }\n }\n return null;\n }\n\n hitTest(ray) {\n if (this.selectable && this.visible) {\n let intersection = this._hitTestSelectableNode(ray);\n\n if (intersection) {\n let origin = vec3.fromValues(ray.origin.x, ray.origin.y, ray.origin.z);\n return {\n node: this,\n intersection: intersection,\n distance: vec3.distance(origin, intersection),\n };\n }\n return null;\n }\n\n let result = null;\n for (let child of this.children) {\n let childResult = child.hitTest(ray);\n if (childResult) {\n if (!result || result.distance > childResult.distance) {\n result = childResult;\n }\n }\n }\n return result;\n }\n\n onSelect(value) {\n this._selectHandler = value;\n }\n\n get selectHandler() {\n return this._selectHandler;\n }\n\n // Called when a selectable node is selected.\n handleSelect() {\n if (this._selectHandler) {\n this._selectHandler();\n }\n }\n\n // Called when a selectable element is pointed at.\n onHoverStart() {\n\n }\n\n // Called when a selectable element is no longer pointed at.\n onHoverEnd() {\n\n }\n\n _update(timestamp, frameDelta) {\n this.onUpdate(timestamp, frameDelta);\n\n for (let child of this.children) {\n child._update(timestamp, frameDelta);\n }\n }\n\n // Called every frame so that the nodes can animate themselves\n onUpdate(timestamp, frameDelta) {\n\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {vec3} from '../math/gl-matrix.js';\n\nexport class PrimitiveAttribute {\n constructor(name, buffer, componentCount, componentType, stride, byteOffset) {\n this.name = name;\n this.buffer = buffer;\n this.componentCount = componentCount || 3;\n this.componentType = componentType || 5126; // gl.FLOAT;\n this.stride = stride || 0;\n this.byteOffset = byteOffset || 0;\n this.normalized = false;\n }\n}\n\nexport class Primitive {\n constructor(attributes, elementCount, mode) {\n this.attributes = attributes || [];\n this.elementCount = elementCount || 0;\n this.mode = mode || 4; // gl.TRIANGLES;\n this.indexBuffer = null;\n this.indexByteOffset = 0;\n this.indexType = 0;\n this._min = null;\n this._max = null;\n }\n\n setIndexBuffer(indexBuffer, byteOffset, indexType) {\n this.indexBuffer = indexBuffer;\n this.indexByteOffset = byteOffset || 0;\n this.indexType = indexType || 5123; // gl.UNSIGNED_SHORT;\n }\n\n setBounds(min, max) {\n this._min = vec3.clone(min);\n this._max = vec3.clone(max);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nexport class Program {\n constructor(gl, vertSrc, fragSrc, attribMap, defines) {\n this._gl = gl;\n this.program = gl.createProgram();\n this.attrib = null;\n this.uniform = null;\n this.defines = {};\n\n this._firstUse = true;\n this._nextUseCallbacks = [];\n\n let definesString = '';\n if (defines) {\n for (let define in defines) {\n this.defines[define] = defines[define];\n definesString += `#define ${define} ${defines[define]}\\n`;\n }\n }\n\n this._vertShader = gl.createShader(gl.VERTEX_SHADER);\n gl.attachShader(this.program, this._vertShader);\n gl.shaderSource(this._vertShader, definesString + vertSrc);\n gl.compileShader(this._vertShader);\n\n this._fragShader = gl.createShader(gl.FRAGMENT_SHADER);\n gl.attachShader(this.program, this._fragShader);\n gl.shaderSource(this._fragShader, definesString + fragSrc);\n gl.compileShader(this._fragShader);\n\n if (attribMap) {\n this.attrib = {};\n for (let attribName in attribMap) {\n gl.bindAttribLocation(this.program, attribMap[attribName], attribName);\n this.attrib[attribName] = attribMap[attribName];\n }\n }\n\n gl.linkProgram(this.program);\n }\n\n onNextUse(callback) {\n this._nextUseCallbacks.push(callback);\n }\n\n use() {\n let gl = this._gl;\n\n // If this is the first time the program has been used do all the error checking and\n // attrib/uniform querying needed.\n if (this._firstUse) {\n this._firstUse = false;\n if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {\n if (!gl.getShaderParameter(this._vertShader, gl.COMPILE_STATUS)) {\n console.error('Vertex shader compile error: ' + gl.getShaderInfoLog(this._vertShader));\n } else if (!gl.getShaderParameter(this._fragShader, gl.COMPILE_STATUS)) {\n console.error('Fragment shader compile error: ' + gl.getShaderInfoLog(this._fragShader));\n } else {\n console.error('Program link error: ' + gl.getProgramInfoLog(this.program));\n }\n gl.deleteProgram(this.program);\n this.program = null;\n } else {\n if (!this.attrib) {\n this.attrib = {};\n let attribCount = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES);\n for (let i = 0; i < attribCount; i++) {\n let attribInfo = gl.getActiveAttrib(this.program, i);\n this.attrib[attribInfo.name] = gl.getAttribLocation(this.program, attribInfo.name);\n }\n }\n\n this.uniform = {};\n let uniformCount = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS);\n let uniformName = '';\n for (let i = 0; i < uniformCount; i++) {\n let uniformInfo = gl.getActiveUniform(this.program, i);\n uniformName = uniformInfo.name.replace('[0]', '');\n this.uniform[uniformName] = gl.getUniformLocation(this.program, uniformName);\n }\n }\n gl.deleteShader(this._vertShader);\n gl.deleteShader(this._fragShader);\n }\n\n gl.useProgram(this.program);\n\n if (this._nextUseCallbacks.length) {\n for (let callback of this._nextUseCallbacks) {\n callback(this);\n }\n this._nextUseCallbacks = [];\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {CAP, MAT_STATE, RENDER_ORDER, stateToBlendFunc} from './material.js';\nimport {Node} from './node.js';\nimport {Program} from './program.js';\nimport {DataTexture, VideoTexture} from './texture.js';\nimport {mat4, vec3} from '../math/gl-matrix.js';\n\nexport const ATTRIB = {\n POSITION: 1,\n NORMAL: 2,\n TANGENT: 3,\n TEXCOORD_0: 4,\n TEXCOORD_1: 5,\n COLOR_0: 6,\n};\n\nexport const ATTRIB_MASK = {\n POSITION: 0x0001,\n NORMAL: 0x0002,\n TANGENT: 0x0004,\n TEXCOORD_0: 0x0008,\n TEXCOORD_1: 0x0010,\n COLOR_0: 0x0020,\n};\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst DEF_LIGHT_DIR = new Float32Array([-0.1, -1.0, -0.2]);\nconst DEF_LIGHT_COLOR = new Float32Array([3.0, 3.0, 3.0]);\n\nconst PRECISION_REGEX = new RegExp('precision (lowp|mediump|highp) float;');\n\nconst VERTEX_SHADER_SINGLE_ENTRY = `\nuniform mat4 PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX;\n\nvoid main() {\n gl_Position = vertex_main(PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX);\n}\n`;\n\nconst VERTEX_SHADER_MULTI_ENTRY = `\n#ERROR Multiview rendering is not implemented\nvoid main() {\n gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER_ENTRY = `\nvoid main() {\n gl_FragColor = fragment_main();\n}\n`;\n\nfunction isPowerOfTwo(n) {\n return (n & (n - 1)) === 0;\n}\n\n// Creates a WebGL context and initializes it with some common default state.\nexport function createWebGLContext(glAttribs) {\n glAttribs = glAttribs || {alpha: false};\n\n let webglCanvas = document.createElement('canvas');\n let contextTypes = glAttribs.webgl2 ? ['webgl2'] : ['webgl', 'experimental-webgl'];\n let context = null;\n\n for (let contextType of contextTypes) {\n context = webglCanvas.getContext(contextType, glAttribs);\n if (context) {\n break;\n }\n }\n\n if (!context) {\n let webglType = (glAttribs.webgl2 ? 'WebGL 2' : 'WebGL');\n console.error('This browser does not support ' + webglType + '.');\n return null;\n }\n\n return context;\n}\n\nexport class RenderView {\n constructor(projectionMatrix, viewMatrix, viewport = null, eye = 'left') {\n this.projectionMatrix = projectionMatrix;\n this.viewMatrix = viewMatrix;\n this.viewport = viewport;\n // If an eye isn't given the left eye is assumed.\n this._eye = eye;\n this._eyeIndex = (eye == 'left' ? 0 : 1);\n }\n\n get eye() {\n return this._eye;\n }\n\n set eye(value) {\n this._eye = value;\n this._eyeIndex = (value == 'left' ? 0 : 1);\n }\n\n get eyeIndex() {\n return this._eyeIndex;\n }\n}\n\nclass RenderBuffer {\n constructor(target, usage, buffer, length = 0) {\n this._target = target;\n this._usage = usage;\n this._length = length;\n if (buffer instanceof Promise) {\n this._buffer = null;\n this._promise = buffer.then((buffer) => {\n this._buffer = buffer;\n return this;\n });\n } else {\n this._buffer = buffer;\n this._promise = Promise.resolve(this);\n }\n }\n\n waitForComplete() {\n return this._promise;\n }\n}\n\nclass RenderPrimitiveAttribute {\n constructor(primitiveAttribute) {\n this._attrib_index = ATTRIB[primitiveAttribute.name];\n this._componentCount = primitiveAttribute.componentCount;\n this._componentType = primitiveAttribute.componentType;\n this._stride = primitiveAttribute.stride;\n this._byteOffset = primitiveAttribute.byteOffset;\n this._normalized = primitiveAttribute.normalized;\n }\n}\n\nclass RenderPrimitiveAttributeBuffer {\n constructor(buffer) {\n this._buffer = buffer;\n this._attributes = [];\n }\n}\n\nclass RenderPrimitive {\n constructor(primitive) {\n this._activeFrameId = 0;\n this._instances = [];\n this._material = null;\n\n this.setPrimitive(primitive);\n }\n\n setPrimitive(primitive) {\n this._mode = primitive.mode;\n this._elementCount = primitive.elementCount;\n this._promise = null;\n this._vao = null;\n this._complete = false;\n this._attributeBuffers = [];\n this._attributeMask = 0;\n\n for (let attribute of primitive.attributes) {\n this._attributeMask |= ATTRIB_MASK[attribute.name];\n let renderAttribute = new RenderPrimitiveAttribute(attribute);\n let foundBuffer = false;\n for (let attributeBuffer of this._attributeBuffers) {\n if (attributeBuffer._buffer == attribute.buffer) {\n attributeBuffer._attributes.push(renderAttribute);\n foundBuffer = true;\n break;\n }\n }\n if (!foundBuffer) {\n let attributeBuffer = new RenderPrimitiveAttributeBuffer(attribute.buffer);\n attributeBuffer._attributes.push(renderAttribute);\n this._attributeBuffers.push(attributeBuffer);\n }\n }\n\n this._indexBuffer = null;\n this._indexByteOffset = 0;\n this._indexType = 0;\n\n if (primitive.indexBuffer) {\n this._indexByteOffset = primitive.indexByteOffset;\n this._indexType = primitive.indexType;\n this._indexBuffer = primitive.indexBuffer;\n }\n\n if (primitive._min) {\n this._min = vec3.clone(primitive._min);\n this._max = vec3.clone(primitive._max);\n } else {\n this._min = null;\n this._max = null;\n }\n\n if (this._material != null) {\n this.waitForComplete(); // To flip the _complete flag.\n }\n }\n\n setRenderMaterial(material) {\n this._material = material;\n this._promise = null;\n this._complete = false;\n\n if (this._material != null) {\n this.waitForComplete(); // To flip the _complete flag.\n }\n }\n\n markActive(frameId) {\n if (this._complete && this._activeFrameId != frameId) {\n if (this._material) {\n if (!this._material.markActive(frameId)) {\n return;\n }\n }\n this._activeFrameId = frameId;\n }\n }\n\n get samplers() {\n return this._material._samplerDictionary;\n }\n\n get uniforms() {\n return this._material._uniform_dictionary;\n }\n\n waitForComplete() {\n if (!this._promise) {\n if (!this._material) {\n return Promise.reject('RenderPrimitive does not have a material');\n }\n\n let completionPromises = [];\n\n for (let attributeBuffer of this._attributeBuffers) {\n if (!attributeBuffer._buffer._buffer) {\n completionPromises.push(attributeBuffer._buffer._promise);\n }\n }\n\n if (this._indexBuffer && !this._indexBuffer._buffer) {\n completionPromises.push(this._indexBuffer._promise);\n }\n\n this._promise = Promise.all(completionPromises).then(() => {\n this._complete = true;\n return this;\n });\n }\n return this._promise;\n }\n}\n\nexport class RenderTexture {\n constructor(texture) {\n this._texture = texture;\n this._complete = false;\n this._activeFrameId = 0;\n this._activeCallback = null;\n }\n\n markActive(frameId) {\n if (this._activeCallback && this._activeFrameId != frameId) {\n this._activeFrameId = frameId;\n this._activeCallback(this);\n }\n }\n}\n\nconst inverseMatrix = mat4.create();\n\nfunction setCap(gl, glEnum, cap, prevState, state) {\n let change = (state & cap) - (prevState & cap);\n if (!change) {\n return;\n }\n\n if (change > 0) {\n gl.enable(glEnum);\n } else {\n gl.disable(glEnum);\n }\n}\n\nclass RenderMaterialSampler {\n constructor(renderer, materialSampler, index) {\n this._renderer = renderer;\n this._uniformName = materialSampler._uniformName;\n this._renderTexture = renderer._getRenderTexture(materialSampler._texture);\n this._index = index;\n }\n\n set texture(value) {\n this._renderTexture = this._renderer._getRenderTexture(value);\n }\n}\n\nclass RenderMaterialUniform {\n constructor(materialUniform) {\n this._uniformName = materialUniform._uniformName;\n this._uniform = null;\n this._length = materialUniform._length;\n if (materialUniform._value instanceof Array) {\n this._value = new Float32Array(materialUniform._value);\n } else {\n this._value = new Float32Array([materialUniform._value]);\n }\n }\n\n set value(value) {\n if (this._value.length == 1) {\n this._value[0] = value;\n } else {\n for (let i = 0; i < this._value.length; ++i) {\n this._value[i] = value[i];\n }\n }\n }\n}\n\nclass RenderMaterial {\n constructor(renderer, material, program) {\n this._program = program;\n this._state = material.state._state;\n this._activeFrameId = 0;\n this._completeForActiveFrame = false;\n\n this._samplerDictionary = {};\n this._samplers = [];\n for (let i = 0; i < material._samplers.length; ++i) {\n let renderSampler = new RenderMaterialSampler(renderer, material._samplers[i], i);\n this._samplers.push(renderSampler);\n this._samplerDictionary[renderSampler._uniformName] = renderSampler;\n }\n\n this._uniform_dictionary = {};\n this._uniforms = [];\n for (let uniform of material._uniforms) {\n let renderUniform = new RenderMaterialUniform(uniform);\n this._uniforms.push(renderUniform);\n this._uniform_dictionary[renderUniform._uniformName] = renderUniform;\n }\n\n this._firstBind = true;\n\n this._renderOrder = material.renderOrder;\n if (this._renderOrder == RENDER_ORDER.DEFAULT) {\n if (this._state & CAP.BLEND) {\n this._renderOrder = RENDER_ORDER.TRANSPARENT;\n } else {\n this._renderOrder = RENDER_ORDER.OPAQUE;\n }\n }\n }\n\n bind(gl) {\n // First time we do a binding, cache the uniform locations and remove\n // unused uniforms from the list.\n if (this._firstBind) {\n for (let i = 0; i < this._samplers.length;) {\n let sampler = this._samplers[i];\n if (!this._program.uniform[sampler._uniformName]) {\n this._samplers.splice(i, 1);\n continue;\n }\n ++i;\n }\n\n for (let i = 0; i < this._uniforms.length;) {\n let uniform = this._uniforms[i];\n uniform._uniform = this._program.uniform[uniform._uniformName];\n if (!uniform._uniform) {\n this._uniforms.splice(i, 1);\n continue;\n }\n ++i;\n }\n this._firstBind = false;\n }\n\n for (let sampler of this._samplers) {\n gl.activeTexture(gl.TEXTURE0 + sampler._index);\n if (sampler._renderTexture && sampler._renderTexture._complete) {\n gl.bindTexture(gl.TEXTURE_2D, sampler._renderTexture._texture);\n } else {\n gl.bindTexture(gl.TEXTURE_2D, null);\n }\n }\n\n for (let uniform of this._uniforms) {\n switch (uniform._length) {\n case 1: gl.uniform1fv(uniform._uniform, uniform._value); break;\n case 2: gl.uniform2fv(uniform._uniform, uniform._value); break;\n case 3: gl.uniform3fv(uniform._uniform, uniform._value); break;\n case 4: gl.uniform4fv(uniform._uniform, uniform._value); break;\n }\n }\n }\n\n markActive(frameId) {\n if (this._activeFrameId != frameId) {\n this._activeFrameId = frameId;\n this._completeForActiveFrame = true;\n for (let i = 0; i < this._samplers.length; ++i) {\n let sampler = this._samplers[i];\n if (sampler._renderTexture) {\n if (!sampler._renderTexture._complete) {\n this._completeForActiveFrame = false;\n break;\n }\n sampler._renderTexture.markActive(frameId);\n }\n }\n }\n return this._completeForActiveFrame;\n }\n\n // Material State fetchers\n get cullFace() {\n return !!(this._state & CAP.CULL_FACE);\n }\n get blend() {\n return !!(this._state & CAP.BLEND);\n }\n get depthTest() {\n return !!(this._state & CAP.DEPTH_TEST);\n }\n get stencilTest() {\n return !!(this._state & CAP.STENCIL_TEST);\n }\n get colorMask() {\n return !!(this._state & CAP.COLOR_MASK);\n }\n get depthMask() {\n return !!(this._state & CAP.DEPTH_MASK);\n }\n get stencilMask() {\n return !!(this._state & CAP.STENCIL_MASK);\n }\n get depthFunc() {\n return ((this._state & MAT_STATE.DEPTH_FUNC_RANGE) >> MAT_STATE.DEPTH_FUNC_SHIFT) + GL.NEVER;\n }\n get blendFuncSrc() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_SRC_RANGE, MAT_STATE.BLEND_SRC_SHIFT);\n }\n get blendFuncDst() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_DST_RANGE, MAT_STATE.BLEND_DST_SHIFT);\n }\n\n // Only really for use from the renderer\n _capsDiff(otherState) {\n return (otherState & MAT_STATE.CAPS_RANGE) ^ (this._state & MAT_STATE.CAPS_RANGE);\n }\n\n _blendDiff(otherState) {\n if (!(this._state & CAP.BLEND)) {\n return 0;\n }\n return (otherState & MAT_STATE.BLEND_FUNC_RANGE) ^ (this._state & MAT_STATE.BLEND_FUNC_RANGE);\n }\n\n _depthFuncDiff(otherState) {\n if (!(this._state & CAP.DEPTH_TEST)) {\n return 0;\n }\n return (otherState & MAT_STATE.DEPTH_FUNC_RANGE) ^ (this._state & MAT_STATE.DEPTH_FUNC_RANGE);\n }\n}\n\nexport class Renderer {\n constructor(gl) {\n this._gl = gl || createWebGLContext();\n this._frameId = 0;\n this._programCache = {};\n this._textureCache = {};\n this._renderPrimitives = Array(RENDER_ORDER.DEFAULT);\n this._cameraPositions = [];\n\n this._vaoExt = gl.getExtension('OES_vertex_array_object');\n\n let fragHighPrecision = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);\n this._defaultFragPrecision = fragHighPrecision.precision > 0 ? 'highp' : 'mediump';\n\n this._depthMaskNeedsReset = false;\n this._colorMaskNeedsReset = false;\n\n this._globalLightColor = vec3.clone(DEF_LIGHT_COLOR);\n this._globalLightDir = vec3.clone(DEF_LIGHT_DIR);\n }\n\n get gl() {\n return this._gl;\n }\n\n set globalLightColor(value) {\n vec3.copy(this._globalLightColor, value);\n }\n\n get globalLightColor() {\n return vec3.clone(this._globalLightColor);\n }\n\n set globalLightDir(value) {\n vec3.copy(this._globalLightDir, value);\n }\n\n get globalLightDir() {\n return vec3.clone(this._globalLightDir);\n }\n\n createRenderBuffer(target, data, usage = GL.STATIC_DRAW) {\n let gl = this._gl;\n let glBuffer = gl.createBuffer();\n\n if (data instanceof Promise) {\n let renderBuffer = new RenderBuffer(target, usage, data.then((data) => {\n gl.bindBuffer(target, glBuffer);\n gl.bufferData(target, data, usage);\n renderBuffer._length = data.byteLength;\n return glBuffer;\n }));\n return renderBuffer;\n } else {\n gl.bindBuffer(target, glBuffer);\n gl.bufferData(target, data, usage);\n return new RenderBuffer(target, usage, glBuffer, data.byteLength);\n }\n }\n\n updateRenderBuffer(buffer, data, offset = 0) {\n if (buffer._buffer) {\n let gl = this._gl;\n gl.bindBuffer(buffer._target, buffer._buffer);\n if (offset == 0 && buffer._length == data.byteLength) {\n gl.bufferData(buffer._target, data, buffer._usage);\n } else {\n gl.bufferSubData(buffer._target, offset, data);\n }\n } else {\n buffer.waitForComplete().then((buffer) => {\n this.updateRenderBuffer(buffer, data, offset);\n });\n }\n }\n\n createRenderPrimitive(primitive, material) {\n let renderPrimitive = new RenderPrimitive(primitive);\n\n let program = this._getMaterialProgram(material, renderPrimitive);\n let renderMaterial = new RenderMaterial(this, material, program);\n renderPrimitive.setRenderMaterial(renderMaterial);\n\n if (!this._renderPrimitives[renderMaterial._renderOrder]) {\n this._renderPrimitives[renderMaterial._renderOrder] = [];\n }\n\n this._renderPrimitives[renderMaterial._renderOrder].push(renderPrimitive);\n\n return renderPrimitive;\n }\n\n createMesh(primitive, material) {\n let meshNode = new Node();\n meshNode.addRenderPrimitive(this.createRenderPrimitive(primitive, material));\n return meshNode;\n }\n\n drawViews(views, rootNode) {\n if (!rootNode) {\n return;\n }\n\n let gl = this._gl;\n this._frameId++;\n\n rootNode.markActive(this._frameId);\n\n // If there's only one view then flip the algorithm a bit so that we're only\n // setting the viewport once.\n if (views.length == 1 && views[0].viewport) {\n let vp = views[0].viewport;\n this._gl.viewport(vp.x, vp.y, vp.width, vp.height);\n }\n\n // Get the positions of the 'camera' for each view matrix.\n for (let i = 0; i < views.length; ++i) {\n mat4.invert(inverseMatrix, views[i].viewMatrix);\n\n if (this._cameraPositions.length <= i) {\n this._cameraPositions.push(vec3.create());\n }\n let cameraPosition = this._cameraPositions[i];\n vec3.set(cameraPosition, 0, 0, 0);\n vec3.transformMat4(cameraPosition, cameraPosition, inverseMatrix);\n }\n\n // Draw each set of render primitives in order\n for (let renderPrimitives of this._renderPrimitives) {\n if (renderPrimitives && renderPrimitives.length) {\n this._drawRenderPrimitiveSet(views, renderPrimitives);\n }\n }\n\n if (this._vaoExt) {\n this._vaoExt.bindVertexArrayOES(null);\n }\n\n if (this._depthMaskNeedsReset) {\n gl.depthMask(true);\n }\n if (this._colorMaskNeedsReset) {\n gl.colorMask(true, true, true, true);\n }\n }\n\n _drawRenderPrimitiveSet(views, renderPrimitives) {\n let gl = this._gl;\n let program = null;\n let material = null;\n let attribMask = 0;\n\n // Loop through every primitive known to the renderer.\n for (let primitive of renderPrimitives) {\n // Skip over those that haven't been marked as active for this frame.\n if (primitive._activeFrameId != this._frameId) {\n continue;\n }\n\n // Bind the primitive material's program if it's different than the one we\n // were using for the previous primitive.\n // TODO: The ording of this could be more efficient.\n if (program != primitive._material._program) {\n program = primitive._material._program;\n program.use();\n\n if (program.uniform.LIGHT_DIRECTION) {\n gl.uniform3fv(program.uniform.LIGHT_DIRECTION, this._globalLightDir);\n }\n\n if (program.uniform.LIGHT_COLOR) {\n gl.uniform3fv(program.uniform.LIGHT_COLOR, this._globalLightColor);\n }\n\n if (views.length == 1) {\n gl.uniformMatrix4fv(program.uniform.PROJECTION_MATRIX, false, views[0].projectionMatrix);\n gl.uniformMatrix4fv(program.uniform.VIEW_MATRIX, false, views[0].viewMatrix);\n gl.uniform3fv(program.uniform.CAMERA_POSITION, this._cameraPositions[0]);\n gl.uniform1i(program.uniform.EYE_INDEX, views[0].eyeIndex);\n }\n }\n\n if (material != primitive._material) {\n this._bindMaterialState(primitive._material, material);\n primitive._material.bind(gl, program, material);\n material = primitive._material;\n }\n\n if (this._vaoExt) {\n if (primitive._vao) {\n this._vaoExt.bindVertexArrayOES(primitive._vao);\n } else {\n primitive._vao = this._vaoExt.createVertexArrayOES();\n this._vaoExt.bindVertexArrayOES(primitive._vao);\n this._bindPrimitive(primitive);\n }\n } else {\n this._bindPrimitive(primitive, attribMask);\n attribMask = primitive._attributeMask;\n }\n\n for (let i = 0; i < views.length; ++i) {\n let view = views[i];\n if (views.length > 1) {\n if (view.viewport) {\n let vp = view.viewport;\n gl.viewport(vp.x, vp.y, vp.width, vp.height);\n }\n gl.uniformMatrix4fv(program.uniform.PROJECTION_MATRIX, false, view.projectionMatrix);\n gl.uniformMatrix4fv(program.uniform.VIEW_MATRIX, false, view.viewMatrix);\n gl.uniform3fv(program.uniform.CAMERA_POSITION, this._cameraPositions[i]);\n gl.uniform1i(program.uniform.EYE_INDEX, view.eyeIndex);\n }\n\n for (let instance of primitive._instances) {\n if (instance._activeFrameId != this._frameId) {\n continue;\n }\n\n gl.uniformMatrix4fv(program.uniform.MODEL_MATRIX, false, instance.worldMatrix);\n\n if (primitive._indexBuffer) {\n gl.drawElements(primitive._mode, primitive._elementCount,\n primitive._indexType, primitive._indexByteOffset);\n } else {\n gl.drawArrays(primitive._mode, 0, primitive._elementCount);\n }\n }\n }\n }\n }\n\n _getRenderTexture(texture) {\n if (!texture) {\n return null;\n }\n\n let key = texture.textureKey;\n if (!key) {\n throw new Error('Texure does not have a valid key');\n }\n\n if (key in this._textureCache) {\n return this._textureCache[key];\n } else {\n let gl = this._gl;\n let textureHandle = gl.createTexture();\n\n let renderTexture = new RenderTexture(textureHandle);\n this._textureCache[key] = renderTexture;\n\n if (texture instanceof DataTexture) {\n gl.bindTexture(gl.TEXTURE_2D, textureHandle);\n gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.width, texture.height,\n 0, texture.format, texture._type, texture._data);\n this._setSamplerParameters(texture);\n renderTexture._complete = true;\n } else {\n texture.waitForComplete().then(() => {\n gl.bindTexture(gl.TEXTURE_2D, textureHandle);\n gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.format, gl.UNSIGNED_BYTE, texture.source);\n this._setSamplerParameters(texture);\n renderTexture._complete = true;\n\n if (texture instanceof VideoTexture) {\n // Once the video starts playing, set a callback to update it's\n // contents each frame.\n texture._video.addEventListener('playing', () => {\n renderTexture._activeCallback = () => {\n if (!texture._video.paused && !texture._video.waiting) {\n gl.bindTexture(gl.TEXTURE_2D, textureHandle);\n gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.format, gl.UNSIGNED_BYTE, texture.source);\n }\n };\n });\n }\n });\n }\n\n return renderTexture;\n }\n }\n\n _setSamplerParameters(texture) {\n let gl = this._gl;\n\n let sampler = texture.sampler;\n let powerOfTwo = isPowerOfTwo(texture.width) && isPowerOfTwo(texture.height);\n let mipmap = powerOfTwo && texture.mipmap;\n if (mipmap) {\n gl.generateMipmap(gl.TEXTURE_2D);\n }\n\n let minFilter = sampler.minFilter || (mipmap ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);\n let wrapS = sampler.wrapS || (powerOfTwo ? gl.REPEAT : gl.CLAMP_TO_EDGE);\n let wrapT = sampler.wrapT || (powerOfTwo ? gl.REPEAT : gl.CLAMP_TO_EDGE);\n\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, sampler.magFilter || gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);\n }\n\n _getProgramKey(name, defines) {\n let key = `${name}:`;\n\n for (let define in defines) {\n key += `${define}=${defines[define]},`;\n }\n\n return key;\n }\n\n _getMaterialProgram(material, renderPrimitive) {\n let materialName = material.materialName;\n let vertexSource = material.vertexSource;\n let fragmentSource = material.fragmentSource;\n\n // These should always be defined for every material\n if (materialName == null) {\n throw new Error('Material does not have a name');\n }\n if (vertexSource == null) {\n throw new Error(`Material \"${materialName}\" does not have a vertex source`);\n }\n if (fragmentSource == null) {\n throw new Error(`Material \"${materialName}\" does not have a fragment source`);\n }\n\n let defines = material.getProgramDefines(renderPrimitive);\n let key = this._getProgramKey(materialName, defines);\n\n if (key in this._programCache) {\n return this._programCache[key];\n } else {\n let multiview = false; // Handle this dynamically later\n let fullVertexSource = vertexSource;\n fullVertexSource += multiview ? VERTEX_SHADER_MULTI_ENTRY :\n VERTEX_SHADER_SINGLE_ENTRY;\n\n let precisionMatch = fragmentSource.match(PRECISION_REGEX);\n let fragPrecisionHeader = precisionMatch ? '' : `precision ${this._defaultFragPrecision} float;\\n`;\n\n let fullFragmentSource = fragPrecisionHeader + fragmentSource;\n fullFragmentSource += FRAGMENT_SHADER_ENTRY;\n\n let program = new Program(this._gl, fullVertexSource, fullFragmentSource, ATTRIB, defines);\n this._programCache[key] = program;\n\n program.onNextUse((program) => {\n // Bind the samplers to the right texture index. This is constant for\n // the lifetime of the program.\n for (let i = 0; i < material._samplers.length; ++i) {\n let sampler = material._samplers[i];\n let uniform = program.uniform[sampler._uniformName];\n if (uniform) {\n this._gl.uniform1i(uniform, i);\n }\n }\n });\n\n return program;\n }\n }\n\n _bindPrimitive(primitive, attribMask) {\n let gl = this._gl;\n\n // If the active attributes have changed then update the active set.\n if (attribMask != primitive._attributeMask) {\n for (let attrib in ATTRIB) {\n if (primitive._attributeMask & ATTRIB_MASK[attrib]) {\n gl.enableVertexAttribArray(ATTRIB[attrib]);\n } else {\n gl.disableVertexAttribArray(ATTRIB[attrib]);\n }\n }\n }\n\n // Bind the primitive attributes and indices.\n for (let attributeBuffer of primitive._attributeBuffers) {\n gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer._buffer._buffer);\n for (let attrib of attributeBuffer._attributes) {\n gl.vertexAttribPointer(\n attrib._attrib_index, attrib._componentCount, attrib._componentType,\n attrib._normalized, attrib._stride, attrib._byteOffset);\n }\n }\n\n if (primitive._indexBuffer) {\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, primitive._indexBuffer._buffer);\n } else {\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n }\n }\n\n _bindMaterialState(material, prevMaterial = null) {\n let gl = this._gl;\n\n let state = material._state;\n let prevState = prevMaterial ? prevMaterial._state : ~state;\n\n // Return early if both materials use identical state\n if (state == prevState) {\n return;\n }\n\n // Any caps bits changed?\n if (material._capsDiff(prevState)) {\n setCap(gl, gl.CULL_FACE, CAP.CULL_FACE, prevState, state);\n setCap(gl, gl.BLEND, CAP.BLEND, prevState, state);\n setCap(gl, gl.DEPTH_TEST, CAP.DEPTH_TEST, prevState, state);\n setCap(gl, gl.STENCIL_TEST, CAP.STENCIL_TEST, prevState, state);\n\n let colorMaskChange = (state & CAP.COLOR_MASK) - (prevState & CAP.COLOR_MASK);\n if (colorMaskChange) {\n let mask = colorMaskChange > 1;\n this._colorMaskNeedsReset = !mask;\n gl.colorMask(mask, mask, mask, mask);\n }\n\n let depthMaskChange = (state & CAP.DEPTH_MASK) - (prevState & CAP.DEPTH_MASK);\n if (depthMaskChange) {\n this._depthMaskNeedsReset = !(depthMaskChange > 1);\n gl.depthMask(depthMaskChange > 1);\n }\n\n let stencilMaskChange = (state & CAP.STENCIL_MASK) - (prevState & CAP.STENCIL_MASK);\n if (stencilMaskChange) {\n gl.stencilMask(stencilMaskChange > 1);\n }\n }\n\n // Blending enabled and blend func changed?\n if (material._blendDiff(prevState)) {\n gl.blendFunc(material.blendFuncSrc, material.blendFuncDst);\n }\n\n // Depth testing enabled and depth func changed?\n if (material._depthFuncDiff(prevState)) {\n gl.depthFunc(material.depthFunc);\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nconst GL = WebGLRenderingContext; // For enums\n\nexport class TextureSampler {\n constructor() {\n this.minFilter = null;\n this.magFilter = null;\n this.wrapS = null;\n this.wrapT = null;\n }\n}\n\nexport class Texture {\n constructor() {\n this.sampler = new TextureSampler();\n this.mipmap = true;\n // TODO: Anisotropy\n }\n\n get format() {\n return GL.RGBA;\n }\n\n get width() {\n return 0;\n }\n\n get height() {\n return 0;\n }\n\n get textureKey() {\n return null;\n }\n}\n\nexport class ImageTexture extends Texture {\n constructor(img) {\n super();\n\n this._img = img;\n this._imgBitmap = null;\n\n if (img.src && img.complete) {\n if (img.naturalWidth) {\n this._promise = this._finishImage();\n } else {\n this._promise = Promise.reject('Image provided had failed to load.');\n }\n } else {\n this._promise = new Promise((resolve, reject) => {\n img.addEventListener('load', () => resolve(this._finishImage()));\n img.addEventListener('error', reject);\n });\n }\n }\n\n _finishImage() {\n if (window.createImageBitmap) {\n return window.createImageBitmap(this._img).then((imgBitmap) => {\n this._imgBitmap = imgBitmap;\n return Promise.resolve(this);\n });\n }\n return Promise.resolve(this);\n }\n\n get format() {\n // TODO: Can be RGB in some cases.\n return GL.RGBA;\n }\n\n get width() {\n return this._img.width;\n }\n\n get height() {\n return this._img.height;\n }\n\n waitForComplete() {\n return this._promise;\n }\n\n get textureKey() {\n return this._img.src;\n }\n\n get source() {\n return this._imgBitmap || this._img;\n }\n}\n\nexport class UrlTexture extends ImageTexture {\n constructor(url) {\n let img = new Image();\n super(img);\n img.src = url;\n }\n}\n\nexport class BlobTexture extends ImageTexture {\n constructor(blob) {\n let img = new Image();\n super(img);\n img.src = window.URL.createObjectURL(blob);\n }\n}\n\nexport class VideoTexture extends Texture {\n constructor(video) {\n super();\n\n this._video = video;\n\n if (video.readyState >= 2) {\n this._promise = Promise.resolve(this);\n } else if (video.error) {\n this._promise = Promise.reject(video.error);\n } else {\n this._promise = new Promise((resolve, reject) => {\n video.addEventListener('loadeddata', () => resolve(this));\n video.addEventListener('error', reject);\n });\n }\n }\n\n get format() {\n // TODO: Can be RGB in some cases.\n return GL.RGBA;\n }\n\n get width() {\n return this._video.videoWidth;\n }\n\n get height() {\n return this._video.videoHeight;\n }\n\n waitForComplete() {\n return this._promise;\n }\n\n get textureKey() {\n return this._video.src;\n }\n\n get source() {\n return this._video;\n }\n}\n\nlet nextDataTextureIndex = 0;\n\nexport class DataTexture extends Texture {\n constructor(data, width, height, format = GL.RGBA, type = GL.UNSIGNED_BYTE) {\n super();\n\n this._data = data;\n this._width = width;\n this._height = height;\n this._format = format;\n this._type = type;\n this._key = `DATA_${nextDataTextureIndex}`;\n nextDataTextureIndex++;\n }\n\n get format() {\n return this._format;\n }\n\n get width() {\n return this._width;\n }\n\n get height() {\n return this._height;\n }\n\n get textureKey() {\n return this._key;\n }\n}\n\nexport class ColorTexture extends DataTexture {\n constructor(r, g, b, a) {\n let colorData = new Uint8Array([r*255.0, g*255.0, b*255.0, a*255.0]);\n super(colorData, 1, 1);\n\n this.mipmap = false;\n this._key = `COLOR_${colorData[0]}_${colorData[1]}_${colorData[2]}_${colorData[3]}`;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nexport {Node} from './core/node.js';\nexport {Renderer, createWebGLContext} from './core/renderer.js';\nexport {UrlTexture} from './core/texture.js';\n\nexport {PrimitiveStream} from './geometry/primitive-stream.js';\nexport {BoxBuilder} from './geometry/box-builder.js';\n\nexport {PbrMaterial} from './materials/pbr.js';\n\nexport {mat4, mat3, vec3, vec4, quat} from './math/gl-matrix.js';\n\nexport {BoundsRenderer} from './nodes/bounds-renderer.js';\nexport {ButtonNode} from './nodes/button.js';\nexport {DropShadowNode} from './nodes/drop-shadow.js';\nexport {CubeSeaNode} from './nodes/cube-sea.js';\nexport {Gltf2Node} from './nodes/gltf2.js';\nexport {SkyboxNode} from './nodes/skybox.js';\nexport {VideoNode} from './nodes/video.js';\n\nexport {WebXRView, Scene} from './scenes/scene.js';\n\nexport {FallbackHelper} from './util/fallback-helper.js';\nexport {QueryArgs} from './util/query-args.js';\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {GeometryBuilderBase} from './primitive-stream.js';\n\nexport class BoxBuilder extends GeometryBuilderBase {\n pushBox(min, max) {\n let stream = this.primitiveStream;\n\n let w = max[0] - min[0];\n let h = max[1] - min[1];\n let d = max[2] - min[2];\n\n let wh = w * 0.5;\n let hh = h * 0.5;\n let dh = d * 0.5;\n\n let cx = min[0] + wh;\n let cy = min[1] + hh;\n let cz = min[2] + dh;\n\n stream.startGeometry();\n\n // Bottom\n let idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+1, idx+2);\n stream.pushTriangle(idx, idx+2, idx+3);\n\n // X Y Z U V NX NY NZ\n stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, 0.0, -1.0, 0.0);\n stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 0.0, -1.0, 0.0);\n stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 1.0, 0.0, 0.0, -1.0, 0.0);\n stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 0.0, 0.0, 0.0, -1.0, 0.0);\n\n // Top\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+2, idx+1);\n stream.pushTriangle(idx, idx+3, idx+2);\n\n stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, 0.0, 1.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 0.0, 1.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 1.0, 1.0, 0.0, 1.0, 0.0);\n stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 0.0, 1.0, 0.0, 1.0, 0.0);\n\n // Left\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+2, idx+1);\n stream.pushTriangle(idx, idx+3, idx+2);\n\n stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, -1.0, 0.0, 0.0);\n stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, -1.0, 0.0, 0.0);\n stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 1.0, 0.0, -1.0, 0.0, 0.0);\n stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 1.0, 1.0, -1.0, 0.0, 0.0);\n\n // Right\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+1, idx+2);\n stream.pushTriangle(idx, idx+2, idx+3);\n\n stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 1.0, 0.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 1.0, 0.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 0.0, 0.0, 1.0, 0.0, 0.0);\n stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 0.0, 1.0, 1.0, 0.0, 0.0);\n\n // Back\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+2, idx+1);\n stream.pushTriangle(idx, idx+3, idx+2);\n\n stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 0.0, 0.0, -1.0);\n stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, 0.0, 0.0, -1.0);\n stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, 0.0, 0.0, -1.0);\n stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 0.0, 0.0, -1.0);\n\n // Front\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+1, idx+2);\n stream.pushTriangle(idx, idx+2, idx+3);\n\n stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 0.0, 1.0, 0.0, 0.0, 1.0);\n stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 1.0, 1.0, 0.0, 0.0, 1.0);\n stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 1.0, 0.0, 0.0, 0.0, 1.0);\n stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 0.0, 0.0, 0.0, 0.0, 1.0);\n\n stream.endGeometry();\n }\n\n pushCube(center = [0, 0, 0], size = 1.0) {\n let hs = size * 0.5;\n this.pushBox([center[0] - hs, center[1] - hs, center[2] - hs],\n [center[0] + hs, center[1] + hs, center[2] + hs]);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {mat3, vec3} from '../math/gl-matrix.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst tempVec3 = vec3.create();\n\nexport class PrimitiveStream {\n constructor(options) {\n this._vertices = [];\n this._indices = [];\n\n this._geometryStarted = false;\n\n this._vertexOffset = 0;\n this._vertexIndex = 0;\n this._highIndex = 0;\n\n this._flipWinding = false;\n this._invertNormals = false;\n this._transform = null;\n this._normalTransform = null;\n this._min = null;\n this._max = null;\n }\n\n set flipWinding(value) {\n if (this._geometryStarted) {\n throw new Error(`Cannot change flipWinding before ending the current geometry.`);\n }\n this._flipWinding = value;\n }\n\n get flipWinding() {\n this._flipWinding;\n }\n\n set invertNormals(value) {\n if (this._geometryStarted) {\n throw new Error(`Cannot change invertNormals before ending the current geometry.`);\n }\n this._invertNormals = value;\n }\n\n get invertNormals() {\n this._invertNormals;\n }\n\n set transform(value) {\n if (this._geometryStarted) {\n throw new Error(`Cannot change transform before ending the current geometry.`);\n }\n this._transform = value;\n if (this._transform) {\n if (!this._normalTransform) {\n this._normalTransform = mat3.create();\n }\n mat3.fromMat4(this._normalTransform, this._transform);\n }\n }\n\n get transform() {\n this._transform;\n }\n\n startGeometry() {\n if (this._geometryStarted) {\n throw new Error(`Attempted to start a new geometry before the previous one was ended.`);\n }\n\n this._geometryStarted = true;\n this._vertexIndex = 0;\n this._highIndex = 0;\n }\n\n endGeometry() {\n if (!this._geometryStarted) {\n throw new Error(`Attempted to end a geometry before one was started.`);\n }\n\n if (this._highIndex >= this._vertexIndex) {\n throw new Error(`Geometry contains indices that are out of bounds.\n (Contains an index of ${this._highIndex} when the vertex count is ${this._vertexIndex})`);\n }\n\n this._geometryStarted = false;\n this._vertexOffset += this._vertexIndex;\n\n // TODO: Anything else need to be done to finish processing here?\n }\n\n pushVertex(x, y, z, u = 0, v = 0, nx = 0, ny = 0, nz = 1) {\n if (!this._geometryStarted) {\n throw new Error(`Cannot push vertices before calling startGeometry().`);\n }\n\n // Transform the incoming vertex if we have a transformation matrix\n if (this._transform) {\n tempVec3[0] = x;\n tempVec3[1] = y;\n tempVec3[2] = z;\n vec3.transformMat4(tempVec3, tempVec3, this._transform);\n x = tempVec3[0];\n y = tempVec3[1];\n z = tempVec3[2];\n\n tempVec3[0] = nx;\n tempVec3[1] = ny;\n tempVec3[2] = nz;\n vec3.transformMat3(tempVec3, tempVec3, this._normalTransform);\n nx = tempVec3[0];\n ny = tempVec3[1];\n nz = tempVec3[2];\n }\n\n if (this._invertNormals) {\n nx *= -1.0;\n ny *= -1.0;\n nz *= -1.0;\n }\n\n this._vertices.push(x, y, z, u, v, nx, ny, nz);\n\n if (this._min) {\n this._min[0] = Math.min(this._min[0], x);\n this._min[1] = Math.min(this._min[1], y);\n this._min[2] = Math.min(this._min[2], z);\n this._max[0] = Math.max(this._max[0], x);\n this._max[1] = Math.max(this._max[1], y);\n this._max[2] = Math.max(this._max[2], z);\n } else {\n this._min = vec3.fromValues(x, y, z);\n this._max = vec3.fromValues(x, y, z);\n }\n\n return this._vertexIndex++;\n }\n\n get nextVertexIndex() {\n return this._vertexIndex;\n }\n\n pushTriangle(idxA, idxB, idxC) {\n if (!this._geometryStarted) {\n throw new Error(`Cannot push triangles before calling startGeometry().`);\n }\n\n this._highIndex = Math.max(this._highIndex, idxA, idxB, idxC);\n\n idxA += this._vertexOffset;\n idxB += this._vertexOffset;\n idxC += this._vertexOffset;\n\n if (this._flipWinding) {\n this._indices.push(idxC, idxB, idxA);\n } else {\n this._indices.push(idxA, idxB, idxC);\n }\n }\n\n clear() {\n if (this._geometryStarted) {\n throw new Error(`Cannot clear before ending the current geometry.`);\n }\n\n this._vertices = [];\n this._indices = [];\n this._vertexOffset = 0;\n this._min = null;\n this._max = null;\n }\n\n finishPrimitive(renderer) {\n if (!this._vertexOffset) {\n throw new Error(`Attempted to call finishPrimitive() before creating any geometry.`);\n }\n\n let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(this._vertices));\n let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(this._indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 32, 0),\n new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 32, 12),\n new PrimitiveAttribute('NORMAL', vertexBuffer, 3, GL.FLOAT, 32, 20),\n ];\n\n let primitive = new Primitive(attribs, this._indices.length);\n primitive.setIndexBuffer(indexBuffer);\n primitive.setBounds(this._min, this._max);\n\n return primitive;\n }\n}\n\nexport class GeometryBuilderBase {\n constructor(primitiveStream) {\n if (primitiveStream) {\n this._stream = primitiveStream;\n } else {\n this._stream = new PrimitiveStream();\n }\n }\n\n set primitiveStream(value) {\n this._stream = value;\n }\n\n get primitiveStream() {\n return this._stream;\n }\n\n finishPrimitive(renderer) {\n return this._stream.finishPrimitive(renderer);\n }\n\n clear() {\n this._stream.clear();\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {PbrMaterial} from '../materials/pbr.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {ImageTexture, ColorTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst GLB_MAGIC = 0x46546C67;\nconst CHUNK_TYPE = {\n JSON: 0x4E4F534A,\n BIN: 0x004E4942,\n};\n\nfunction isAbsoluteUri(uri) {\n let absRegEx = new RegExp('^'+window.location.protocol, 'i');\n return !!uri.match(absRegEx);\n}\n\nfunction isDataUri(uri) {\n let dataRegEx = /^data:/;\n return !!uri.match(dataRegEx);\n}\n\nfunction resolveUri(uri, baseUrl) {\n if (isAbsoluteUri(uri) || isDataUri(uri)) {\n return uri;\n }\n return baseUrl + uri;\n}\n\nfunction getComponentCount(type) {\n switch (type) {\n case 'SCALAR': return 1;\n case 'VEC2': return 2;\n case 'VEC3': return 3;\n case 'VEC4': return 4;\n default: return 0;\n }\n}\n\n/**\n * Gltf2SceneLoader\n * Loads glTF 2.0 scenes into a renderable node tree.\n */\n\nexport class Gltf2Loader {\n constructor(renderer) {\n this.renderer = renderer;\n this._gl = renderer._gl;\n }\n\n loadFromUrl(url) {\n return fetch(url)\n .then((response) => {\n let i = url.lastIndexOf('/');\n let baseUrl = (i !== 0) ? url.substring(0, i + 1) : '';\n\n if (url.endsWith('.gltf')) {\n return response.json().then((json) => {\n return this.loadFromJson(json, baseUrl);\n });\n } else if (url.endsWith('.glb')) {\n return response.arrayBuffer().then((arrayBuffer) => {\n return this.loadFromBinary(arrayBuffer, baseUrl);\n });\n } else {\n throw new Error('Unrecognized file extension');\n }\n });\n }\n\n loadFromBinary(arrayBuffer, baseUrl) {\n let headerView = new DataView(arrayBuffer, 0, 12);\n let magic = headerView.getUint32(0, true);\n let version = headerView.getUint32(4, true);\n let length = headerView.getUint32(8, true);\n\n if (magic != GLB_MAGIC) {\n throw new Error('Invalid magic string in binary header.');\n }\n\n if (version != 2) {\n throw new Error('Incompatible version in binary header.');\n }\n\n let chunks = {};\n let chunkOffset = 12;\n while (chunkOffset < length) {\n let chunkHeaderView = new DataView(arrayBuffer, chunkOffset, 8);\n let chunkLength = chunkHeaderView.getUint32(0, true);\n let chunkType = chunkHeaderView.getUint32(4, true);\n chunks[chunkType] = arrayBuffer.slice(chunkOffset + 8, chunkOffset + 8 + chunkLength);\n chunkOffset += chunkLength + 8;\n }\n\n if (!chunks[CHUNK_TYPE.JSON]) {\n throw new Error('File contained no json chunk.');\n }\n\n let decoder = new TextDecoder('utf-8');\n let jsonString = decoder.decode(chunks[CHUNK_TYPE.JSON]);\n let json = JSON.parse(jsonString);\n return this.loadFromJson(json, baseUrl, chunks[CHUNK_TYPE.BIN]);\n }\n\n loadFromJson(json, baseUrl, binaryChunk) {\n if (!json.asset) {\n throw new Error('Missing asset description.');\n }\n\n if (json.asset.minVersion != '2.0' && json.asset.version != '2.0') {\n throw new Error('Incompatible asset version.');\n }\n\n let buffers = [];\n if (binaryChunk) {\n buffers[0] = new Gltf2Resource({}, baseUrl, binaryChunk);\n } else {\n for (let buffer of json.buffers) {\n buffers.push(new Gltf2Resource(buffer, baseUrl));\n }\n }\n\n let bufferViews = [];\n for (let bufferView of json.bufferViews) {\n bufferViews.push(new Gltf2BufferView(bufferView, buffers));\n }\n\n let images = [];\n if (json.images) {\n for (let image of json.images) {\n images.push(new Gltf2Resource(image, baseUrl));\n }\n }\n\n let textures = [];\n if (json.textures) {\n for (let texture of json.textures) {\n let image = images[texture.source];\n let glTexture = image.texture(bufferViews);\n if (texture.sampler) {\n let sampler = sampler[texture.sampler];\n glTexture.sampler.minFilter = sampler.minFilter;\n glTexture.sampler.magFilter = sampler.magFilter;\n glTexture.sampler.wrapS = sampler.wrapS;\n glTexture.sampler.wrapT = sampler.wrapT;\n }\n textures.push(glTexture);\n }\n }\n\n function getTexture(textureInfo) {\n if (!textureInfo) {\n return null;\n }\n return textures[textureInfo.index];\n }\n\n let materials = [];\n if (json.materials) {\n for (let material of json.materials) {\n let glMaterial = new PbrMaterial();\n let pbr = material.pbrMetallicRoughness || {};\n\n glMaterial.baseColorFactor.value = pbr.baseColorFactor || [1, 1, 1, 1];\n glMaterial.baseColor.texture = getTexture(pbr.baseColorTexture);\n glMaterial.metallicRoughnessFactor.value = [\n pbr.metallicFactor || 1.0,\n pbr.roughnessFactor || 1.0,\n ];\n glMaterial.metallicRoughness.texture = getTexture(pbr.metallicRoughnessTexture);\n glMaterial.normal.texture = getTexture(json.normalTexture);\n glMaterial.occlusion.texture = getTexture(json.occlusionTexture);\n glMaterial.occlusionStrength.value = (json.occlusionTexture && json.occlusionTexture.strength) ?\n json.occlusionTexture.strength : 1.0;\n glMaterial.emissiveFactor.value = material.emissiveFactor || [0, 0, 0];\n glMaterial.emissive.texture = getTexture(json.emissiveTexture);\n if (!glMaterial.emissive.texture && json.emissiveFactor) {\n glMaterial.emissive.texture = new ColorTexture(1.0, 1.0, 1.0, 1.0);\n }\n\n switch (material.alphaMode) {\n case 'BLEND':\n glMaterial.state.blend = true;\n break;\n case 'MASK':\n // Not really supported.\n glMaterial.state.blend = true;\n break;\n default: // Includes 'OPAQUE'\n glMaterial.state.blend = false;\n }\n\n // glMaterial.alpha_mode = material.alphaMode;\n // glMaterial.alpha_cutoff = material.alphaCutoff;\n glMaterial.state.cullFace = !(material.doubleSided);\n\n materials.push(glMaterial);\n }\n }\n\n let accessors = json.accessors;\n\n let meshes = [];\n for (let mesh of json.meshes) {\n let glMesh = new Gltf2Mesh();\n meshes.push(glMesh);\n\n for (let primitive of mesh.primitives) {\n let material = null;\n if ('material' in primitive) {\n material = materials[primitive.material];\n } else {\n // Create a \"default\" material if the primitive has none.\n material = new PbrMaterial();\n }\n\n let attributes = [];\n let elementCount = 0;\n /* let glPrimitive = new Gltf2Primitive(primitive, material);\n glMesh.primitives.push(glPrimitive); */\n\n let min = null;\n let max = null;\n\n for (let name in primitive.attributes) {\n let accessor = accessors[primitive.attributes[name]];\n let bufferView = bufferViews[accessor.bufferView];\n elementCount = accessor.count;\n\n let glAttribute = new PrimitiveAttribute(\n name,\n bufferView.renderBuffer(this.renderer, GL.ARRAY_BUFFER),\n getComponentCount(accessor.type),\n accessor.componentType,\n bufferView.byteStride || 0,\n accessor.byteOffset || 0\n );\n glAttribute.normalized = accessor.normalized || false;\n\n if (name == 'POSITION') {\n min = accessor.min;\n max = accessor.max;\n }\n\n attributes.push(glAttribute);\n }\n\n let glPrimitive = new Primitive(attributes, elementCount, primitive.mode);\n\n if ('indices' in primitive) {\n let accessor = accessors[primitive.indices];\n let bufferView = bufferViews[accessor.bufferView];\n\n glPrimitive.setIndexBuffer(\n bufferView.renderBuffer(this.renderer, GL.ELEMENT_ARRAY_BUFFER),\n accessor.byteOffset || 0,\n accessor.componentType\n );\n glPrimitive.indexType = accessor.componentType;\n glPrimitive.indexByteOffset = accessor.byteOffset || 0;\n glPrimitive.elementCount = accessor.count;\n }\n\n if (min && max) {\n glPrimitive.setBounds(min, max);\n }\n\n // After all the attributes have been processed, get a program that is\n // appropriate for both the material and the primitive attributes.\n glMesh.primitives.push(\n this.renderer.createRenderPrimitive(glPrimitive, material));\n }\n }\n\n let sceneNode = new Node();\n let scene = json.scenes[json.scene];\n for (let nodeId of scene.nodes) {\n let node = json.nodes[nodeId];\n sceneNode.addNode(\n this.processNodes(node, json.nodes, meshes));\n }\n\n return sceneNode;\n }\n\n processNodes(node, nodes, meshes) {\n let glNode = new Node();\n glNode.name = node.name;\n\n if ('mesh' in node) {\n let mesh = meshes[node.mesh];\n for (let primitive of mesh.primitives) {\n glNode.addRenderPrimitive(primitive);\n }\n }\n\n if (node.matrix) {\n glNode.matrix = new Float32Array(node.matrix);\n } else if (node.translation || node.rotation || node.scale) {\n if (node.translation) {\n glNode.translation = new Float32Array(node.translation);\n }\n\n if (node.rotation) {\n glNode.rotation = new Float32Array(node.rotation);\n }\n\n if (node.scale) {\n glNode.scale = new Float32Array(node.scale);\n }\n }\n\n if (node.children) {\n for (let nodeId of node.children) {\n let node = nodes[nodeId];\n glNode.addNode(this.processNodes(node, nodes, meshes));\n }\n }\n\n return glNode;\n }\n}\n\nclass Gltf2Mesh {\n constructor() {\n this.primitives = [];\n }\n}\n\nclass Gltf2BufferView {\n constructor(json, buffers) {\n this.buffer = buffers[json.buffer];\n this.byteOffset = json.byteOffset || 0;\n this.byteLength = json.byteLength || null;\n this.byteStride = json.byteStride;\n\n this._viewPromise = null;\n this._renderBuffer = null;\n }\n\n dataView() {\n if (!this._viewPromise) {\n this._viewPromise = this.buffer.arrayBuffer().then((arrayBuffer) => {\n return new DataView(arrayBuffer, this.byteOffset, this.byteLength);\n });\n }\n return this._viewPromise;\n }\n\n renderBuffer(renderer, target) {\n if (!this._renderBuffer) {\n this._renderBuffer = renderer.createRenderBuffer(target, this.dataView());\n }\n return this._renderBuffer;\n }\n}\n\nclass Gltf2Resource {\n constructor(json, baseUrl, arrayBuffer) {\n this.json = json;\n this.baseUrl = baseUrl;\n\n this._dataPromise = null;\n this._texture = null;\n if (arrayBuffer) {\n this._dataPromise = Promise.resolve(arrayBuffer);\n }\n }\n\n arrayBuffer() {\n if (!this._dataPromise) {\n if (isDataUri(this.json.uri)) {\n let base64String = this.json.uri.replace('data:application/octet-stream;base64,', '');\n let binaryArray = Uint8Array.from(atob(base64String), (c) => c.charCodeAt(0));\n this._dataPromise = Promise.resolve(binaryArray.buffer);\n return this._dataPromise;\n }\n\n this._dataPromise = fetch(resolveUri(this.json.uri, this.baseUrl))\n .then((response) => response.arrayBuffer());\n }\n return this._dataPromise;\n }\n\n texture(bufferViews) {\n if (!this._texture) {\n let img = new Image();\n this._texture = new ImageTexture(img);\n\n if (this.json.uri) {\n if (isDataUri(this.json.uri)) {\n img.src = this.json.uri;\n } else {\n img.src = `${this.baseUrl}${this.json.uri}`;\n }\n } else {\n let view = bufferViews[this.json.bufferView];\n view.dataView().then((dataView) => {\n let blob = new Blob([dataView], {type: this.json.mimeType});\n img.src = window.URL.createObjectURL(blob);\n });\n }\n }\n return this._texture;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {ATTRIB_MASK} from '../core/renderer.js';\n\nconst VERTEX_SOURCE = `\nattribute vec3 POSITION, NORMAL;\nattribute vec2 TEXCOORD_0, TEXCOORD_1;\n\nuniform vec3 CAMERA_POSITION;\nuniform vec3 LIGHT_DIRECTION;\n\nvarying vec3 vLight; // Vector from vertex to light.\nvarying vec3 vView; // Vector from vertex to camera.\nvarying vec2 vTex;\n\n#ifdef USE_NORMAL_MAP\nattribute vec4 TANGENT;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_VERTEX_COLOR\nattribute vec4 COLOR_0;\nvarying vec4 vCol;\n#endif\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 n = normalize(vec3(model * vec4(NORMAL, 0.0)));\n#ifdef USE_NORMAL_MAP\n vec3 t = normalize(vec3(model * vec4(TANGENT.xyz, 0.0)));\n vec3 b = cross(n, t) * TANGENT.w;\n vTBN = mat3(t, b, n);\n#else\n vNorm = n;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n vCol = COLOR_0;\n#endif\n\n vTex = TEXCOORD_0;\n vec4 mPos = model * vec4(POSITION, 1.0);\n vLight = -LIGHT_DIRECTION;\n vView = CAMERA_POSITION - mPos.xyz;\n return proj * view * mPos;\n}`;\n\n// These equations are borrowed with love from this docs from Epic because I\n// just don't have anything novel to bring to the PBR scene.\n// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf\nconst EPIC_PBR_FUNCTIONS = `\nvec3 lambertDiffuse(vec3 cDiff) {\n return cDiff / M_PI;\n}\n\nfloat specD(float a, float nDotH) {\n float aSqr = a * a;\n float f = ((nDotH * nDotH) * (aSqr - 1.0) + 1.0);\n return aSqr / (M_PI * f * f);\n}\n\nfloat specG(float roughness, float nDotL, float nDotV) {\n float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n float gl = nDotL / (nDotL * (1.0 - k) + k);\n float gv = nDotV / (nDotV * (1.0 - k) + k);\n return gl * gv;\n}\n\nvec3 specF(float vDotH, vec3 F0) {\n float exponent = (-5.55473 * vDotH - 6.98316) * vDotH;\n float base = 2.0;\n return F0 + (1.0 - F0) * pow(base, exponent);\n}`;\n\nconst FRAGMENT_SOURCE = `\n#define M_PI 3.14159265\n\nuniform vec4 baseColorFactor;\n#ifdef USE_BASE_COLOR_MAP\nuniform sampler2D baseColorTex;\n#endif\n\nvarying vec3 vLight;\nvarying vec3 vView;\nvarying vec2 vTex;\n\n#ifdef USE_VERTEX_COLOR\nvarying vec4 vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\nuniform sampler2D normalTex;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_METAL_ROUGH_MAP\nuniform sampler2D metallicRoughnessTex;\n#endif\nuniform vec2 metallicRoughnessFactor;\n\n#ifdef USE_OCCLUSION\nuniform sampler2D occlusionTex;\nuniform float occlusionStrength;\n#endif\n\n#ifdef USE_EMISSIVE_TEXTURE\nuniform sampler2D emissiveTex;\n#endif\nuniform vec3 emissiveFactor;\n\nuniform vec3 LIGHT_COLOR;\n\nconst vec3 dielectricSpec = vec3(0.04);\nconst vec3 black = vec3(0.0);\n\n${EPIC_PBR_FUNCTIONS}\n\nvec4 fragment_main() {\n#ifdef USE_BASE_COLOR_MAP\n vec4 baseColor = texture2D(baseColorTex, vTex) * baseColorFactor;\n#else\n vec4 baseColor = baseColorFactor;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n baseColor *= vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\n vec3 n = texture2D(normalTex, vTex).rgb;\n n = normalize(vTBN * (2.0 * n - 1.0));\n#else\n vec3 n = normalize(vNorm);\n#endif\n\n#ifdef FULLY_ROUGH\n float metallic = 0.0;\n#else\n float metallic = metallicRoughnessFactor.x;\n#endif\n\n float roughness = metallicRoughnessFactor.y;\n\n#ifdef USE_METAL_ROUGH_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessTex, vTex);\n metallic *= metallicRoughness.b;\n roughness *= metallicRoughness.g;\n#endif\n \n vec3 l = normalize(vLight);\n vec3 v = normalize(vView);\n vec3 h = normalize(l+v);\n\n float nDotL = clamp(dot(n, l), 0.001, 1.0);\n float nDotV = abs(dot(n, v)) + 0.001;\n float nDotH = max(dot(n, h), 0.0);\n float vDotH = max(dot(v, h), 0.0);\n\n // From GLTF Spec\n vec3 cDiff = mix(baseColor.rgb * (1.0 - dielectricSpec.r), black, metallic); // Diffuse color\n vec3 F0 = mix(dielectricSpec, baseColor.rgb, metallic); // Specular color\n float a = roughness * roughness;\n\n#ifdef FULLY_ROUGH\n vec3 specular = F0 * 0.45;\n#else\n vec3 F = specF(vDotH, F0);\n float D = specD(a, nDotH);\n float G = specG(roughness, nDotL, nDotV);\n vec3 specular = (D * F * G) / (4.0 * nDotL * nDotV);\n#endif\n float halfLambert = dot(n, l) * 0.5 + 0.5;\n halfLambert *= halfLambert;\n\n vec3 color = (halfLambert * LIGHT_COLOR * lambertDiffuse(cDiff)) + specular;\n\n#ifdef USE_OCCLUSION\n float occlusion = texture2D(occlusionTex, vTex).r;\n color = mix(color, color * occlusion, occlusionStrength);\n#endif\n \n vec3 emissive = emissiveFactor;\n#ifdef USE_EMISSIVE_TEXTURE\n emissive *= texture2D(emissiveTex, vTex).rgb;\n#endif\n color += emissive;\n\n // gamma correction\n //color = pow(color, vec3(1.0/2.2));\n\n return vec4(color, baseColor.a);\n}`;\n\nexport class PbrMaterial extends Material {\n constructor() {\n super();\n\n this.baseColor = this.defineSampler('baseColorTex');\n this.metallicRoughness = this.defineSampler('metallicRoughnessTex');\n this.normal = this.defineSampler('normalTex');\n this.occlusion = this.defineSampler('occlusionTex');\n this.emissive = this.defineSampler('emissiveTex');\n\n this.baseColorFactor = this.defineUniform('baseColorFactor', [1.0, 1.0, 1.0, 1.0]);\n this.metallicRoughnessFactor = this.defineUniform('metallicRoughnessFactor', [1.0, 1.0]);\n this.occlusionStrength = this.defineUniform('occlusionStrength', 1.0);\n this.emissiveFactor = this.defineUniform('emissiveFactor', [0, 0, 0]);\n }\n\n get materialName() {\n return 'PBR';\n }\n\n get vertexSource() {\n return VERTEX_SOURCE;\n }\n\n get fragmentSource() {\n return FRAGMENT_SOURCE;\n }\n\n getProgramDefines(renderPrimitive) {\n let programDefines = {};\n\n if (renderPrimitive._attributeMask & ATTRIB_MASK.COLOR_0) {\n programDefines['USE_VERTEX_COLOR'] = 1;\n }\n\n if (renderPrimitive._attributeMask & ATTRIB_MASK.TEXCOORD_0) {\n if (this.baseColor.texture) {\n programDefines['USE_BASE_COLOR_MAP'] = 1;\n }\n\n if (this.normal.texture && (renderPrimitive._attributeMask & ATTRIB_MASK.TANGENT)) {\n programDefines['USE_NORMAL_MAP'] = 1;\n }\n\n if (this.metallicRoughness.texture) {\n programDefines['USE_METAL_ROUGH_MAP'] = 1;\n }\n\n if (this.occlusion.texture) {\n programDefines['USE_OCCLUSION'] = 1;\n }\n\n if (this.emissive.texture) {\n programDefines['USE_EMISSIVE_TEXTURE'] = 1;\n }\n }\n\n if ((!this.metallicRoughness.texture ||\n !(renderPrimitive._attributeMask & ATTRIB_MASK.TEXCOORD_0)) &&\n this.metallicRoughnessFactor.value[1] == 1.0) {\n programDefines['FULLY_ROUGH'] = 1;\n }\n\n return programDefines;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport * as glMatrix from '../../node_modules/gl-matrix/src/gl-matrix/common.js';\nimport * as mat2 from '../../node_modules/gl-matrix/src/gl-matrix/mat2.js';\nimport * as mat2d from '../../node_modules/gl-matrix/src/gl-matrix/mat2d.js';\nimport * as mat3 from '../../node_modules/gl-matrix/src/gl-matrix/mat3.js';\nimport * as mat4 from '../../node_modules/gl-matrix/src/gl-matrix/mat4.js';\nimport * as quat from '../../node_modules/gl-matrix/src/gl-matrix/quat.js';\nimport * as quat2 from '../../node_modules/gl-matrix/src/gl-matrix/quat2.js';\nimport * as vec2 from '../../node_modules/gl-matrix/src/gl-matrix/vec2.js';\nimport * as vec3 from '../../node_modules/gl-matrix/src/gl-matrix/vec3.js';\nimport * as vec4 from '../../node_modules/gl-matrix/src/gl-matrix/vec4.js';\n\nexport {\n glMatrix,\n mat2,\n mat2d,\n mat3,\n mat4,\n quat,\n quat2,\n vec2,\n vec3,\n vec4,\n};\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {mat3, vec3} from './gl-matrix.js';\n\nlet normalMat = mat3.create();\n\nconst RAY_INTERSECTION_OFFSET = 0.02;\n\nexport class Ray {\n constructor(matrix = null) {\n this.origin = vec3.create();\n\n this._dir = vec3.create();\n this._dir[2] = -1.0;\n\n if (matrix) {\n vec3.transformMat4(this.origin, this.origin, matrix);\n mat3.fromMat4(normalMat, matrix);\n vec3.transformMat3(this._dir, this._dir, normalMat);\n }\n\n // To force the inverse and sign calculations.\n this.dir = this._dir;\n }\n\n get dir() {\n return this._dir;\n }\n\n set dir(value) {\n this._dir = vec3.copy(this._dir, value);\n vec3.normalize(this._dir, this._dir);\n\n this.inv_dir = vec3.fromValues(\n 1.0 / this._dir[0],\n 1.0 / this._dir[1],\n 1.0 / this._dir[2]);\n\n this.sign = [\n (this.inv_dir[0] < 0) ? 1 : 0,\n (this.inv_dir[1] < 0) ? 1 : 0,\n (this.inv_dir[2] < 0) ? 1 : 0,\n ];\n }\n\n // Borrowed from:\n // eslint-disable-next-line max-len\n // https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection\n intersectsAABB(min, max) {\n let r = this;\n\n let bounds = [min, max];\n\n let tmin = (bounds[r.sign[0]][0] - r.origin[0]) * r.inv_dir[0];\n let tmax = (bounds[1-r.sign[0]][0] - r.origin[0]) * r.inv_dir[0];\n let tymin = (bounds[r.sign[1]][1] - r.origin[1]) * r.inv_dir[1];\n let tymax = (bounds[1-r.sign[1]][1] - r.origin[1]) * r.inv_dir[1];\n\n if ((tmin > tymax) || (tymin > tmax)) {\n return null;\n }\n if (tymin > tmin) {\n tmin = tymin;\n }\n if (tymax < tmax) {\n tmax = tymax;\n }\n\n let tzmin = (bounds[r.sign[2]][2] - r.origin[2]) * r.inv_dir[2];\n let tzmax = (bounds[1-r.sign[2]][2] - r.origin[2]) * r.inv_dir[2];\n\n if ((tmin > tzmax) || (tzmin > tmax)) {\n return null;\n }\n if (tzmin > tmin) {\n tmin = tzmin;\n }\n if (tzmax < tmax) {\n tmax = tzmax;\n }\n\n let t = -1;\n if (tmin > 0 && tmax > 0) {\n t = Math.min(tmin, tmax);\n } else if (tmin > 0) {\n t = tmin;\n } else if (tmax > 0) {\n t = tmax;\n } else {\n // Intersection is behind the ray origin.\n return null;\n }\n\n // Push ray intersection point back along the ray a bit so that cursors\n // don't accidentally intersect with the hit surface.\n t -= RAY_INTERSECTION_OFFSET;\n\n // Return the point where the ray first intersected with the AABB.\n let intersectionPoint = vec3.clone(this._dir);\n vec3.scale(intersectionPoint, intersectionPoint, t);\n vec3.add(intersectionPoint, intersectionPoint, this.origin);\n return intersectionPoint;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nThis file renders a passed in XRStageBounds object and attempts\nto render geometry on the floor to indicate where the bounds is.\nXRStageBounds' `geometry` is a series of XRStageBoundsPoints (in\nclockwise-order) with `x` and `z` properties for each.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nclass BoundsMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n this.state.blendFuncSrc = GL.SRC_ALPHA;\n this.state.blendFuncDst = GL.ONE;\n this.state.depthTest = false;\n }\n\n get materialName() {\n return 'BOUNDS_RENDERER';\n }\n\n get vertexSource() {\n return `\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n\n vec4 fragment_main() {\n return vec4(0.0, 1.0, 0.0, 0.3);\n }`;\n }\n}\n\nexport class BoundsRenderer extends Node {\n constructor() {\n super();\n\n this._stageBounds = null;\n }\n\n onRendererChanged(renderer) {\n this.stageBounds = this._stageBounds;\n }\n\n get stageBounds() {\n return this._stageBounds;\n }\n\n set stageBounds(stageBounds) {\n if (this._stageBounds) {\n this.clearRenderPrimitives();\n }\n this._stageBounds = stageBounds;\n if (!stageBounds || stageBounds.length === 0 || !this._renderer) {\n return;\n }\n\n let verts = [];\n let indices = [];\n\n // Tessellate the bounding points from XRStageBounds and connect\n // each point to a neighbor and 0,0,0.\n const pointCount = stageBounds.geometry.length;\n for (let i = 0; i < pointCount; i++) {\n const point = stageBounds.geometry[i];\n verts.push(point.x, 0, point.z);\n indices.push(i, i === 0 ? pointCount - 1 : i - 1, pointCount);\n }\n // Center point\n verts.push(0, 0, 0);\n\n let vertexBuffer = this._renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(verts));\n let indexBuffer = this._renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 12, 0),\n ];\n\n let primitive = new Primitive(attribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n\n let renderPrimitive = this._renderer.createRenderPrimitive(primitive, new BoundsMaterial());\n this.addRenderPrimitive(renderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {PrimitiveStream} from '../geometry/primitive-stream.js';\n\nconst BUTTON_SIZE = 0.1;\nconst BUTTON_CORNER_RADIUS = 0.025;\nconst BUTTON_CORNER_SEGMENTS = 8;\nconst BUTTON_ICON_SIZE = 0.07;\nconst BUTTON_LAYER_DISTANCE = 0.005;\nconst BUTTON_COLOR = 0.75;\nconst BUTTON_ALPHA = 0.85;\nconst BUTTON_HOVER_COLOR = 0.9;\nconst BUTTON_HOVER_ALPHA = 1.0;\nconst BUTTON_HOVER_SCALE = 1.1;\nconst BUTTON_HOVER_TRANSITION_TIME_MS = 200;\n\nclass ButtonMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n\n this.defineUniform('hoverAmount', 0);\n }\n\n get materialName() {\n return 'BUTTON_MATERIAL';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n\n uniform float hoverAmount;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n float scale = mix(1.0, ${BUTTON_HOVER_SCALE}, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform float hoverAmount;\n\n const vec4 default_color = vec4(${BUTTON_COLOR}, ${BUTTON_COLOR}, ${BUTTON_COLOR}, ${BUTTON_ALPHA});\n const vec4 hover_color = vec4(${BUTTON_HOVER_COLOR}, ${BUTTON_HOVER_COLOR},\n ${BUTTON_HOVER_COLOR}, ${BUTTON_HOVER_ALPHA});\n\n vec4 fragment_main() {\n return mix(default_color, hover_color, hoverAmount);\n }`;\n }\n}\n\nclass ButtonIconMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n\n this.defineUniform('hoverAmount', 0);\n this.icon = this.defineSampler('icon');\n }\n\n get materialName() {\n return 'BUTTON_ICON_MATERIAL';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n uniform float hoverAmount;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n float scale = mix(1.0, ${BUTTON_HOVER_SCALE}, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform sampler2D icon;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(icon, vTexCoord);\n }`;\n }\n}\n\nexport class ButtonNode extends Node {\n constructor(iconTexture, callback) {\n super();\n\n // All buttons are selectable by default.\n this.selectable = true;\n\n this._selectHandler = callback;\n this._iconTexture = iconTexture;\n this._hovered = false;\n this._hoverT = 0;\n }\n\n get iconTexture() {\n return this._iconTexture;\n }\n\n set iconTexture(value) {\n if (this._iconTexture == value) {\n return;\n }\n\n this._iconTexture = value;\n this._iconRenderPrimitive.samplers.icon.texture = value;\n }\n\n onRendererChanged(renderer) {\n let stream = new PrimitiveStream();\n\n let hd = BUTTON_LAYER_DISTANCE * 0.5;\n\n // Build a rounded rect for the background.\n let hs = BUTTON_SIZE * 0.5;\n let ihs = hs - BUTTON_CORNER_RADIUS;\n stream.startGeometry();\n\n // Rounded corners and sides\n let segments = BUTTON_CORNER_SEGMENTS * 4;\n for (let i = 0; i < segments; ++i) {\n let rad = i * ((Math.PI * 2.0) / segments);\n let x = Math.cos(rad) * BUTTON_CORNER_RADIUS;\n let y = Math.sin(rad) * BUTTON_CORNER_RADIUS;\n let section = Math.floor(i / BUTTON_CORNER_SEGMENTS);\n switch (section) {\n case 0:\n x += ihs;\n y += ihs;\n break;\n case 1:\n x -= ihs;\n y += ihs;\n break;\n case 2:\n x -= ihs;\n y -= ihs;\n break;\n case 3:\n x += ihs;\n y -= ihs;\n break;\n }\n\n stream.pushVertex(x, y, -hd, 0, 0, 0, 0, 1);\n\n if (i > 1) {\n stream.pushTriangle(0, i-1, i);\n }\n }\n\n stream.endGeometry();\n\n let buttonPrimitive = stream.finishPrimitive(renderer);\n this._buttonRenderPrimitive = renderer.createRenderPrimitive(buttonPrimitive, new ButtonMaterial());\n this.addRenderPrimitive(this._buttonRenderPrimitive);\n\n // Build a simple textured quad for the foreground.\n hs = BUTTON_ICON_SIZE * 0.5;\n stream.clear();\n stream.startGeometry();\n\n stream.pushVertex(-hs, hs, hd, 0, 0, 0, 0, 1);\n stream.pushVertex(-hs, -hs, hd, 0, 1, 0, 0, 1);\n stream.pushVertex(hs, -hs, hd, 1, 1, 0, 0, 1);\n stream.pushVertex(hs, hs, hd, 1, 0, 0, 0, 1);\n\n stream.pushTriangle(0, 1, 2);\n stream.pushTriangle(0, 2, 3);\n\n stream.endGeometry();\n\n let iconPrimitive = stream.finishPrimitive(renderer);\n let iconMaterial = new ButtonIconMaterial();\n iconMaterial.icon.texture = this._iconTexture;\n this._iconRenderPrimitive = renderer.createRenderPrimitive(iconPrimitive, iconMaterial);\n this.addRenderPrimitive(this._iconRenderPrimitive);\n }\n\n onHoverStart() {\n this._hovered = true;\n }\n\n onHoverEnd() {\n this._hovered = false;\n }\n\n _updateHoverState() {\n let t = this._hoverT / BUTTON_HOVER_TRANSITION_TIME_MS;\n // Cubic Ease In/Out\n // TODO: Get a better animation system\n let hoverAmount = t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1;\n this._buttonRenderPrimitive.uniforms.hoverAmount.value = hoverAmount;\n this._iconRenderPrimitive.uniforms.hoverAmount.value = hoverAmount;\n }\n\n onUpdate(timestamp, frameDelta) {\n if (this._hovered && this._hoverT < BUTTON_HOVER_TRANSITION_TIME_MS) {\n this._hoverT = Math.min(BUTTON_HOVER_TRANSITION_TIME_MS, this._hoverT + frameDelta);\n this._updateHoverState();\n } else if (!this._hovered && this._hoverT > 0) {\n this._hoverT = Math.max(0.0, this._hoverT - frameDelta);\n this._updateHoverState();\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {UrlTexture} from '../core/texture.js';\nimport {BoxBuilder} from '../geometry/box-builder.js';\nimport {mat4} from '../math/gl-matrix.js';\n\nclass CubeSeaMaterial extends Material {\n constructor(heavy = false) {\n super();\n\n this.heavy = heavy;\n\n this.baseColor = this.defineSampler('baseColor');\n }\n\n get materialName() {\n return 'CUBE_SEA';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n attribute vec3 NORMAL;\n\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n const vec3 lightDir = vec3(0.75, 0.5, 1.0);\n const vec3 ambientColor = vec3(0.5, 0.5, 0.5);\n const vec3 lightColor = vec3(0.75, 0.75, 0.75);\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 normalRotated = vec3(model * vec4(NORMAL, 0.0));\n float lightFactor = max(dot(normalize(lightDir), normalRotated), 0.0);\n vLight = ambientColor + (lightColor * lightFactor);\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n if (!this.heavy) {\n return `\n precision mediump float;\n uniform sampler2D baseColor;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec4 fragment_main() {\n return vec4(vLight, 1.0) * texture2D(baseColor, vTexCoord);\n }`;\n } else {\n // Used when we want to stress the GPU a bit more.\n // Stolen with love from https://www.clicktorelease.com/code/codevember-2016/4/\n return `\n precision mediump float;\n\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec2 dimensions = vec2(64, 64);\n float seed = 0.42;\n\n vec2 hash( vec2 p ) {\n p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3)));\n return fract(sin(p)*18.5453);\n }\n\n vec3 hash3( vec2 p ) {\n vec3 q = vec3( dot(p,vec2(127.1,311.7)),\n dot(p,vec2(269.5,183.3)),\n dot(p,vec2(419.2,371.9)) );\n return fract(sin(q)*43758.5453);\n }\n\n float iqnoise( in vec2 x, float u, float v ) {\n vec2 p = floor(x);\n vec2 f = fract(x);\n float k = 1.0+63.0*pow(1.0-v,4.0);\n float va = 0.0;\n float wt = 0.0;\n for( int j=-2; j<=2; j++ )\n for( int i=-2; i<=2; i++ ) {\n vec2 g = vec2( float(i),float(j) );\n vec3 o = hash3( p + g )*vec3(u,u,1.0);\n vec2 r = g - f + o.xy;\n float d = dot(r,r);\n float ww = pow( 1.0-smoothstep(0.0,1.414,sqrt(d)), k );\n va += o.z*ww;\n wt += ww;\n }\n return va/wt;\n }\n\n // return distance, and cell id\n vec2 voronoi( in vec2 x ) {\n vec2 n = floor( x );\n vec2 f = fract( x );\n vec3 m = vec3( 8.0 );\n for( int j=-1; j<=1; j++ )\n for( int i=-1; i<=1; i++ ) {\n vec2 g = vec2( float(i), float(j) );\n vec2 o = hash( n + g );\n vec2 r = g - f + (0.5+0.5*sin(seed+6.2831*o));\n float d = dot( r, r );\n if( d<m.x )\n m = vec3( d, o );\n }\n return vec2( sqrt(m.x), m.y+m.z );\n }\n\n vec4 fragment_main() {\n vec2 uv = ( vTexCoord );\n uv *= vec2( 10., 10. );\n uv += seed;\n vec2 p = 0.5 - 0.5*sin( 0.*vec2(1.01,1.71) );\n\n vec2 c = voronoi( uv );\n vec3 col = vec3( c.y / 2. );\n\n float f = iqnoise( 1. * uv + c.y, p.x, p.y );\n col *= 1.0 + .25 * vec3( f );\n\n return vec4(vLight, 1.0) * texture2D(diffuse, vTexCoord) * vec4( col, 1. );\n }`;\n }\n }\n}\n\nexport class CubeSeaNode extends Node {\n constructor(options = {}) {\n super();\n\n // Test variables\n // If true, use a very heavyweight shader to stress the GPU.\n this.heavyGpu = !!options.heavyGpu;\n\n // Number and size of the static cubes. Warning, large values\n // don't render right due to overflow of the int16 indices.\n this.cubeCount = options.cubeCount || (this.heavyGpu ? 12 : 10);\n this.cubeScale = options.cubeScale || 1.0;\n\n // Draw only half the world cubes. Helps test variable render cost\n // when combined with heavyGpu.\n this.halfOnly = !!options.halfOnly;\n\n // Automatically spin the world cubes. Intended for automated testing,\n // not recommended for viewing in a headset.\n this.autoRotate = !!options.autoRotate;\n\n this._texture = new UrlTexture(options.imageUrl || 'media/textures/cube-sea.png');\n\n this._material = new CubeSeaMaterial(this.heavyGpu);\n this._material.baseColor.texture = this._texture;\n\n this._renderPrimitive = null;\n }\n\n onRendererChanged(renderer) {\n this._renderPrimitive = null;\n\n let boxBuilder = new BoxBuilder();\n\n // Build the spinning \"hero\" cubes\n boxBuilder.pushCube([0, 0.25, -0.8], 0.1);\n boxBuilder.pushCube([0.8, 0.25, 0], 0.1);\n boxBuilder.pushCube([0, 0.25, 0.8], 0.1);\n boxBuilder.pushCube([-0.8, 0.25, 0], 0.1);\n\n let heroPrimitive = boxBuilder.finishPrimitive(renderer);\n\n this.heroNode = renderer.createMesh(heroPrimitive, this._material);\n\n this.rebuildCubes(boxBuilder);\n\n this.cubeSeaNode = new Node();\n this.cubeSeaNode.addRenderPrimitive(this._renderPrimitive);\n\n this.addNode(this.cubeSeaNode);\n this.addNode(this.heroNode);\n\n return this.waitForComplete();\n }\n\n rebuildCubes(boxBuilder) {\n if (!this._renderer) {\n return;\n }\n\n if (!boxBuilder) {\n boxBuilder = new BoxBuilder();\n } else {\n boxBuilder.clear();\n }\n\n let size = 0.4 * this.cubeScale;\n\n // Build the cube sea\n let halfGrid = this.cubeCount * 0.5;\n for (let x = 0; x < this.cubeCount; ++x) {\n for (let y = 0; y < this.cubeCount; ++y) {\n for (let z = 0; z < this.cubeCount; ++z) {\n let pos = [x - halfGrid, y - halfGrid, z - halfGrid];\n // Only draw cubes on one side. Useful for testing variable render\n // cost that depends on view direction.\n if (this.halfOnly && pos[0] < 0) {\n continue;\n }\n\n // Don't place a cube in the center of the grid.\n if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0) {\n continue;\n }\n\n boxBuilder.pushCube(pos, size);\n }\n }\n }\n\n if (this.cubeCount > 12) {\n // Each cube has 6 sides with 2 triangles and 3 indices per triangle, so\n // the total number of indices needed is cubeCount^3 * 36. This exceeds\n // the short index range past 12 cubes.\n boxBuilder.indexType = 5125; // gl.UNSIGNED_INT\n }\n let cubeSeaPrimitive = boxBuilder.finishPrimitive(this._renderer);\n\n if (!this._renderPrimitive) {\n this._renderPrimitive = this._renderer.createRenderPrimitive(cubeSeaPrimitive, this._material);\n } else {\n this._renderPrimitive.setPrimitive(cubeSeaPrimitive);\n }\n }\n\n onUpdate(timestamp, frameDelta) {\n if (this.autoRotate) {\n mat4.fromRotation(this.cubeSeaNode.matrix, timestamp / 500, [0, -1, 0]);\n }\n mat4.fromRotation(this.heroNode.matrix, timestamp / 2000, [0, 1, 0]);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {PrimitiveStream} from '../geometry/primitive-stream.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst SHADOW_SEGMENTS = 32;\nconst SHADOW_GROUND_OFFSET = 0.01;\nconst SHADOW_CENTER_ALPHA = 0.7;\nconst SHADOW_INNER_ALPHA = 0.3;\nconst SHADOW_OUTER_ALPHA = 0.0;\nconst SHADOW_INNER_RADIUS = 0.6;\nconst SHADOW_OUTER_RADIUS = 1.0;\n\nclass DropShadowMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.blendFuncDst = GL.ONE_MINUS_SRC_ALPHA;\n this.state.depthFunc = GL.LEQUAL;\n this.state.depthMask = false;\n }\n\n get materialName() {\n return 'DROP_SHADOW_MATERIAL';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying float vShadow;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vShadow = TEXCOORD_0.x;\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n varying float vShadow;\n\n vec4 fragment_main() {\n return vec4(0.0, 0.0, 0.0, vShadow);\n }`;\n }\n}\n\nexport class DropShadowNode extends Node {\n constructor(iconTexture, callback) {\n super();\n }\n\n onRendererChanged(renderer) {\n let stream = new PrimitiveStream();\n\n stream.startGeometry();\n\n // Shadow center\n stream.pushVertex(0, SHADOW_GROUND_OFFSET, 0, SHADOW_CENTER_ALPHA);\n\n let segRad = ((Math.PI * 2.0) / SHADOW_SEGMENTS);\n\n let idx;\n for (let i = 0; i < SHADOW_SEGMENTS; ++i) {\n idx = stream.nextVertexIndex;\n\n let rad = i * segRad;\n let x = Math.cos(rad);\n let y = Math.sin(rad);\n stream.pushVertex(x * SHADOW_INNER_RADIUS, SHADOW_GROUND_OFFSET, y * SHADOW_INNER_RADIUS, SHADOW_INNER_ALPHA);\n stream.pushVertex(x * SHADOW_OUTER_RADIUS, SHADOW_GROUND_OFFSET, y * SHADOW_OUTER_RADIUS, SHADOW_OUTER_ALPHA);\n\n if (i > 0) {\n // Inner circle\n stream.pushTriangle(0, idx, idx-2);\n\n // Outer circle\n stream.pushTriangle(idx, idx+1, idx-1);\n stream.pushTriangle(idx, idx-1, idx-2);\n }\n }\n\n stream.pushTriangle(0, 1, idx);\n\n stream.pushTriangle(1, 2, idx+1);\n stream.pushTriangle(1, idx+1, idx);\n\n stream.endGeometry();\n\n let shadowPrimitive = stream.finishPrimitive(renderer);\n this._shadowRenderPrimitive = renderer.createRenderPrimitive(shadowPrimitive, new DropShadowMaterial());\n this.addRenderPrimitive(this._shadowRenderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Node} from '../core/node.js';\nimport {Gltf2Loader} from '../loaders/gltf2.js';\n\n// Using a weak map here allows us to cache a loader per-renderer without\n// modifying the renderer object or leaking memory when it's garbage collected.\nlet gltfLoaderMap = new WeakMap();\n\nexport class Gltf2Node extends Node {\n constructor(options) {\n super();\n this._url = options.url;\n\n this._promise = null;\n this._resolver = null;\n this._rejecter = null;\n }\n\n onRendererChanged(renderer) {\n let loader = gltfLoaderMap.get(renderer);\n if (!loader) {\n loader = new Gltf2Loader(renderer);\n gltfLoaderMap.set(renderer, loader);\n }\n\n // Do we have a previously resolved promise? If so clear it.\n if (!this._resolver && this._promise) {\n this._promise = null;\n }\n\n this._ensurePromise();\n\n loader.loadFromUrl(this._url).then((sceneNode) => {\n this.addNode(sceneNode);\n this._resolver(sceneNode.waitForComplete());\n this._resolver = null;\n this._rejecter = null;\n }).catch((err) => {\n this._rejecter(err);\n this._resolver = null;\n this._rejecter = null;\n });\n }\n\n _ensurePromise() {\n if (!this._promise) {\n this._promise = new Promise((resolve, reject) => {\n this._resolver = resolve;\n this._rejecter = reject;\n });\n }\n return this._promise;\n }\n\n waitForComplete() {\n return this._ensurePromise();\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material, RENDER_ORDER} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {DataTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\n// Laser texture data, 48x1 RGBA (not premultiplied alpha). This represents a\n// \"cross section\" of the laser beam with a bright core and a feathered edge.\n// Borrowed from Chromium source code.\nconst LASER_TEXTURE_DATA = new Uint8Array([\n0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x02, 0xbf, 0xbf, 0xbf, 0x04, 0xcc, 0xcc, 0xcc, 0x05,\n0xdb, 0xdb, 0xdb, 0x07, 0xcc, 0xcc, 0xcc, 0x0a, 0xd8, 0xd8, 0xd8, 0x0d, 0xd2, 0xd2, 0xd2, 0x11,\n0xce, 0xce, 0xce, 0x15, 0xce, 0xce, 0xce, 0x1a, 0xce, 0xce, 0xce, 0x1f, 0xcd, 0xcd, 0xcd, 0x24,\n0xc8, 0xc8, 0xc8, 0x2a, 0xc9, 0xc9, 0xc9, 0x2f, 0xc9, 0xc9, 0xc9, 0x34, 0xc9, 0xc9, 0xc9, 0x39,\n0xc9, 0xc9, 0xc9, 0x3d, 0xc8, 0xc8, 0xc8, 0x41, 0xcb, 0xcb, 0xcb, 0x44, 0xee, 0xee, 0xee, 0x87,\n0xfa, 0xfa, 0xfa, 0xc8, 0xf9, 0xf9, 0xf9, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xfa, 0xfa, 0xfa, 0xc9,\n0xfa, 0xfa, 0xfa, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xfa, 0xfa, 0xfa, 0xc8,\n0xee, 0xee, 0xee, 0x87, 0xcb, 0xcb, 0xcb, 0x44, 0xc8, 0xc8, 0xc8, 0x41, 0xc9, 0xc9, 0xc9, 0x3d,\n0xc9, 0xc9, 0xc9, 0x39, 0xc9, 0xc9, 0xc9, 0x34, 0xc9, 0xc9, 0xc9, 0x2f, 0xc8, 0xc8, 0xc8, 0x2a,\n0xcd, 0xcd, 0xcd, 0x24, 0xce, 0xce, 0xce, 0x1f, 0xce, 0xce, 0xce, 0x1a, 0xce, 0xce, 0xce, 0x15,\n0xd2, 0xd2, 0xd2, 0x11, 0xd8, 0xd8, 0xd8, 0x0d, 0xcc, 0xcc, 0xcc, 0x0a, 0xdb, 0xdb, 0xdb, 0x07,\n0xcc, 0xcc, 0xcc, 0x05, 0xbf, 0xbf, 0xbf, 0x04, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0x01,\n]);\n\nconst LASER_LENGTH = 1.0;\nconst LASER_DIAMETER = 0.01;\nconst LASER_FADE_END = 0.535;\nconst LASER_FADE_POINT = 0.5335;\nconst LASER_DEFAULT_COLOR = [1.0, 1.0, 1.0, 0.25];\n\nconst CURSOR_RADIUS = 0.004;\nconst CURSOR_SHADOW_RADIUS = 0.007;\nconst CURSOR_SHADOW_INNER_LUMINANCE = 0.5;\nconst CURSOR_SHADOW_OUTER_LUMINANCE = 0.0;\nconst CURSOR_SHADOW_INNER_OPACITY = 0.75;\nconst CURSOR_SHADOW_OUTER_OPACITY = 0.0;\nconst CURSOR_OPACITY = 0.9;\nconst CURSOR_SEGMENTS = 16;\nconst CURSOR_DEFAULT_COLOR = [1.0, 1.0, 1.0, 1.0];\nconst CURSOR_DEFAULT_HIDDEN_COLOR = [0.5, 0.5, 0.5, 0.25];\n\nconst DEFAULT_RESET_OPTIONS = {\n controllers: true,\n lasers: true,\n cursors: true,\n};\n\nclass LaserMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.ADDITIVE;\n this.state.cullFace = false;\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.blendFuncDst = GL.ONE;\n this.state.depthMask = false;\n\n this.laser = this.defineSampler('diffuse');\n this.laser.texture = new DataTexture(LASER_TEXTURE_DATA, 48, 1);\n this.laserColor = this.defineUniform('laserColor', LASER_DEFAULT_COLOR);\n }\n\n get materialName() {\n return 'INPUT_LASER';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n\n uniform vec4 laserColor;\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n const float fadePoint = ${LASER_FADE_POINT};\n const float fadeEnd = ${LASER_FADE_END};\n\n vec4 fragment_main() {\n vec2 uv = vTexCoord;\n float front_fade_factor = 1.0 - clamp(1.0 - (uv.y - fadePoint) / (1.0 - fadePoint), 0.0, 1.0);\n float back_fade_factor = clamp((uv.y - fadePoint) / (fadeEnd - fadePoint), 0.0, 1.0);\n vec4 color = laserColor * texture2D(diffuse, vTexCoord);\n float opacity = color.a * front_fade_factor * back_fade_factor;\n return vec4(color.rgb * opacity, opacity);\n }`;\n }\n}\n\nconst CURSOR_VERTEX_SHADER = `\nattribute vec4 POSITION;\n\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vLuminance = POSITION.z;\n vOpacity = POSITION.w;\n\n // Billboarded, constant size vertex transform.\n vec4 screenPos = proj * view * model * vec4(0.0, 0.0, 0.0, 1.0);\n screenPos /= screenPos.w;\n screenPos.xy += POSITION.xy;\n return screenPos;\n}`;\n\nconst CURSOR_FRAGMENT_SHADER = `\nprecision mediump float;\n\nuniform vec4 cursorColor;\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 fragment_main() {\n vec3 color = cursorColor.rgb * vLuminance;\n float opacity = cursorColor.a * vOpacity;\n return vec4(color * opacity, opacity);\n}`;\n\n// Cursors are drawn as billboards that always face the camera and are rendered\n// as a fixed size no matter how far away they are.\nclass CursorMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.ADDITIVE;\n this.state.cullFace = false;\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.depthMask = false;\n\n this.cursorColor = this.defineUniform('cursorColor', CURSOR_DEFAULT_COLOR);\n }\n\n get materialName() {\n return 'INPUT_CURSOR';\n }\n\n get vertexSource() {\n return CURSOR_VERTEX_SHADER;\n }\n\n get fragmentSource() {\n return CURSOR_FRAGMENT_SHADER;\n }\n}\n\nclass CursorHiddenMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.ADDITIVE;\n this.state.cullFace = false;\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.depthFunc = GL.GEQUAL;\n this.state.depthMask = false;\n\n this.cursorColor = this.defineUniform('cursorColor', CURSOR_DEFAULT_HIDDEN_COLOR);\n }\n\n // TODO: Rename to \"program_name\"\n get materialName() {\n return 'INPUT_CURSOR_2';\n }\n\n get vertexSource() {\n return CURSOR_VERTEX_SHADER;\n }\n\n get fragmentSource() {\n return CURSOR_FRAGMENT_SHADER;\n }\n}\n\nexport class InputRenderer extends Node {\n constructor() {\n super();\n\n this._maxInputElements = 32;\n\n this._controllers = [];\n this._controllerNode = null;\n this._controllerNodeHandedness = null;\n this._lasers = null;\n this._cursors = null;\n\n this._activeControllers = 0;\n this._activeLasers = 0;\n this._activeCursors = 0;\n }\n\n onRendererChanged(renderer) {\n this._controllers = [];\n this._controllerNode = null;\n this._controllerNodeHandedness = null;\n this._lasers = null;\n this._cursors = null;\n\n this._activeControllers = 0;\n this._activeLasers = 0;\n this._activeCursors = 0;\n }\n\n setControllerMesh(controllerNode, handedness = 'right') {\n this._controllerNode = controllerNode;\n this._controllerNode.visible = false;\n // FIXME: Temporary fix to initialize for cloning.\n this.addNode(this._controllerNode);\n this._controllerNodeHandedness = handedness;\n }\n\n addController(gripMatrix) {\n if (!this._controllerNode) {\n return;\n }\n\n let controller = null;\n if (this._activeControllers < this._controllers.length) {\n controller = this._controllers[this._activeControllers];\n } else {\n controller = this._controllerNode.clone();\n this.addNode(controller);\n this._controllers.push(controller);\n }\n this._activeControllers = (this._activeControllers + 1) % this._maxInputElements;\n\n controller.matrix = gripMatrix;\n controller.visible = true;\n }\n\n addLaserPointer(targetRay) {\n // Create the laser pointer mesh if needed.\n if (!this._lasers && this._renderer) {\n this._lasers = [this._createLaserMesh()];\n this.addNode(this._lasers[0]);\n }\n\n let laser = null;\n if (this._activeLasers < this._lasers.length) {\n laser = this._lasers[this._activeLasers];\n } else {\n laser = this._lasers[0].clone();\n this.addNode(laser);\n this._lasers.push(laser);\n }\n this._activeLasers = (this._activeLasers + 1) % this._maxInputElements;\n\n laser.matrix = targetRay.transformMatrix;\n laser.visible = true;\n }\n\n addCursor(cursorPos) {\n // Create the cursor mesh if needed.\n if (!this._cursors && this._renderer) {\n this._cursors = [this._createCursorMesh()];\n this.addNode(this._cursors[0]);\n }\n\n let cursor = null;\n if (this._activeCursors < this._cursors.length) {\n cursor = this._cursors[this._activeCursors];\n } else {\n cursor = this._cursors[0].clone();\n this.addNode(cursor);\n this._cursors.push(cursor);\n }\n this._activeCursors = (this._activeCursors + 1) % this._maxInputElements;\n\n cursor.translation = cursorPos;\n cursor.visible = true;\n }\n\n reset(options) {\n if (!options) {\n options = DEFAULT_RESET_OPTIONS;\n }\n if (this._controllers && options.controllers) {\n for (let controller of this._controllers) {\n controller.visible = false;\n }\n this._activeControllers = 0;\n }\n if (this._lasers && options.lasers) {\n for (let laser of this._lasers) {\n laser.visible = false;\n }\n this._activeLasers = 0;\n }\n if (this._cursors && options.cursors) {\n for (let cursor of this._cursors) {\n cursor.visible = false;\n }\n this._activeCursors = 0;\n }\n }\n\n _createLaserMesh() {\n let gl = this._renderer._gl;\n\n let lr = LASER_DIAMETER * 0.5;\n let ll = LASER_LENGTH;\n\n // Laser is rendered as cross-shaped beam\n let laserVerts = [\n // X Y Z U V\n 0.0, lr, 0.0, 0.0, 1.0,\n 0.0, lr, -ll, 0.0, 0.0,\n 0.0, -lr, 0.0, 1.0, 1.0,\n 0.0, -lr, -ll, 1.0, 0.0,\n\n lr, 0.0, 0.0, 0.0, 1.0,\n lr, 0.0, -ll, 0.0, 0.0,\n -lr, 0.0, 0.0, 1.0, 1.0,\n -lr, 0.0, -ll, 1.0, 0.0,\n\n 0.0, -lr, 0.0, 0.0, 1.0,\n 0.0, -lr, -ll, 0.0, 0.0,\n 0.0, lr, 0.0, 1.0, 1.0,\n 0.0, lr, -ll, 1.0, 0.0,\n\n -lr, 0.0, 0.0, 0.0, 1.0,\n -lr, 0.0, -ll, 0.0, 0.0,\n lr, 0.0, 0.0, 1.0, 1.0,\n lr, 0.0, -ll, 1.0, 0.0,\n ];\n let laserIndices = [\n 0, 1, 2, 1, 3, 2,\n 4, 5, 6, 5, 7, 6,\n 8, 9, 10, 9, 11, 10,\n 12, 13, 14, 13, 15, 14,\n ];\n\n let laserVertexBuffer = this._renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(laserVerts));\n let laserIndexBuffer = this._renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(laserIndices));\n\n let laserIndexCount = laserIndices.length;\n\n let laserAttribs = [\n new PrimitiveAttribute('POSITION', laserVertexBuffer, 3, gl.FLOAT, 20, 0),\n new PrimitiveAttribute('TEXCOORD_0', laserVertexBuffer, 2, gl.FLOAT, 20, 12),\n ];\n\n let laserPrimitive = new Primitive(laserAttribs, laserIndexCount);\n laserPrimitive.setIndexBuffer(laserIndexBuffer);\n\n let laserMaterial = new LaserMaterial();\n\n let laserRenderPrimitive = this._renderer.createRenderPrimitive(laserPrimitive, laserMaterial);\n let meshNode = new Node();\n meshNode.addRenderPrimitive(laserRenderPrimitive);\n return meshNode;\n }\n\n _createCursorMesh() {\n let gl = this._renderer._gl;\n\n // Cursor is a circular white dot with a dark \"shadow\" skirt around the edge\n // that fades from black to transparent as it moves out from the center.\n // Cursor verts are packed as [X, Y, Luminance, Opacity]\n let cursorVerts = [];\n let cursorIndices = [];\n\n let segRad = (2.0 * Math.PI) / CURSOR_SEGMENTS;\n\n // Cursor center\n for (let i = 0; i < CURSOR_SEGMENTS; ++i) {\n let rad = i * segRad;\n let x = Math.cos(rad);\n let y = Math.sin(rad);\n cursorVerts.push(x * CURSOR_RADIUS, y * CURSOR_RADIUS, 1.0, CURSOR_OPACITY);\n\n if (i > 1) {\n cursorIndices.push(0, i-1, i);\n }\n }\n\n let indexOffset = CURSOR_SEGMENTS;\n\n // Cursor Skirt\n for (let i = 0; i < CURSOR_SEGMENTS; ++i) {\n let rad = i * segRad;\n let x = Math.cos(rad);\n let y = Math.sin(rad);\n cursorVerts.push(x * CURSOR_RADIUS, y * CURSOR_RADIUS,\n CURSOR_SHADOW_INNER_LUMINANCE, CURSOR_SHADOW_INNER_OPACITY);\n cursorVerts.push(x * CURSOR_SHADOW_RADIUS, y * CURSOR_SHADOW_RADIUS,\n CURSOR_SHADOW_OUTER_LUMINANCE, CURSOR_SHADOW_OUTER_OPACITY);\n\n if (i > 0) {\n let idx = indexOffset + (i * 2);\n cursorIndices.push(idx-2, idx-1, idx);\n cursorIndices.push(idx-1, idx+1, idx);\n }\n }\n\n let idx = indexOffset + (CURSOR_SEGMENTS * 2);\n cursorIndices.push(idx-2, idx-1, indexOffset);\n cursorIndices.push(idx-1, indexOffset+1, indexOffset);\n\n let cursorVertexBuffer = this._renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(cursorVerts));\n let cursorIndexBuffer = this._renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cursorIndices));\n\n let cursorIndexCount = cursorIndices.length;\n\n let cursorAttribs = [\n new PrimitiveAttribute('POSITION', cursorVertexBuffer, 4, gl.FLOAT, 16, 0),\n ];\n\n let cursorPrimitive = new Primitive(cursorAttribs, cursorIndexCount);\n cursorPrimitive.setIndexBuffer(cursorIndexBuffer);\n\n let cursorMaterial = new CursorMaterial();\n let cursorHiddenMaterial = new CursorHiddenMaterial();\n\n // Cursor renders two parts: The bright opaque cursor for areas where it's\n // not obscured and a more transparent, darker version for areas where it's\n // behind another object.\n let cursorRenderPrimitive = this._renderer.createRenderPrimitive(cursorPrimitive, cursorMaterial);\n let cursorHiddenRenderPrimitive = this._renderer.createRenderPrimitive(cursorPrimitive, cursorHiddenMaterial);\n let meshNode = new Node();\n meshNode.addRenderPrimitive(cursorRenderPrimitive);\n meshNode.addRenderPrimitive(cursorHiddenRenderPrimitive);\n return meshNode;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nRenders simple text using a seven-segment LED style pattern. Only really good\nfor numbers and a limited number of other characters.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\n\nconst TEXT_KERNING = 2.0;\n\nclass SevenSegmentMaterial extends Material {\n get materialName() {\n return 'SEVEN_SEGMENT_TEXT';\n }\n\n get vertexSource() {\n return `\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 0.0, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n const vec4 color = vec4(0.0, 1.0, 0.0, 1.0);\n\n vec4 fragment_main() {\n return color;\n }`;\n }\n}\n\nexport class SevenSegmentText extends Node {\n constructor() {\n super();\n\n this._text = '';\n this._charNodes = [];\n }\n\n onRendererChanged(renderer) {\n this.clearNodes();\n this._charNodes = [];\n\n let vertices = [];\n let segmentIndices = {};\n let indices = [];\n\n const width = 0.5;\n const thickness = 0.25;\n\n function defineSegment(id, left, top, right, bottom) {\n let idx = vertices.length / 2;\n vertices.push(\n left, top,\n right, top,\n right, bottom,\n left, bottom);\n\n segmentIndices[id] = [\n idx, idx+2, idx+1,\n idx, idx+3, idx+2,\n ];\n }\n\n let characters = {};\n function defineCharacter(c, segments) {\n let character = {\n character: c,\n offset: indices.length * 2,\n count: 0,\n };\n\n for (let i = 0; i < segments.length; ++i) {\n let idx = segments[i];\n let segment = segmentIndices[idx];\n character.count += segment.length;\n indices.push(...segment);\n }\n\n characters[c] = character;\n }\n\n /* Segment layout is as follows:\n\n |-0-|\n 3 4\n |-1-|\n 5 6\n |-2-|\n\n */\n\n defineSegment(0, -1, 1, width, 1-thickness);\n defineSegment(1, -1, thickness*0.5, width, -thickness*0.5);\n defineSegment(2, -1, -1+thickness, width, -1);\n defineSegment(3, -1, 1, -1+thickness, -thickness*0.5);\n defineSegment(4, width-thickness, 1, width, -thickness*0.5);\n defineSegment(5, -1, thickness*0.5, -1+thickness, -1);\n defineSegment(6, width-thickness, thickness*0.5, width, -1);\n\n\n defineCharacter('0', [0, 2, 3, 4, 5, 6]);\n defineCharacter('1', [4, 6]);\n defineCharacter('2', [0, 1, 2, 4, 5]);\n defineCharacter('3', [0, 1, 2, 4, 6]);\n defineCharacter('4', [1, 3, 4, 6]);\n defineCharacter('5', [0, 1, 2, 3, 6]);\n defineCharacter('6', [0, 1, 2, 3, 5, 6]);\n defineCharacter('7', [0, 4, 6]);\n defineCharacter('8', [0, 1, 2, 3, 4, 5, 6]);\n defineCharacter('9', [0, 1, 2, 3, 4, 6]);\n defineCharacter('A', [0, 1, 3, 4, 5, 6]);\n defineCharacter('B', [1, 2, 3, 5, 6]);\n defineCharacter('C', [0, 2, 3, 5]);\n defineCharacter('D', [1, 2, 4, 5, 6]);\n defineCharacter('E', [0, 1, 2, 4, 6]);\n defineCharacter('F', [0, 1, 3, 5]);\n defineCharacter('P', [0, 1, 3, 4, 5]);\n defineCharacter('-', [1]);\n defineCharacter(' ', []);\n defineCharacter('_', [2]); // Used for undefined characters\n\n let gl = renderer.gl;\n let vertexBuffer = renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(vertices));\n let indexBuffer = renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let vertexAttribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 2, gl.FLOAT, 8, 0),\n ];\n\n let primitive = new Primitive(vertexAttribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n\n let material = new SevenSegmentMaterial();\n\n this._charPrimitives = {};\n for (let char in characters) {\n let charDef = characters[char];\n primitive.elementCount = charDef.count;\n primitive.indexByteOffset = charDef.offset;\n this._charPrimitives[char] = renderer.createRenderPrimitive(primitive, material);\n }\n\n this.text = this._text;\n }\n\n get text() {\n return this._text;\n }\n\n set text(value) {\n this._text = value;\n\n let i = 0;\n let charPrimitive = null;\n for (; i < value.length; ++i) {\n if (value[i] in this._charPrimitives) {\n charPrimitive = this._charPrimitives[value[i]];\n } else {\n charPrimitive = this._charPrimitives['_'];\n }\n\n if (this._charNodes.length <= i) {\n let node = new Node();\n node.addRenderPrimitive(charPrimitive);\n let offset = i * TEXT_KERNING;\n node.translation = [offset, 0, 0];\n this._charNodes.push(node);\n this.addNode(node);\n } else {\n // This is sort of an abuse of how these things are expected to work,\n // but it's the cheapest thing I could think of that didn't break the\n // world.\n this._charNodes[i].clearRenderPrimitives();\n this._charNodes[i].addRenderPrimitive(charPrimitive);\n this._charNodes[i].visible = true;\n }\n }\n\n // If there's any nodes left over make them invisible\n for (; i < this._charNodes.length; ++i) {\n this._charNodes[i].visible = false;\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nNode for displaying 360 equirect images as a skybox.\n*/\n\nimport {Material, RENDER_ORDER} from '../core/material.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {Node} from '../core/node.js';\nimport {UrlTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nclass SkyboxMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.SKY;\n this.state.depthFunc = GL.LEQUAL;\n this.state.depthMask = false;\n\n this.image = this.defineSampler('diffuse');\n\n this.texCoordScaleOffset = this.defineUniform('texCoordScaleOffset',\n [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0], 4);\n }\n\n get materialName() {\n return 'SKYBOX';\n }\n\n get vertexSource() {\n return `\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n // Drop the translation portion of the view matrix\n view[3].xyz = vec3(0.0, 0.0, 0.0);\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n\n // Returning the W component for both Z and W forces the geometry depth to\n // the far plane. When combined with a depth func of LEQUAL this makes the\n // sky write to any depth fragment that has not been written to yet.\n return out_vec.xyww;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }`;\n }\n}\n\nexport class SkyboxNode extends Node {\n constructor(options) {\n super();\n\n this._url = options.url;\n this._displayMode = options.displayMode || 'mono';\n this._rotationY = options.rotationY || 0;\n }\n\n onRendererChanged(renderer) {\n let vertices = [];\n let indices = [];\n\n let latSegments = 40;\n let lonSegments = 40;\n\n // Create the vertices/indices\n for (let i=0; i <= latSegments; ++i) {\n let theta = i * Math.PI / latSegments;\n let sinTheta = Math.sin(theta);\n let cosTheta = Math.cos(theta);\n\n let idxOffsetA = i * (lonSegments+1);\n let idxOffsetB = (i+1) * (lonSegments+1);\n\n for (let j=0; j <= lonSegments; ++j) {\n let phi = (j * 2 * Math.PI / lonSegments) + this._rotationY;\n let x = Math.sin(phi) * sinTheta;\n let y = cosTheta;\n let z = -Math.cos(phi) * sinTheta;\n let u = (j / lonSegments);\n let v = (i / latSegments);\n\n // Vertex shader will force the geometry to the far plane, so the\n // radius of the sphere is immaterial.\n vertices.push(x, y, z, u, v);\n\n if (i < latSegments && j < lonSegments) {\n let idxA = idxOffsetA+j;\n let idxB = idxOffsetB+j;\n\n indices.push(idxA, idxB, idxA+1,\n idxB, idxB+1, idxA+1);\n }\n }\n }\n\n let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(vertices));\n let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 20, 0),\n new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 20, 12),\n ];\n\n let primitive = new Primitive(attribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n\n let material = new SkyboxMaterial();\n material.image.texture = new UrlTexture(this._url);\n\n switch (this._displayMode) {\n case 'mono':\n material.texCoordScaleOffset.value = [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0];\n break;\n case 'stereoTopBottom':\n material.texCoordScaleOffset.value = [1.0, 0.5, 0.0, 0.0,\n 1.0, 0.5, 0.0, 0.5];\n break;\n case 'stereoLeftRight':\n material.texCoordScaleOffset.value = [0.5, 1.0, 0.0, 0.0,\n 0.5, 1.0, 0.5, 0.0];\n break;\n }\n\n let renderPrimitive = renderer.createRenderPrimitive(primitive, material);\n this.addRenderPrimitive(renderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nHeavily inspired by Mr. Doobs stats.js, this FPS counter is rendered completely\nwith WebGL, allowing it to be shown in cases where overlaid HTML elements aren't\nusable (like WebXR), or if you want the FPS counter to be rendered as part of\nyour scene.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {SevenSegmentText} from './seven-segment-text.js';\n\nconst SEGMENTS = 30;\nconst MAX_FPS = 90;\n\nclass StatsMaterial extends Material {\n get materialName() {\n return 'STATS_VIEWER';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec3 COLOR_0;\n varying vec4 vColor;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vColor = vec4(COLOR_0, 1.0);\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n varying vec4 vColor;\n\n vec4 fragment_main() {\n return vColor;\n }`;\n }\n}\n\nfunction segmentToX(i) {\n return ((0.9/SEGMENTS) * i) - 0.45;\n}\n\nfunction fpsToY(value) {\n return (Math.min(value, MAX_FPS) * (0.7 / MAX_FPS)) - 0.45;\n}\n\nfunction fpsToRGB(value) {\n return {\n r: Math.max(0.0, Math.min(1.0, 1.0 - (value/60))),\n g: Math.max(0.0, Math.min(1.0, ((value-15)/(MAX_FPS-15)))),\n b: Math.max(0.0, Math.min(1.0, ((value-15)/(MAX_FPS-15)))),\n };\n}\n\nlet now = (window.performance && performance.now) ? performance.now.bind(performance) : Date.now;\n\nexport class StatsViewer extends Node {\n constructor() {\n super();\n\n this._performanceMonitoring = false;\n\n this._startTime = now();\n this._prevFrameTime = this._startTime;\n this._prevGraphUpdateTime = this._startTime;\n this._frames = 0;\n this._fpsAverage = 0;\n this._fpsMin = 0;\n this._fpsStep = this._performanceMonitoring ? 1000 : 250;\n this._lastSegment = 0;\n\n this._fpsVertexBuffer = null;\n this._fpsRenderPrimitive = null;\n this._fpsNode = null;\n\n this._sevenSegmentNode = new SevenSegmentText();\n // Hard coded because it doesn't change:\n // Scale by 0.075 in X and Y\n // Translate into upper left corner w/ z = 0.02\n this._sevenSegmentNode.matrix = new Float32Array([\n 0.075, 0, 0, 0,\n 0, 0.075, 0, 0,\n 0, 0, 1, 0,\n -0.3625, 0.3625, 0.02, 1,\n ]);\n }\n\n onRendererChanged(renderer) {\n this.clearNodes();\n\n let gl = renderer.gl;\n\n let fpsVerts = [];\n let fpsIndices = [];\n\n // Graph geometry\n for (let i = 0; i < SEGMENTS; ++i) {\n // Bar top\n fpsVerts.push(segmentToX(i), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n fpsVerts.push(segmentToX(i+1), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n\n // Bar bottom\n fpsVerts.push(segmentToX(i), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n fpsVerts.push(segmentToX(i+1), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n\n let idx = i * 4;\n fpsIndices.push(idx, idx+3, idx+1,\n idx+3, idx, idx+2);\n }\n\n function addBGSquare(left, bottom, right, top, z, r, g, b) {\n let idx = fpsVerts.length / 6;\n\n fpsVerts.push(left, bottom, z, r, g, b);\n fpsVerts.push(right, top, z, r, g, b);\n fpsVerts.push(left, top, z, r, g, b);\n fpsVerts.push(right, bottom, z, r, g, b);\n\n fpsIndices.push(idx, idx+1, idx+2,\n idx, idx+3, idx+1);\n }\n\n // Panel Background\n addBGSquare(-0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.125);\n\n // FPS Background\n addBGSquare(-0.45, -0.45, 0.45, 0.25, 0.01, 0.0, 0.0, 0.4);\n\n // 30 FPS line\n addBGSquare(-0.45, fpsToY(30), 0.45, fpsToY(32), 0.015, 0.5, 0.0, 0.5);\n\n // 60 FPS line\n addBGSquare(-0.45, fpsToY(60), 0.45, fpsToY(62), 0.015, 0.2, 0.0, 0.75);\n\n this._fpsVertexBuffer = renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(fpsVerts), gl.DYNAMIC_DRAW);\n let fpsIndexBuffer = renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(fpsIndices));\n\n let fpsAttribs = [\n new PrimitiveAttribute('POSITION', this._fpsVertexBuffer, 3, gl.FLOAT, 24, 0),\n new PrimitiveAttribute('COLOR_0', this._fpsVertexBuffer, 3, gl.FLOAT, 24, 12),\n ];\n\n let fpsPrimitive = new Primitive(fpsAttribs, fpsIndices.length);\n fpsPrimitive.setIndexBuffer(fpsIndexBuffer);\n fpsPrimitive.setBounds([-0.5, -0.5, 0.0], [0.5, 0.5, 0.015]);\n\n this._fpsRenderPrimitive = renderer.createRenderPrimitive(fpsPrimitive, new StatsMaterial());\n this._fpsNode = new Node();\n this._fpsNode.addRenderPrimitive(this._fpsRenderPrimitive);\n\n this.addNode(this._fpsNode);\n this.addNode(this._sevenSegmentNode);\n }\n\n get performanceMonitoring() {\n return this._performanceMonitoring;\n }\n\n set performanceMonitoring(value) {\n this._performanceMonitoring = value;\n this._fpsStep = value ? 1000 : 250;\n }\n\n begin() {\n this._startTime = now();\n }\n\n end() {\n let time = now();\n\n let frameFps = 1000 / (time - this._prevFrameTime);\n this._prevFrameTime = time;\n this._fpsMin = this._frames ? Math.min(this._fpsMin, frameFps) : frameFps;\n this._frames++;\n\n if (time > this._prevGraphUpdateTime + this._fpsStep) {\n let intervalTime = time - this._prevGraphUpdateTime;\n this._fpsAverage = Math.round(1000 / (intervalTime / this._frames));\n\n // Draw both average and minimum FPS for this period\n // so that dropped frames are more clearly visible.\n this._updateGraph(this._fpsMin, this._fpsAverage);\n if (this._performanceMonitoring) {\n console.log(`Average FPS: ${this._fpsAverage} Min FPS: ${this._fpsMin}`);\n }\n\n this._prevGraphUpdateTime = time;\n this._frames = 0;\n this._fpsMin = 0;\n }\n }\n\n _updateGraph(valueLow, valueHigh) {\n let color = fpsToRGB(valueLow);\n // Draw a range from the low to high value. Artificially widen the\n // range a bit to ensure that near-equal values still remain\n // visible - the logic here should match that used by the\n // \"60 FPS line\" setup below. Hitting 60fps consistently will\n // keep the top half of the 60fps background line visible.\n let y0 = fpsToY(valueLow - 1);\n let y1 = fpsToY(valueHigh + 1);\n\n // Update the current segment with the new FPS value\n let updateVerts = [\n segmentToX(this._lastSegment), y1, 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1), y1, 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment), y0, 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1), y0, 0.02, color.r, color.g, color.b,\n ];\n\n // Re-shape the next segment into the green \"progress\" line\n color.r = 0.2;\n color.g = 1.0;\n color.b = 0.2;\n\n if (this._lastSegment == SEGMENTS - 1) {\n // If we're updating the last segment we need to do two bufferSubDatas\n // to update the segment and turn the first segment into the progress line.\n this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts),\n this._lastSegment * 24 * 4);\n updateVerts = [\n segmentToX(0), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(.25), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(0), fpsToY(0), 0.02, color.r, color.g, color.b,\n segmentToX(.25), fpsToY(0), 0.02, color.r, color.g, color.b,\n ];\n this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts), 0);\n } else {\n updateVerts.push(\n segmentToX(this._lastSegment+1), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1.25), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1), fpsToY(0), 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1.25), fpsToY(0), 0.02, color.r, color.g, color.b\n );\n this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts),\n this._lastSegment * 24 * 4);\n }\n\n this._lastSegment = (this._lastSegment+1) % SEGMENTS;\n\n this._sevenSegmentNode.text = `${this._fpsAverage} FP5`;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nNode for displaying 2D or stereo videos on a quad.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {Node} from '../core/node.js';\nimport {VideoTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nclass VideoMaterial extends Material {\n constructor() {\n super();\n\n this.image = this.defineSampler('diffuse');\n\n this.texCoordScaleOffset = this.defineUniform('texCoordScaleOffset',\n [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0], 4);\n }\n\n get materialName() {\n return 'VIDEO_PLAYER';\n }\n\n get vertexSource() {\n return `\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n return out_vec;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }`;\n }\n}\n\nexport class VideoNode extends Node {\n constructor(options) {\n super();\n\n this._video = options.video;\n this._displayMode = options.displayMode || 'mono';\n\n this._video_texture = new VideoTexture(this._video);\n }\n\n get aspectRatio() {\n let width = this._video.videoWidth;\n let height = this._video.videoHeight;\n\n switch (this._displayMode) {\n case 'stereoTopBottom': height *= 0.5; break;\n case 'stereoLeftRight': width *= 0.5; break;\n }\n\n if (!height || !width) {\n return 1;\n }\n\n return width / height;\n }\n\n onRendererChanged(renderer) {\n let vertices = [\n -1.0, 1.0, 0.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 1.0, 0.0,\n 1.0, -1.0, 0.0, 1.0, 1.0,\n -1.0, -1.0, 0.0, 0.0, 1.0,\n ];\n let indices = [\n 0, 2, 1,\n 0, 3, 2,\n ];\n\n let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(vertices));\n let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 20, 0),\n new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 20, 12),\n ];\n\n let primitive = new Primitive(attribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n primitive.setBounds([-1.0, -1.0, 0.0], [1.0, 1.0, 0.015]);\n\n let material = new VideoMaterial();\n material.image.texture = this._video_texture;\n\n switch (this._displayMode) {\n case 'mono':\n material.texCoordScaleOffset.value = [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0];\n break;\n case 'stereoTopBottom':\n material.texCoordScaleOffset.value = [1.0, 0.5, 0.0, 0.0,\n 1.0, 0.5, 0.0, 0.5];\n break;\n case 'stereoLeftRight':\n material.texCoordScaleOffset.value = [0.5, 1.0, 0.0, 0.0,\n 0.5, 1.0, 0.5, 0.0];\n break;\n }\n\n let renderPrimitive = renderer.createRenderPrimitive(primitive, material);\n this.addRenderPrimitive(renderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {RenderView} from '../core/renderer.js';\nimport {InputRenderer} from '../nodes/input-renderer.js';\nimport {StatsViewer} from '../nodes/stats-viewer.js';\nimport {Node} from '../core/node.js';\nimport {vec3, quat} from '../math/gl-matrix.js';\n\nexport class WebXRView extends RenderView {\n constructor(view, pose, layer) {\n super(\n view ? view.projectionMatrix : null,\n (pose && view) ? pose.getViewMatrix(view) : null,\n (layer && view) ? layer.getViewport(view) : null,\n view ? view.eye : 'left'\n );\n }\n}\n\nexport class Scene extends Node {\n constructor() {\n super();\n\n this._timestamp = -1;\n this._frameDelta = 0;\n this._statsStanding = false;\n this._stats = null;\n this._statsEnabled = false;\n this.enableStats(true); // Ensure the stats are added correctly by default.\n\n this._inputRenderer = null;\n this._resetInputEndFrame = true;\n\n this._lastTimestamp = 0;\n\n this._hoverFrame = 0;\n this._hoveredNodes = [];\n\n this.clear = true;\n }\n\n setRenderer(renderer) {\n this._setRenderer(renderer);\n }\n\n loseRenderer() {\n if (this._renderer) {\n this._stats = null;\n this._renderer = null;\n this._inputRenderer = null;\n }\n }\n\n get inputRenderer() {\n if (!this._inputRenderer) {\n this._inputRenderer = new InputRenderer();\n this.addNode(this._inputRenderer);\n }\n return this._inputRenderer;\n }\n\n // Helper function that automatically adds the appropriate visual elements for\n // all input sources.\n updateInputSources(frame, frameOfRef) {\n // FIXME: Check for the existence of the API first. This check should be\n // removed once the input API is part of the official spec.\n if (!frame.session.getInputSources) {\n return;\n }\n\n let inputSources = frame.session.getInputSources();\n\n let newHoveredNodes = [];\n let lastHoverFrame = this._hoverFrame;\n this._hoverFrame++;\n\n for (let inputSource of inputSources) {\n let inputPose = frame.getInputPose(inputSource, frameOfRef);\n\n if (!inputPose) {\n continue;\n }\n\n // Any time that we have a grip matrix, we'll render a controller.\n if (inputPose.gripMatrix) {\n this.inputRenderer.addController(inputPose.gripMatrix);\n }\n\n if (inputPose.targetRay) {\n if (inputSource.targetRayMode == 'tracked-pointer') {\n // If we have a pointer matrix and the pointer origin is the users\n // hand (as opposed to their head or the screen) use it to render\n // a ray coming out of the input device to indicate the pointer\n // direction.\n this.inputRenderer.addLaserPointer(inputPose.targetRay);\n }\n\n // If we have a pointer matrix we can also use it to render a cursor\n // for both handheld and gaze-based input sources.\n\n // Check and see if the pointer is pointing at any selectable objects.\n let hitResult = this.hitTest(inputPose.targetRay);\n\n if (hitResult) {\n // Render a cursor at the intersection point.\n this.inputRenderer.addCursor(hitResult.intersection);\n\n if (hitResult.node._hoverFrameId != lastHoverFrame) {\n hitResult.node.onHoverStart();\n }\n hitResult.node._hoverFrameId = this._hoverFrame;\n newHoveredNodes.push(hitResult.node);\n } else {\n // Statically render the cursor 1 meters down the ray since we didn't\n // hit anything selectable.\n let cursorDistance = 1.0;\n let cursorPos = vec3.fromValues(\n inputPose.targetRay.origin.x,\n inputPose.targetRay.origin.y,\n inputPose.targetRay.origin.z\n );\n vec3.add(cursorPos, cursorPos, [\n inputPose.targetRay.direction.x * cursorDistance,\n inputPose.targetRay.direction.y * cursorDistance,\n inputPose.targetRay.direction.z * cursorDistance,\n ]);\n // let cursorPos = vec3.fromValues(0, 0, -1.0);\n // vec3.transformMat4(cursorPos, cursorPos, inputPose.targetRay);\n this.inputRenderer.addCursor(cursorPos);\n }\n }\n }\n\n for (let hoverNode of this._hoveredNodes) {\n if (hoverNode._hoverFrameId != this._hoverFrame) {\n hoverNode.onHoverEnd();\n }\n }\n\n this._hoveredNodes = newHoveredNodes;\n }\n\n handleSelect(inputSource, frame, frameOfRef) {\n let inputPose = frame.getInputPose(inputSource, frameOfRef);\n\n if (!inputPose) {\n return;\n }\n\n this.handleSelectPointer(inputPose.targetRay);\n }\n\n handleSelectPointer(targetRay) {\n if (targetRay) {\n // Check and see if the pointer is pointing at any selectable objects.\n let hitResult = this.hitTest(targetRay);\n\n if (hitResult) {\n // Render a cursor at the intersection point.\n hitResult.node.handleSelect();\n }\n }\n }\n\n enableStats(enable) {\n if (enable == this._statsEnabled) {\n return;\n }\n\n this._statsEnabled = enable;\n\n if (enable) {\n this._stats = new StatsViewer();\n this._stats.selectable = true;\n this.addNode(this._stats);\n\n if (this._statsStanding) {\n this._stats.translation = [0, 1.4, -0.75];\n } else {\n this._stats.translation = [0, -0.3, -0.5];\n }\n this._stats.scale = [0.3, 0.3, 0.3];\n quat.fromEuler(this._stats.rotation, -45.0, 0.0, 0.0);\n } else if (!enable) {\n if (this._stats) {\n this.removeNode(this._stats);\n this._stats = null;\n }\n }\n }\n\n standingStats(enable) {\n this._statsStanding = enable;\n if (this._stats) {\n if (this._statsStanding) {\n this._stats.translation = [0, 1.4, -0.75];\n } else {\n this._stats.translation = [0, -0.3, -0.5];\n }\n this._stats.scale = [0.3, 0.3, 0.3];\n quat.fromEuler(this._stats.rotation, -45.0, 0.0, 0.0);\n }\n }\n\n draw(projectionMatrix, viewMatrix, eye) {\n let view = new RenderView();\n view.projectionMatrix = projectionMatrix;\n view.viewMatrix = viewMatrix;\n if (eye) {\n view.eye = eye;\n }\n\n this.drawViewArray([view]);\n }\n\n /** Draws the scene into the base layer of the XRFrame's session */\n drawXRFrame(xrFrame, pose) {\n if (!this._renderer || !pose) {\n return;\n }\n\n let gl = this._renderer.gl;\n let session = xrFrame.session;\n // Assumed to be a XRWebGLLayer for now.\n let layer = session.baseLayer;\n\n if (!gl) {\n return;\n }\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);\n\n if (this.clear) {\n gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n }\n\n let views = [];\n for (let view of xrFrame.views) {\n views.push(new WebXRView(view, pose, layer));\n }\n\n this.drawViewArray(views);\n }\n\n drawViewArray(views) {\n // Don't draw when we don't have a valid context\n if (!this._renderer) {\n return;\n }\n\n this._renderer.drawViews(views, this);\n }\n\n startFrame() {\n let prevTimestamp = this._timestamp;\n this._timestamp = performance.now();\n if (this._stats) {\n this._stats.begin();\n }\n\n if (prevTimestamp >= 0) {\n this._frameDelta = this._timestamp - prevTimestamp;\n } else {\n this._frameDelta = 0;\n }\n\n this._update(this._timestamp, this._frameDelta);\n\n return this._frameDelta;\n }\n\n endFrame() {\n if (this._inputRenderer && this._resetInputEndFrame) {\n this._inputRenderer.reset();\n }\n\n if (this._stats) {\n this._stats.end();\n }\n }\n\n // Override to load scene resources on construction or context restore.\n onLoadScene(renderer) {\n return Promise.resolve();\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {mat4} from '../math/gl-matrix.js';\n\nconst LOOK_SPEED = 0.0025;\n\nexport class FallbackHelper {\n constructor(scene, gl) {\n this.scene = scene;\n this.gl = gl;\n this._emulateStage = false;\n\n this.lookYaw = 0;\n this.lookPitch = 0;\n\n this.viewMatrix = mat4.create();\n\n let projectionMatrix = mat4.create();\n this.projectionMatrix = projectionMatrix;\n\n // Using a simple identity matrix for the view.\n mat4.identity(this.viewMatrix);\n\n // We need to track the canvas size in order to resize the WebGL\n // backbuffer width and height, as well as update the projection matrix\n // and adjust the viewport.\n function onResize() {\n gl.canvas.width = gl.canvas.offsetWidth * window.devicePixelRatio;\n gl.canvas.height = gl.canvas.offsetHeight * window.devicePixelRatio;\n mat4.perspective(projectionMatrix, Math.PI*0.4,\n gl.canvas.width/gl.canvas.height,\n 0.1, 1000.0);\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n }\n window.addEventListener('resize', onResize);\n onResize();\n\n // Upding the view matrix with touch or mouse events.\n let canvas = gl.canvas;\n let lastTouchX = 0;\n let lastTouchY = 0;\n canvas.addEventListener('touchstart', (ev) => {\n if (ev.touches.length == 2) {\n lastTouchX = ev.touches[1].pageX;\n lastTouchY = ev.touches[1].pageY;\n }\n });\n canvas.addEventListener('touchmove', (ev) => {\n // Rotate the view when two fingers are being used.\n if (ev.touches.length == 2) {\n this.onLook(ev.touches[1].pageX - lastTouchX, ev.touches[1].pageY - lastTouchY);\n lastTouchX = ev.touches[1].pageX;\n lastTouchY = ev.touches[1].pageY;\n }\n });\n canvas.addEventListener('mousemove', (ev) => {\n // Only rotate when the right button is pressed.\n if (ev.buttons & 2) {\n this.onLook(ev.movementX, ev.movementY);\n }\n });\n canvas.addEventListener('contextmenu', (ev) => {\n // Prevent context menus on the canvas so that we can use right click to rotate.\n ev.preventDefault();\n });\n\n this.boundOnFrame = this.onFrame.bind(this);\n window.requestAnimationFrame(this.boundOnFrame);\n }\n\n onLook(yaw, pitch) {\n this.lookYaw += yaw * LOOK_SPEED;\n this.lookPitch += pitch * LOOK_SPEED;\n\n // Clamp pitch rotation beyond looking straight up or down.\n if (this.lookPitch < -Math.PI*0.5) {\n this.lookPitch = -Math.PI*0.5;\n }\n if (this.lookPitch > Math.PI*0.5) {\n this.lookPitch = Math.PI*0.5;\n }\n\n this.updateView();\n }\n\n onFrame(t) {\n let gl = this.gl;\n window.requestAnimationFrame(this.boundOnFrame);\n\n this.scene.startFrame();\n\n // We can skip setting the framebuffer and viewport every frame, because\n // it won't change from frame to frame and we're updating the viewport\n // only when we resize for efficency.\n gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n\n // We're drawing with our own projection and view matrix now, and we\n // don't have a list of view to loop through, but otherwise all of the\n // WebGL drawing logic is exactly the same.\n this.scene.draw(this.projectionMatrix, this.viewMatrix);\n\n this.scene.endFrame();\n }\n\n get emulateStage() {\n return this._emulateStage;\n }\n\n set emulateStage(value) {\n this._emulateStage = value;\n this.updateView();\n }\n\n updateView() {\n mat4.identity(this.viewMatrix);\n\n mat4.rotateX(this.viewMatrix, this.viewMatrix, -this.lookPitch);\n mat4.rotateY(this.viewMatrix, this.viewMatrix, -this.lookYaw);\n\n // If we're emulating a stage frame of reference we'll need to move the view\n // matrix roughly a meter and a half up in the air.\n if (this._emulateStage) {\n mat4.translate(this.viewMatrix, this.viewMatrix, [0, -1.6, 0]);\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nProvides a simple way to get values from the query string if they're present\nand use a default value if not. Not strictly a \"WebGL\" utility, but I use it\nfrequently enough for debugging that I wanted to include it here.\n\nExample:\nFor the URL http://example.com/index.html?particleCount=1000\n\nQueryArgs.getInt(\"particleCount\", 100); // URL overrides, returns 1000\nQueryArgs.getInt(\"particleSize\", 10); // Not in URL, returns default of 10\n*/\n\nlet urlArgs = null;\nwindow.onhashchange = function() {\n // Force re-parsing on next access\n urlArgs = null;\n};\n\nfunction ensureArgsCached() {\n if (!urlArgs) {\n urlArgs = {};\n let query = window.location.search.substring(1) || window.location.hash.substring(1);\n let vars = query.split('&');\n for (let i = 0; i < vars.length; i++) {\n let pair = vars[i].split('=');\n urlArgs[pair[0].toLowerCase()] = decodeURIComponent(pair[1]);\n }\n }\n}\n\nexport class QueryArgs {\n static getString(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return urlArgs[lcaseName];\n }\n return defaultValue;\n }\n\n static getInt(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return parseInt(urlArgs[lcaseName], 10);\n }\n return defaultValue;\n }\n\n static getFloat(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return parseFloat(urlArgs[lcaseName]);\n }\n return defaultValue;\n }\n\n static getBool(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return parseInt(urlArgs[lcaseName], 10) != 0;\n }\n return defaultValue;\n }\n}\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap","webpack:///./node_modules/gl-matrix/src/gl-matrix/common.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat2.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat2d.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat3.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/mat4.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/quat.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/quat2.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/vec2.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/vec3.js","webpack:///./node_modules/gl-matrix/src/gl-matrix/vec4.js","webpack:///./src/core/material.js","webpack:///./src/core/node.js","webpack:///./src/core/primitive.js","webpack:///./src/core/program.js","webpack:///./src/core/renderer.js","webpack:///./src/core/texture.js","webpack:///./src/cottontail.js","webpack:///./src/geometry/box-builder.js","webpack:///./src/geometry/primitive-stream.js","webpack:///./src/loaders/gltf2.js","webpack:///./src/materials/pbr.js","webpack:///./src/math/gl-matrix.js","webpack:///./src/math/ray.js","webpack:///./src/nodes/bounds-renderer.js","webpack:///./src/nodes/button.js","webpack:///./src/nodes/cube-sea.js","webpack:///./src/nodes/drop-shadow.js","webpack:///./src/nodes/gltf2.js","webpack:///./src/nodes/input-renderer.js","webpack:///./src/nodes/seven-segment-text.js","webpack:///./src/nodes/skybox.js","webpack:///./src/nodes/stats-viewer.js","webpack:///./src/nodes/video.js","webpack:///./src/scenes/scene.js","webpack:///./src/util/fallback-helper.js","webpack:///./src/util/query-args.js"],"names":["stateToBlendFunc","GL","WebGLRenderingContext","CAP","CULL_FACE","BLEND","DEPTH_TEST","STENCIL_TEST","COLOR_MASK","DEPTH_MASK","STENCIL_MASK","MAT_STATE","CAPS_RANGE","BLEND_SRC_SHIFT","BLEND_SRC_RANGE","BLEND_DST_SHIFT","BLEND_DST_RANGE","BLEND_FUNC_RANGE","DEPTH_FUNC_SHIFT","DEPTH_FUNC_RANGE","RENDER_ORDER","OPAQUE","SKY","TRANSPARENT","ADDITIVE","DEFAULT","state","mask","shift","value","SRC_COLOR","MaterialState","_state","blendFuncSrc","SRC_ALPHA","blendFuncDst","ONE_MINUS_SRC_ALPHA","depthFunc","LESS","NEVER","MaterialSampler","uniformName","_uniformName","_texture","MaterialUniform","defaultValue","length","_value","_length","Array","Material","renderOrder","_samplers","_uniforms","sampler","push","uniform","renderPrimitive","DEFAULT_TRANSLATION","Float32Array","DEFAULT_ROTATION","DEFAULT_SCALE","tmpRayMatrix","mat4","create","Node","name","children","parent","visible","selectable","_matrix","_dirtyTRS","_translation","_rotation","_scale","_dirtyWorldMatrix","_worldMatrix","_activeFrameId","_hoverFrameId","_renderPrimitives","_renderer","_selectHandler","renderer","clearRenderPrimitives","onRendererChanged","child","_setRenderer","cloneNode","vec3","copy","quat","waitForComplete","then","primitive","addRenderPrimitive","addNode","clone","frameId","markActive","removeNode","i","indexOf","splice","setMatrixDirty","fromRotationTranslationScale","childPromises","Promise","all","_instances","index","ray","localRay","_min","invert","worldMatrix","multiply","transformMatrix","Ray","intersection","intersectsAABB","_max","transformMat4","_hitTestSelectableNode","origin","fromValues","x","y","z","node","distance","result","childResult","hitTest","timestamp","frameDelta","onUpdate","_update","_updateLocalMatrix","mul","PrimitiveAttribute","buffer","componentCount","componentType","stride","byteOffset","normalized","Primitive","attributes","elementCount","mode","indexBuffer","indexByteOffset","indexType","min","max","Program","gl","vertSrc","fragSrc","attribMap","defines","_gl","program","createProgram","attrib","_firstUse","_nextUseCallbacks","definesString","define","_vertShader","createShader","VERTEX_SHADER","attachShader","shaderSource","compileShader","_fragShader","FRAGMENT_SHADER","attribName","bindAttribLocation","linkProgram","callback","getProgramParameter","LINK_STATUS","getShaderParameter","COMPILE_STATUS","console","error","getShaderInfoLog","getProgramInfoLog","deleteProgram","attribCount","ACTIVE_ATTRIBUTES","attribInfo","getActiveAttrib","getAttribLocation","uniformCount","ACTIVE_UNIFORMS","uniformInfo","getActiveUniform","replace","getUniformLocation","deleteShader","useProgram","createWebGLContext","ATTRIB","POSITION","NORMAL","TANGENT","TEXCOORD_0","TEXCOORD_1","COLOR_0","ATTRIB_MASK","DEF_LIGHT_DIR","DEF_LIGHT_COLOR","PRECISION_REGEX","RegExp","VERTEX_SHADER_SINGLE_ENTRY","VERTEX_SHADER_MULTI_ENTRY","FRAGMENT_SHADER_ENTRY","isPowerOfTwo","n","glAttribs","alpha","webglCanvas","document","createElement","contextTypes","webgl2","context","contextType","getContext","webglType","RenderView","projectionMatrix","viewMatrix","viewport","eye","_eye","_eyeIndex","RenderBuffer","target","usage","_target","_usage","_buffer","_promise","resolve","RenderPrimitiveAttribute","primitiveAttribute","_attrib_index","_componentCount","_componentType","_stride","_byteOffset","_normalized","RenderPrimitiveAttributeBuffer","_attributes","RenderPrimitive","_material","setPrimitive","_mode","_elementCount","_vao","_complete","_attributeBuffers","_attributeMask","attribute","renderAttribute","foundBuffer","attributeBuffer","_indexBuffer","_indexByteOffset","_indexType","material","reject","completionPromises","_samplerDictionary","_uniform_dictionary","RenderTexture","texture","_activeCallback","inverseMatrix","setCap","glEnum","cap","prevState","change","enable","disable","RenderMaterialSampler","materialSampler","_renderTexture","_getRenderTexture","_index","RenderMaterialUniform","materialUniform","_uniform","RenderMaterial","_program","_completeForActiveFrame","renderSampler","renderUniform","_firstBind","_renderOrder","activeTexture","TEXTURE0","bindTexture","TEXTURE_2D","uniform1fv","uniform2fv","uniform3fv","uniform4fv","otherState","Renderer","_frameId","_programCache","_textureCache","_cameraPositions","_vaoExt","getExtension","fragHighPrecision","getShaderPrecisionFormat","HIGH_FLOAT","_defaultFragPrecision","precision","_depthMaskNeedsReset","_colorMaskNeedsReset","_globalLightColor","_globalLightDir","data","STATIC_DRAW","glBuffer","createBuffer","renderBuffer","bindBuffer","bufferData","byteLength","offset","bufferSubData","updateRenderBuffer","_getMaterialProgram","renderMaterial","setRenderMaterial","meshNode","createRenderPrimitive","views","rootNode","vp","width","height","cameraPosition","set","renderPrimitives","_drawRenderPrimitiveSet","bindVertexArrayOES","depthMask","colorMask","attribMask","use","LIGHT_DIRECTION","LIGHT_COLOR","uniformMatrix4fv","PROJECTION_MATRIX","VIEW_MATRIX","CAMERA_POSITION","uniform1i","EYE_INDEX","eyeIndex","_bindMaterialState","bind","createVertexArrayOES","_bindPrimitive","view","instance","MODEL_MATRIX","drawElements","drawArrays","key","textureKey","Error","textureHandle","createTexture","renderTexture","DataTexture","texImage2D","format","_type","_data","_setSamplerParameters","UNSIGNED_BYTE","source","VideoTexture","_video","addEventListener","paused","waiting","powerOfTwo","mipmap","generateMipmap","minFilter","LINEAR_MIPMAP_LINEAR","LINEAR","wrapS","REPEAT","CLAMP_TO_EDGE","wrapT","texParameteri","TEXTURE_MAG_FILTER","magFilter","TEXTURE_MIN_FILTER","TEXTURE_WRAP_S","TEXTURE_WRAP_T","materialName","vertexSource","fragmentSource","getProgramDefines","_getProgramKey","multiview","fullVertexSource","precisionMatch","match","fragPrecisionHeader","fullFragmentSource","onNextUse","enableVertexAttribArray","disableVertexAttribArray","ARRAY_BUFFER","vertexAttribPointer","ELEMENT_ARRAY_BUFFER","prevMaterial","_capsDiff","colorMaskChange","depthMaskChange","stencilMaskChange","stencilMask","_blendDiff","blendFunc","_depthFuncDiff","TextureSampler","Texture","RGBA","ImageTexture","img","_img","_imgBitmap","src","complete","naturalWidth","_finishImage","window","createImageBitmap","imgBitmap","UrlTexture","url","Image","BlobTexture","blob","URL","createObjectURL","video","readyState","videoWidth","videoHeight","nextDataTextureIndex","type","_width","_height","_format","_key","ColorTexture","r","g","b","a","colorData","Uint8Array","PrimitiveStream","BoxBuilder","PbrMaterial","mat3","vec4","BoundsRenderer","ButtonNode","DropShadowNode","CubeSeaNode","Gltf2Node","SkyboxNode","VideoNode","WebXRView","Scene","FallbackHelper","QueryArgs","stream","primitiveStream","w","h","d","wh","hh","dh","cx","cy","cz","startGeometry","idx","nextVertexIndex","pushTriangle","pushVertex","endGeometry","center","size","hs","pushBox","GeometryBuilderBase","tempVec3","options","_vertices","_indices","_geometryStarted","_vertexOffset","_vertexIndex","_highIndex","_flipWinding","_invertNormals","_transform","_normalTransform","u","v","nx","ny","nz","transformMat3","Math","idxA","idxB","idxC","vertexBuffer","createRenderBuffer","Uint16Array","attribs","FLOAT","setIndexBuffer","setBounds","fromMat4","_stream","finishPrimitive","clear","GLB_MAGIC","CHUNK_TYPE","JSON","BIN","isAbsoluteUri","uri","absRegEx","location","protocol","isDataUri","dataRegEx","resolveUri","baseUrl","getComponentCount","Gltf2Loader","fetch","response","lastIndexOf","substring","endsWith","json","loadFromJson","arrayBuffer","loadFromBinary","headerView","DataView","magic","getUint32","version","chunks","chunkOffset","chunkHeaderView","chunkLength","chunkType","slice","decoder","TextDecoder","jsonString","decode","parse","binaryChunk","asset","minVersion","buffers","Gltf2Resource","bufferViews","bufferView","Gltf2BufferView","images","image","textures","glTexture","getTexture","textureInfo","materials","glMaterial","pbr","pbrMetallicRoughness","baseColorFactor","baseColor","baseColorTexture","metallicRoughnessFactor","metallicFactor","roughnessFactor","metallicRoughness","metallicRoughnessTexture","normal","normalTexture","occlusion","occlusionTexture","occlusionStrength","strength","emissiveFactor","emissive","emissiveTexture","alphaMode","blend","cullFace","doubleSided","accessors","meshes","mesh","glMesh","Gltf2Mesh","primitives","accessor","count","glAttribute","byteStride","glPrimitive","indices","sceneNode","scene","scenes","nodes","nodeId","processNodes","glNode","matrix","translation","rotation","scale","_viewPromise","_renderBuffer","dataView","_dataPromise","base64String","binaryArray","from","atob","c","charCodeAt","Blob","mimeType","VERTEX_SOURCE","EPIC_PBR_FUNCTIONS","FRAGMENT_SOURCE","defineSampler","defineUniform","programDefines","glMatrix","mat2","mat2d","quat2","vec2","normalMat","RAY_INTERSECTION_OFFSET","_dir","dir","bounds","tmin","sign","inv_dir","tmax","tymin","tymax","tzmin","tzmax","t","intersectionPoint","add","normalize","BoundsMaterial","ONE","depthTest","_stageBounds","stageBounds","verts","pointCount","geometry","point","BUTTON_SIZE","BUTTON_CORNER_RADIUS","BUTTON_CORNER_SEGMENTS","BUTTON_ICON_SIZE","BUTTON_LAYER_DISTANCE","BUTTON_COLOR","BUTTON_ALPHA","BUTTON_HOVER_COLOR","BUTTON_HOVER_ALPHA","BUTTON_HOVER_SCALE","BUTTON_HOVER_TRANSITION_TIME_MS","ButtonMaterial","ButtonIconMaterial","icon","iconTexture","_iconTexture","_hovered","_hoverT","hd","ihs","segments","rad","PI","cos","sin","section","floor","buttonPrimitive","_buttonRenderPrimitive","iconPrimitive","iconMaterial","_iconRenderPrimitive","hoverAmount","uniforms","_updateHoverState","samplers","CubeSeaMaterial","heavy","heavyGpu","cubeCount","cubeScale","halfOnly","autoRotate","imageUrl","_renderPrimitive","boxBuilder","pushCube","heroPrimitive","heroNode","createMesh","rebuildCubes","cubeSeaNode","halfGrid","pos","cubeSeaPrimitive","fromRotation","SHADOW_SEGMENTS","SHADOW_GROUND_OFFSET","SHADOW_CENTER_ALPHA","SHADOW_INNER_ALPHA","SHADOW_OUTER_ALPHA","SHADOW_INNER_RADIUS","SHADOW_OUTER_RADIUS","DropShadowMaterial","LEQUAL","segRad","shadowPrimitive","_shadowRenderPrimitive","gltfLoaderMap","WeakMap","_url","_resolver","_rejecter","loader","get","_ensurePromise","loadFromUrl","catch","err","LASER_TEXTURE_DATA","LASER_LENGTH","LASER_DIAMETER","LASER_FADE_END","LASER_FADE_POINT","LASER_DEFAULT_COLOR","CURSOR_RADIUS","CURSOR_SHADOW_RADIUS","CURSOR_SHADOW_INNER_LUMINANCE","CURSOR_SHADOW_OUTER_LUMINANCE","CURSOR_SHADOW_INNER_OPACITY","CURSOR_SHADOW_OUTER_OPACITY","CURSOR_OPACITY","CURSOR_SEGMENTS","CURSOR_DEFAULT_COLOR","CURSOR_DEFAULT_HIDDEN_COLOR","DEFAULT_RESET_OPTIONS","controllers","lasers","cursors","LaserMaterial","laser","laserColor","CURSOR_VERTEX_SHADER","CURSOR_FRAGMENT_SHADER","CursorMaterial","cursorColor","CursorHiddenMaterial","GEQUAL","InputRenderer","_maxInputElements","_controllers","_controllerNode","_controllerNodeHandedness","_lasers","_cursors","_activeControllers","_activeLasers","_activeCursors","controllerNode","handedness","gripMatrix","controller","targetRay","_createLaserMesh","cursorPos","_createCursorMesh","cursor","lr","ll","laserVerts","laserIndices","laserVertexBuffer","laserIndexBuffer","laserIndexCount","laserAttribs","laserPrimitive","laserMaterial","laserRenderPrimitive","cursorVerts","cursorIndices","indexOffset","cursorVertexBuffer","cursorIndexBuffer","cursorIndexCount","cursorAttribs","cursorPrimitive","cursorMaterial","cursorHiddenMaterial","cursorRenderPrimitive","cursorHiddenRenderPrimitive","TEXT_KERNING","SevenSegmentMaterial","SevenSegmentText","_text","_charNodes","clearNodes","vertices","segmentIndices","thickness","defineSegment","id","left","top","right","bottom","characters","defineCharacter","character","segment","vertexAttribs","_charPrimitives","char","charDef","text","charPrimitive","SkyboxMaterial","texCoordScaleOffset","_displayMode","displayMode","_rotationY","rotationY","latSegments","lonSegments","theta","sinTheta","cosTheta","idxOffsetA","idxOffsetB","j","phi","SEGMENTS","MAX_FPS","StatsMaterial","segmentToX","fpsToY","fpsToRGB","now","performance","Date","StatsViewer","_performanceMonitoring","_startTime","_prevFrameTime","_prevGraphUpdateTime","_frames","_fpsAverage","_fpsMin","_fpsStep","_lastSegment","_fpsVertexBuffer","_fpsRenderPrimitive","_fpsNode","_sevenSegmentNode","fpsVerts","fpsIndices","addBGSquare","DYNAMIC_DRAW","fpsIndexBuffer","fpsAttribs","fpsPrimitive","time","frameFps","intervalTime","round","_updateGraph","log","valueLow","valueHigh","color","y0","y1","updateVerts","VideoMaterial","_video_texture","layer","getViewport","_timestamp","_frameDelta","_statsStanding","_stats","_statsEnabled","enableStats","_inputRenderer","_resetInputEndFrame","_lastTimestamp","_hoverFrame","_hoveredNodes","frame","frameOfRef","session","getInputSources","inputSources","newHoveredNodes","lastHoverFrame","inputSource","inputPose","getInputPose","inputRenderer","addController","targetRayMode","addLaserPointer","hitResult","addCursor","onHoverStart","cursorDistance","direction","hoverNode","onHoverEnd","handleSelectPointer","handleSelect","fromEuler","drawViewArray","xrFrame","pose","baseLayer","bindFramebuffer","FRAMEBUFFER","framebuffer","COLOR_BUFFER_BIT","DEPTH_BUFFER_BIT","drawViews","prevTimestamp","begin","reset","end","LOOK_SPEED","_emulateStage","lookYaw","lookPitch","identity","onResize","canvas","offsetWidth","devicePixelRatio","offsetHeight","perspective","drawingBufferWidth","drawingBufferHeight","lastTouchX","lastTouchY","ev","touches","pageX","pageY","onLook","buttons","movementX","movementY","preventDefault","boundOnFrame","onFrame","requestAnimationFrame","yaw","pitch","updateView","startFrame","draw","endFrame","rotateX","rotateY","translate","urlArgs","onhashchange","ensureArgsCached","query","search","hash","vars","split","pair","toLowerCase","decodeURIComponent","lcaseName","parseInt","parseFloat"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;ACVA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,kDAA0C,gCAAgC;AAC1E;AACA;;AAEA;AACA;AACA;AACA,gEAAwD,kBAAkB;AAC1E;AACA,yDAAiD,cAAc;AAC/D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAyC,iCAAiC;AAC1E,wHAAgH,mBAAmB,EAAE;AACrI;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;;AAGA;AACA;;;;;;;;;;;;;AClFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACO;AACA;AACA;;AAEP;AACA;AACA;AACA,WAAW,KAAK;AAChB;AACO;AACP;AACA;;AAEA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;;;;;;;;;;;;ACzCA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAuC;;AAEvC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB;;AAEO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;;;;;;;;;;;;AC9ZP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,MAAM;AACnB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;;;;;;;;;;;;AC/bP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,UAAU,KAAK;AACf,UAAU,KAAK;AACf;AACA,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,UAAU,KAAK;AACf,UAAU,KAAK;AACf;AACA,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;AAIA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;;;;;;;;;;;;AC1uBP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,YAAY,WAAW,WAAW;AAClC;AACA;AACA;AACA;;AAEA,YAAY,WAAW,YAAY;AACnC;AACA;AACA;AACA;;AAEA,aAAa,YAAY,YAAY;AACrC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH,eAAe,YAAY,YAAY;AACvC,eAAe,YAAY,YAAY;AACvC,eAAe,YAAY,aAAa;;AAExC,iBAAiB,cAAc,cAAc;AAC7C,iBAAiB,cAAc,cAAc;AAC7C,iBAAiB,cAAc,eAAe;;AAE9C;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,YAAY,kDAAgB,GAAG,aAAa;;AAE5C;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,aAAa,YAAY,YAAY;AACrC,aAAa,YAAY,YAAY;AACrC,aAAa,YAAY,aAAa;;AAEtC;AACA,sBAAsB,yBAAyB;AAC/C,0BAA0B,qBAAqB;AAC/C,0BAA0B,yBAAyB;;AAEnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA,YAAY,kDAAgB,GAAG,aAAa;;AAE5C;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,KAAK;AAClB;AACO;AACP,wBAAwB,qDAAmB;AAC3C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB;AACA,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD,iCAAiC,kDAAgB;AACjD;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;;;;;;;;;;;;AClrDP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAuC;AACN;AACA;AACA;;AAEjC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,KAAK;AACjB,YAAY,OAAO;AACnB;AACO;AACP;AACA;AACA,UAAU,kDAAgB;AAC1B;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,kDAAgB;AACvC;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA,WAAW,iDAAe;AAC1B,WAAW,iDAAe;AAC1B,WAAW,iDAAe;;AAE1B;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA,oCAAoC;AACpC;AACA,sBAAsB;AACtB;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,EAAE;AACb,WAAW,EAAE;AACb,WAAW,EAAE;AACb,aAAa,KAAK;AAClB;AACA;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACA;AACO,cAAc,8CAAU;;AAE/B;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACA;AACO,mBAAmB,mDAAe;;AAEzC;AACA;AACA;AACA,WAAW,KAAK;AA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A;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP,eAAe,qDAAmB;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP,eAAe,qDAAmB;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA,cAAc,+CAAW;AACzB,EAAE,oDAAgB;AAClB,cAAc,qDAAmB;AACjC,EAAE,uDAAmB;AACrB;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,MAAM;AAClB,YAAY,KAAK;AACjB;AACO,gBAAgB,6CAAS;;AAEhC;AACA;AACA,YAAY,KAAK;AACjB,YAAY,MAAM;AAClB,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO,gBAAgB,6CAAS;;AAEhC;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAY,KAAK;AACjB,YAAY,MAAM;AAClB,YAAY,KAAK;AACjB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,gDAAY;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,gDAAY;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,gDAAY;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA,sBAAsB,kDAAgB;AACtC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACO,YAAY,4CAAQ;;AAE3B;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACO,eAAe,+CAAW;;AAEjC;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACA;AACO,sBAAsB,sDAAkB;;AAE/C;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,MAAM;AACnB;AACA;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,MAAM;AACjB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,kDAAgB;AAC/C,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC,yBAAyB,kDAAgB;AACzC;;;;;;;;;;;;;ACr1BA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA,UAAU,iDAAe;AACzB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,MAAM;AACjB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA,mBAAmB,OAAO;AAC1B,oBAAoB;AACpB;AACA,oBAAoB;AACpB;;AAEA;AACA;AACA,CAAC;;;;;;;;;;;;;AChnBD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA,UAAU,iDAAe;AACzB,WAAW,iDAAe;AAC1B;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA,mBAAmB,OAAO;AAC1B,oBAAoB,iBAAiB;AACrC;AACA,oBAAoB,iBAAiB;AACrC;;AAEA;AACA;AACA,CAAC;;;;;;;;;;;;;AChwBD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAwC;;AAExC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC,KAAK,qDAAmB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP,gBAAgB,qDAAmB;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,OAAO;AAClB,aAAa,KAAK;AAClB;AACO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,iDAAe;AACxB,SAAS,iDAAe;AACxB;AACA,GAAG;AACH;AACA,SAAS,iDAAe;AACxB,SAAS,iDAAe;AACxB;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,OAAO;AACpB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C,+BAA+B,kDAAgB;AAC/C;;AAEA;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA,cAAc;AACd;AACA;AACO;;AAEP;AACA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACO;AACP;;AAEA;AACA;AAC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","file":"cottontail.debug.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse {\n\t\tvar a = factory();\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/cottontail.js\");\n","/**\n * Common utilities\n * @module glMatrix\n */\n\n// Configuration Constants\nexport const EPSILON = 0.000001;\nexport let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;\nexport const RANDOM = Math.random;\n\n/**\n * Sets the type of array used when creating new vectors and matrices\n *\n * @param {Type} type Array type, such as Float32Array or Array\n */\nexport function setMatrixArrayType(type) {\n ARRAY_TYPE = type;\n}\n\nconst degree = Math.PI / 180;\n\n/**\n * Convert Degree To Radian\n *\n * @param {Number} a Angle in Degrees\n */\nexport function toRadian(a) {\n return a * degree;\n}\n\n/**\n * Tests whether or not the arguments have approximately the same value, within an absolute\n * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less\n * than or equal to 1.0, and a relative tolerance is used for larger values)\n *\n * @param {Number} a The first number to test.\n * @param {Number} b The second number to test.\n * @returns {Boolean} True if the numbers are approximately equal, false otherwise.\n */\nexport function equals(a, b) {\n return Math.abs(a - b) <= EPSILON*Math.max(1.0, Math.abs(a), Math.abs(b));\n}\n","import * as glMatrix from \"./common.js\"\n\n/**\n * 2x2 Matrix\n * @module mat2\n */\n\n/**\n * Creates a new identity mat2\n *\n * @returns {mat2} a new 2x2 matrix\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(4);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[1] = 0;\n out[2] = 0;\n }\n out[0] = 1;\n out[3] = 1;\n return out;\n}\n\n/**\n * Creates a new mat2 initialized with values from an existing matrix\n *\n * @param {mat2} a matrix to clone\n * @returns {mat2} a new 2x2 matrix\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(4);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n}\n\n/**\n * Copy the values from one mat2 to another\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the source matrix\n * @returns {mat2} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n}\n\n/**\n * Set a mat2 to the identity matrix\n *\n * @param {mat2} out the receiving matrix\n * @returns {mat2} out\n */\nexport function identity(out) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n return out;\n}\n\n/**\n * Create a new mat2 with the given values\n *\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m10 Component in column 1, row 0 position (index 2)\n * @param {Number} m11 Component in column 1, row 1 position (index 3)\n * @returns {mat2} out A new 2x2 matrix\n */\nexport function fromValues(m00, m01, m10, m11) {\n let out = new glMatrix.ARRAY_TYPE(4);\n out[0] = m00;\n out[1] = m01;\n out[2] = m10;\n out[3] = m11;\n return out;\n}\n\n/**\n * Set the components of a mat2 to the given values\n *\n * @param {mat2} out the receiving matrix\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m10 Component in column 1, row 0 position (index 2)\n * @param {Number} m11 Component in column 1, row 1 position (index 3)\n * @returns {mat2} out\n */\nexport function set(out, m00, m01, m10, m11) {\n out[0] = m00;\n out[1] = m01;\n out[2] = m10;\n out[3] = m11;\n return out;\n}\n\n/**\n * Transpose the values of a mat2\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the source matrix\n * @returns {mat2} out\n */\nexport function transpose(out, a) {\n // If we are transposing ourselves we can skip a few steps but have to cache\n // some values\n if (out === a) {\n let a1 = a[1];\n out[1] = a[2];\n out[2] = a1;\n } else {\n out[0] = a[0];\n out[1] = a[2];\n out[2] = a[1];\n out[3] = a[3];\n }\n\n return out;\n}\n\n/**\n * Inverts a mat2\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the source matrix\n * @returns {mat2} out\n */\nexport function invert(out, a) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n\n // Calculate the determinant\n let det = a0 * a3 - a2 * a1;\n\n if (!det) {\n return null;\n }\n det = 1.0 / det;\n\n out[0] = a3 * det;\n out[1] = -a1 * det;\n out[2] = -a2 * det;\n out[3] = a0 * det;\n\n return out;\n}\n\n/**\n * Calculates the adjugate of a mat2\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the source matrix\n * @returns {mat2} out\n */\nexport function adjoint(out, a) {\n // Caching this value is nessecary if out == a\n let a0 = a[0];\n out[0] = a[3];\n out[1] = -a[1];\n out[2] = -a[2];\n out[3] = a0;\n\n return out;\n}\n\n/**\n * Calculates the determinant of a mat2\n *\n * @param {mat2} a the source matrix\n * @returns {Number} determinant of a\n */\nexport function determinant(a) {\n return a[0] * a[3] - a[2] * a[1];\n}\n\n/**\n * Multiplies two mat2's\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the first operand\n * @param {mat2} b the second operand\n * @returns {mat2} out\n */\nexport function multiply(out, a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n out[0] = a0 * b0 + a2 * b1;\n out[1] = a1 * b0 + a3 * b1;\n out[2] = a0 * b2 + a2 * b3;\n out[3] = a1 * b2 + a3 * b3;\n return out;\n}\n\n/**\n * Rotates a mat2 by the given angle\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat2} out\n */\nexport function rotate(out, a, rad) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n out[0] = a0 * c + a2 * s;\n out[1] = a1 * c + a3 * s;\n out[2] = a0 * -s + a2 * c;\n out[3] = a1 * -s + a3 * c;\n return out;\n}\n\n/**\n * Scales the mat2 by the dimensions in the given vec2\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the matrix to rotate\n * @param {vec2} v the vec2 to scale the matrix by\n * @returns {mat2} out\n **/\nexport function scale(out, a, v) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let v0 = v[0], v1 = v[1];\n out[0] = a0 * v0;\n out[1] = a1 * v0;\n out[2] = a2 * v1;\n out[3] = a3 * v1;\n return out;\n}\n\n/**\n * Creates a matrix from a given angle\n * This is equivalent to (but much faster than):\n *\n * mat2.identity(dest);\n * mat2.rotate(dest, dest, rad);\n *\n * @param {mat2} out mat2 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat2} out\n */\nexport function fromRotation(out, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n out[0] = c;\n out[1] = s;\n out[2] = -s;\n out[3] = c;\n return out;\n}\n\n/**\n * Creates a matrix from a vector scaling\n * This is equivalent to (but much faster than):\n *\n * mat2.identity(dest);\n * mat2.scale(dest, dest, vec);\n *\n * @param {mat2} out mat2 receiving operation result\n * @param {vec2} v Scaling vector\n * @returns {mat2} out\n */\nexport function fromScaling(out, v) {\n out[0] = v[0];\n out[1] = 0;\n out[2] = 0;\n out[3] = v[1];\n return out;\n}\n\n/**\n * Returns a string representation of a mat2\n *\n * @param {mat2} a matrix to represent as a string\n * @returns {String} string representation of the matrix\n */\nexport function str(a) {\n return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\n}\n\n/**\n * Returns Frobenius norm of a mat2\n *\n * @param {mat2} a the matrix to calculate Frobenius norm of\n * @returns {Number} Frobenius norm\n */\nexport function frob(a) {\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)))\n}\n\n/**\n * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix\n * @param {mat2} L the lower triangular matrix\n * @param {mat2} D the diagonal matrix\n * @param {mat2} U the upper triangular matrix\n * @param {mat2} a the input matrix to factorize\n */\n\nexport function LDU(L, D, U, a) {\n L[2] = a[2]/a[0];\n U[0] = a[0];\n U[1] = a[1];\n U[3] = a[3] - L[2] * U[1];\n return [L, D, U];\n}\n\n/**\n * Adds two mat2's\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the first operand\n * @param {mat2} b the second operand\n * @returns {mat2} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n return out;\n}\n\n/**\n * Subtracts matrix b from matrix a\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the first operand\n * @param {mat2} b the second operand\n * @returns {mat2} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n out[3] = a[3] - b[3];\n return out;\n}\n\n/**\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\n *\n * @param {mat2} a The first matrix.\n * @param {mat2} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];\n}\n\n/**\n * Returns whether or not the matrices have approximately the same elements in the same position.\n *\n * @param {mat2} a The first matrix.\n * @param {mat2} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));\n}\n\n/**\n * Multiply each element of the matrix by a scalar.\n *\n * @param {mat2} out the receiving matrix\n * @param {mat2} a the matrix to scale\n * @param {Number} b amount to scale the matrix's elements by\n * @returns {mat2} out\n */\nexport function multiplyScalar(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n return out;\n}\n\n/**\n * Adds two mat2's after multiplying each element of the second operand by a scalar value.\n *\n * @param {mat2} out the receiving vector\n * @param {mat2} a the first operand\n * @param {mat2} b the second operand\n * @param {Number} scale the amount to scale b's elements by before adding\n * @returns {mat2} out\n */\nexport function multiplyScalarAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n out[3] = a[3] + (b[3] * scale);\n return out;\n}\n\n/**\n * Alias for {@link mat2.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link mat2.subtract}\n * @function\n */\nexport const sub = subtract;\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 2x3 Matrix\n * @module mat2d\n *\n * @description\n * A mat2d contains six elements defined as:\n * <pre>\n * [a, c, tx,\n * b, d, ty]\n * </pre>\n * This is a short form for the 3x3 matrix:\n * <pre>\n * [a, c, tx,\n * b, d, ty,\n * 0, 0, 1]\n * </pre>\n * The last row is ignored so the array is shorter and operations are faster.\n */\n\n/**\n * Creates a new identity mat2d\n *\n * @returns {mat2d} a new 2x3 matrix\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(6);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[1] = 0;\n out[2] = 0;\n out[4] = 0;\n out[5] = 0;\n }\n out[0] = 1;\n out[3] = 1;\n return out;\n}\n\n/**\n * Creates a new mat2d initialized with values from an existing matrix\n *\n * @param {mat2d} a matrix to clone\n * @returns {mat2d} a new 2x3 matrix\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(6);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n return out;\n}\n\n/**\n * Copy the values from one mat2d to another\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the source matrix\n * @returns {mat2d} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n return out;\n}\n\n/**\n * Set a mat2d to the identity matrix\n *\n * @param {mat2d} out the receiving matrix\n * @returns {mat2d} out\n */\nexport function identity(out) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n out[4] = 0;\n out[5] = 0;\n return out;\n}\n\n/**\n * Create a new mat2d with the given values\n *\n * @param {Number} a Component A (index 0)\n * @param {Number} b Component B (index 1)\n * @param {Number} c Component C (index 2)\n * @param {Number} d Component D (index 3)\n * @param {Number} tx Component TX (index 4)\n * @param {Number} ty Component TY (index 5)\n * @returns {mat2d} A new mat2d\n */\nexport function fromValues(a, b, c, d, tx, ty) {\n let out = new glMatrix.ARRAY_TYPE(6);\n out[0] = a;\n out[1] = b;\n out[2] = c;\n out[3] = d;\n out[4] = tx;\n out[5] = ty;\n return out;\n}\n\n/**\n * Set the components of a mat2d to the given values\n *\n * @param {mat2d} out the receiving matrix\n * @param {Number} a Component A (index 0)\n * @param {Number} b Component B (index 1)\n * @param {Number} c Component C (index 2)\n * @param {Number} d Component D (index 3)\n * @param {Number} tx Component TX (index 4)\n * @param {Number} ty Component TY (index 5)\n * @returns {mat2d} out\n */\nexport function set(out, a, b, c, d, tx, ty) {\n out[0] = a;\n out[1] = b;\n out[2] = c;\n out[3] = d;\n out[4] = tx;\n out[5] = ty;\n return out;\n}\n\n/**\n * Inverts a mat2d\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the source matrix\n * @returns {mat2d} out\n */\nexport function invert(out, a) {\n let aa = a[0], ab = a[1], ac = a[2], ad = a[3];\n let atx = a[4], aty = a[5];\n\n let det = aa * ad - ab * ac;\n if(!det){\n return null;\n }\n det = 1.0 / det;\n\n out[0] = ad * det;\n out[1] = -ab * det;\n out[2] = -ac * det;\n out[3] = aa * det;\n out[4] = (ac * aty - ad * atx) * det;\n out[5] = (ab * atx - aa * aty) * det;\n return out;\n}\n\n/**\n * Calculates the determinant of a mat2d\n *\n * @param {mat2d} a the source matrix\n * @returns {Number} determinant of a\n */\nexport function determinant(a) {\n return a[0] * a[3] - a[1] * a[2];\n}\n\n/**\n * Multiplies two mat2d's\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the first operand\n * @param {mat2d} b the second operand\n * @returns {mat2d} out\n */\nexport function multiply(out, a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];\n out[0] = a0 * b0 + a2 * b1;\n out[1] = a1 * b0 + a3 * b1;\n out[2] = a0 * b2 + a2 * b3;\n out[3] = a1 * b2 + a3 * b3;\n out[4] = a0 * b4 + a2 * b5 + a4;\n out[5] = a1 * b4 + a3 * b5 + a5;\n return out;\n}\n\n/**\n * Rotates a mat2d by the given angle\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat2d} out\n */\nexport function rotate(out, a, rad) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n out[0] = a0 * c + a2 * s;\n out[1] = a1 * c + a3 * s;\n out[2] = a0 * -s + a2 * c;\n out[3] = a1 * -s + a3 * c;\n out[4] = a4;\n out[5] = a5;\n return out;\n}\n\n/**\n * Scales the mat2d by the dimensions in the given vec2\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the matrix to translate\n * @param {vec2} v the vec2 to scale the matrix by\n * @returns {mat2d} out\n **/\nexport function scale(out, a, v) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\n let v0 = v[0], v1 = v[1];\n out[0] = a0 * v0;\n out[1] = a1 * v0;\n out[2] = a2 * v1;\n out[3] = a3 * v1;\n out[4] = a4;\n out[5] = a5;\n return out;\n}\n\n/**\n * Translates the mat2d by the dimensions in the given vec2\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the matrix to translate\n * @param {vec2} v the vec2 to translate the matrix by\n * @returns {mat2d} out\n **/\nexport function translate(out, a, v) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\n let v0 = v[0], v1 = v[1];\n out[0] = a0;\n out[1] = a1;\n out[2] = a2;\n out[3] = a3;\n out[4] = a0 * v0 + a2 * v1 + a4;\n out[5] = a1 * v0 + a3 * v1 + a5;\n return out;\n}\n\n/**\n * Creates a matrix from a given angle\n * This is equivalent to (but much faster than):\n *\n * mat2d.identity(dest);\n * mat2d.rotate(dest, dest, rad);\n *\n * @param {mat2d} out mat2d receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat2d} out\n */\nexport function fromRotation(out, rad) {\n let s = Math.sin(rad), c = Math.cos(rad);\n out[0] = c;\n out[1] = s;\n out[2] = -s;\n out[3] = c;\n out[4] = 0;\n out[5] = 0;\n return out;\n}\n\n/**\n * Creates a matrix from a vector scaling\n * This is equivalent to (but much faster than):\n *\n * mat2d.identity(dest);\n * mat2d.scale(dest, dest, vec);\n *\n * @param {mat2d} out mat2d receiving operation result\n * @param {vec2} v Scaling vector\n * @returns {mat2d} out\n */\nexport function fromScaling(out, v) {\n out[0] = v[0];\n out[1] = 0;\n out[2] = 0;\n out[3] = v[1];\n out[4] = 0;\n out[5] = 0;\n return out;\n}\n\n/**\n * Creates a matrix from a vector translation\n * This is equivalent to (but much faster than):\n *\n * mat2d.identity(dest);\n * mat2d.translate(dest, dest, vec);\n *\n * @param {mat2d} out mat2d receiving operation result\n * @param {vec2} v Translation vector\n * @returns {mat2d} out\n */\nexport function fromTranslation(out, v) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n out[4] = v[0];\n out[5] = v[1];\n return out;\n}\n\n/**\n * Returns a string representation of a mat2d\n *\n * @param {mat2d} a matrix to represent as a string\n * @returns {String} string representation of the matrix\n */\nexport function str(a) {\n return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +\n a[3] + ', ' + a[4] + ', ' + a[5] + ')';\n}\n\n/**\n * Returns Frobenius norm of a mat2d\n *\n * @param {mat2d} a the matrix to calculate Frobenius norm of\n * @returns {Number} Frobenius norm\n */\nexport function frob(a) {\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1))\n}\n\n/**\n * Adds two mat2d's\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the first operand\n * @param {mat2d} b the second operand\n * @returns {mat2d} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n out[4] = a[4] + b[4];\n out[5] = a[5] + b[5];\n return out;\n}\n\n/**\n * Subtracts matrix b from matrix a\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the first operand\n * @param {mat2d} b the second operand\n * @returns {mat2d} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n out[3] = a[3] - b[3];\n out[4] = a[4] - b[4];\n out[5] = a[5] - b[5];\n return out;\n}\n\n/**\n * Multiply each element of the matrix by a scalar.\n *\n * @param {mat2d} out the receiving matrix\n * @param {mat2d} a the matrix to scale\n * @param {Number} b amount to scale the matrix's elements by\n * @returns {mat2d} out\n */\nexport function multiplyScalar(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n out[4] = a[4] * b;\n out[5] = a[5] * b;\n return out;\n}\n\n/**\n * Adds two mat2d's after multiplying each element of the second operand by a scalar value.\n *\n * @param {mat2d} out the receiving vector\n * @param {mat2d} a the first operand\n * @param {mat2d} b the second operand\n * @param {Number} scale the amount to scale b's elements by before adding\n * @returns {mat2d} out\n */\nexport function multiplyScalarAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n out[3] = a[3] + (b[3] * scale);\n out[4] = a[4] + (b[4] * scale);\n out[5] = a[5] + (b[5] * scale);\n return out;\n}\n\n/**\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\n *\n * @param {mat2d} a The first matrix.\n * @param {mat2d} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];\n}\n\n/**\n * Returns whether or not the matrices have approximately the same elements in the same position.\n *\n * @param {mat2d} a The first matrix.\n * @param {mat2d} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\n Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\n Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)));\n}\n\n/**\n * Alias for {@link mat2d.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link mat2d.subtract}\n * @function\n */\nexport const sub = subtract;\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 3x3 Matrix\n * @module mat3\n */\n\n/**\n * Creates a new identity mat3\n *\n * @returns {mat3} a new 3x3 matrix\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(9);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[5] = 0;\n out[6] = 0;\n out[7] = 0;\n }\n out[0] = 1;\n out[4] = 1;\n out[8] = 1;\n return out;\n}\n\n/**\n * Copies the upper-left 3x3 values into the given mat3.\n *\n * @param {mat3} out the receiving 3x3 matrix\n * @param {mat4} a the source 4x4 matrix\n * @returns {mat3} out\n */\nexport function fromMat4(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[4];\n out[4] = a[5];\n out[5] = a[6];\n out[6] = a[8];\n out[7] = a[9];\n out[8] = a[10];\n return out;\n}\n\n/**\n * Creates a new mat3 initialized with values from an existing matrix\n *\n * @param {mat3} a matrix to clone\n * @returns {mat3} a new 3x3 matrix\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(9);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n return out;\n}\n\n/**\n * Copy the values from one mat3 to another\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the source matrix\n * @returns {mat3} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n return out;\n}\n\n/**\n * Create a new mat3 with the given values\n *\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\n * @param {Number} m10 Component in column 1, row 0 position (index 3)\n * @param {Number} m11 Component in column 1, row 1 position (index 4)\n * @param {Number} m12 Component in column 1, row 2 position (index 5)\n * @param {Number} m20 Component in column 2, row 0 position (index 6)\n * @param {Number} m21 Component in column 2, row 1 position (index 7)\n * @param {Number} m22 Component in column 2, row 2 position (index 8)\n * @returns {mat3} A new mat3\n */\nexport function fromValues(m00, m01, m02, m10, m11, m12, m20, m21, m22) {\n let out = new glMatrix.ARRAY_TYPE(9);\n out[0] = m00;\n out[1] = m01;\n out[2] = m02;\n out[3] = m10;\n out[4] = m11;\n out[5] = m12;\n out[6] = m20;\n out[7] = m21;\n out[8] = m22;\n return out;\n}\n\n/**\n * Set the components of a mat3 to the given values\n *\n * @param {mat3} out the receiving matrix\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\n * @param {Number} m10 Component in column 1, row 0 position (index 3)\n * @param {Number} m11 Component in column 1, row 1 position (index 4)\n * @param {Number} m12 Component in column 1, row 2 position (index 5)\n * @param {Number} m20 Component in column 2, row 0 position (index 6)\n * @param {Number} m21 Component in column 2, row 1 position (index 7)\n * @param {Number} m22 Component in column 2, row 2 position (index 8)\n * @returns {mat3} out\n */\nexport function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {\n out[0] = m00;\n out[1] = m01;\n out[2] = m02;\n out[3] = m10;\n out[4] = m11;\n out[5] = m12;\n out[6] = m20;\n out[7] = m21;\n out[8] = m22;\n return out;\n}\n\n/**\n * Set a mat3 to the identity matrix\n *\n * @param {mat3} out the receiving matrix\n * @returns {mat3} out\n */\nexport function identity(out) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 1;\n out[5] = 0;\n out[6] = 0;\n out[7] = 0;\n out[8] = 1;\n return out;\n}\n\n/**\n * Transpose the values of a mat3\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the source matrix\n * @returns {mat3} out\n */\nexport function transpose(out, a) {\n // If we are transposing ourselves we can skip a few steps but have to cache some values\n if (out === a) {\n let a01 = a[1], a02 = a[2], a12 = a[5];\n out[1] = a[3];\n out[2] = a[6];\n out[3] = a01;\n out[5] = a[7];\n out[6] = a02;\n out[7] = a12;\n } else {\n out[0] = a[0];\n out[1] = a[3];\n out[2] = a[6];\n out[3] = a[1];\n out[4] = a[4];\n out[5] = a[7];\n out[6] = a[2];\n out[7] = a[5];\n out[8] = a[8];\n }\n\n return out;\n}\n\n/**\n * Inverts a mat3\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the source matrix\n * @returns {mat3} out\n */\nexport function invert(out, a) {\n let a00 = a[0], a01 = a[1], a02 = a[2];\n let a10 = a[3], a11 = a[4], a12 = a[5];\n let a20 = a[6], a21 = a[7], a22 = a[8];\n\n let b01 = a22 * a11 - a12 * a21;\n let b11 = -a22 * a10 + a12 * a20;\n let b21 = a21 * a10 - a11 * a20;\n\n // Calculate the determinant\n let det = a00 * b01 + a01 * b11 + a02 * b21;\n\n if (!det) {\n return null;\n }\n det = 1.0 / det;\n\n out[0] = b01 * det;\n out[1] = (-a22 * a01 + a02 * a21) * det;\n out[2] = (a12 * a01 - a02 * a11) * det;\n out[3] = b11 * det;\n out[4] = (a22 * a00 - a02 * a20) * det;\n out[5] = (-a12 * a00 + a02 * a10) * det;\n out[6] = b21 * det;\n out[7] = (-a21 * a00 + a01 * a20) * det;\n out[8] = (a11 * a00 - a01 * a10) * det;\n return out;\n}\n\n/**\n * Calculates the adjugate of a mat3\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the source matrix\n * @returns {mat3} out\n */\nexport function adjoint(out, a) {\n let a00 = a[0], a01 = a[1], a02 = a[2];\n let a10 = a[3], a11 = a[4], a12 = a[5];\n let a20 = a[6], a21 = a[7], a22 = a[8];\n\n out[0] = (a11 * a22 - a12 * a21);\n out[1] = (a02 * a21 - a01 * a22);\n out[2] = (a01 * a12 - a02 * a11);\n out[3] = (a12 * a20 - a10 * a22);\n out[4] = (a00 * a22 - a02 * a20);\n out[5] = (a02 * a10 - a00 * a12);\n out[6] = (a10 * a21 - a11 * a20);\n out[7] = (a01 * a20 - a00 * a21);\n out[8] = (a00 * a11 - a01 * a10);\n return out;\n}\n\n/**\n * Calculates the determinant of a mat3\n *\n * @param {mat3} a the source matrix\n * @returns {Number} determinant of a\n */\nexport function determinant(a) {\n let a00 = a[0], a01 = a[1], a02 = a[2];\n let a10 = a[3], a11 = a[4], a12 = a[5];\n let a20 = a[6], a21 = a[7], a22 = a[8];\n\n return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);\n}\n\n/**\n * Multiplies two mat3's\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the first operand\n * @param {mat3} b the second operand\n * @returns {mat3} out\n */\nexport function multiply(out, a, b) {\n let a00 = a[0], a01 = a[1], a02 = a[2];\n let a10 = a[3], a11 = a[4], a12 = a[5];\n let a20 = a[6], a21 = a[7], a22 = a[8];\n\n let b00 = b[0], b01 = b[1], b02 = b[2];\n let b10 = b[3], b11 = b[4], b12 = b[5];\n let b20 = b[6], b21 = b[7], b22 = b[8];\n\n out[0] = b00 * a00 + b01 * a10 + b02 * a20;\n out[1] = b00 * a01 + b01 * a11 + b02 * a21;\n out[2] = b00 * a02 + b01 * a12 + b02 * a22;\n\n out[3] = b10 * a00 + b11 * a10 + b12 * a20;\n out[4] = b10 * a01 + b11 * a11 + b12 * a21;\n out[5] = b10 * a02 + b11 * a12 + b12 * a22;\n\n out[6] = b20 * a00 + b21 * a10 + b22 * a20;\n out[7] = b20 * a01 + b21 * a11 + b22 * a21;\n out[8] = b20 * a02 + b21 * a12 + b22 * a22;\n return out;\n}\n\n/**\n * Translate a mat3 by the given vector\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the matrix to translate\n * @param {vec2} v vector to translate by\n * @returns {mat3} out\n */\nexport function translate(out, a, v) {\n let a00 = a[0], a01 = a[1], a02 = a[2],\n a10 = a[3], a11 = a[4], a12 = a[5],\n a20 = a[6], a21 = a[7], a22 = a[8],\n x = v[0], y = v[1];\n\n out[0] = a00;\n out[1] = a01;\n out[2] = a02;\n\n out[3] = a10;\n out[4] = a11;\n out[5] = a12;\n\n out[6] = x * a00 + y * a10 + a20;\n out[7] = x * a01 + y * a11 + a21;\n out[8] = x * a02 + y * a12 + a22;\n return out;\n}\n\n/**\n * Rotates a mat3 by the given angle\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat3} out\n */\nexport function rotate(out, a, rad) {\n let a00 = a[0], a01 = a[1], a02 = a[2],\n a10 = a[3], a11 = a[4], a12 = a[5],\n a20 = a[6], a21 = a[7], a22 = a[8],\n\n s = Math.sin(rad),\n c = Math.cos(rad);\n\n out[0] = c * a00 + s * a10;\n out[1] = c * a01 + s * a11;\n out[2] = c * a02 + s * a12;\n\n out[3] = c * a10 - s * a00;\n out[4] = c * a11 - s * a01;\n out[5] = c * a12 - s * a02;\n\n out[6] = a20;\n out[7] = a21;\n out[8] = a22;\n return out;\n};\n\n/**\n * Scales the mat3 by the dimensions in the given vec2\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the matrix to rotate\n * @param {vec2} v the vec2 to scale the matrix by\n * @returns {mat3} out\n **/\nexport function scale(out, a, v) {\n let x = v[0], y = v[1];\n\n out[0] = x * a[0];\n out[1] = x * a[1];\n out[2] = x * a[2];\n\n out[3] = y * a[3];\n out[4] = y * a[4];\n out[5] = y * a[5];\n\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n return out;\n}\n\n/**\n * Creates a matrix from a vector translation\n * This is equivalent to (but much faster than):\n *\n * mat3.identity(dest);\n * mat3.translate(dest, dest, vec);\n *\n * @param {mat3} out mat3 receiving operation result\n * @param {vec2} v Translation vector\n * @returns {mat3} out\n */\nexport function fromTranslation(out, v) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 1;\n out[5] = 0;\n out[6] = v[0];\n out[7] = v[1];\n out[8] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from a given angle\n * This is equivalent to (but much faster than):\n *\n * mat3.identity(dest);\n * mat3.rotate(dest, dest, rad);\n *\n * @param {mat3} out mat3 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat3} out\n */\nexport function fromRotation(out, rad) {\n let s = Math.sin(rad), c = Math.cos(rad);\n\n out[0] = c;\n out[1] = s;\n out[2] = 0;\n\n out[3] = -s;\n out[4] = c;\n out[5] = 0;\n\n out[6] = 0;\n out[7] = 0;\n out[8] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from a vector scaling\n * This is equivalent to (but much faster than):\n *\n * mat3.identity(dest);\n * mat3.scale(dest, dest, vec);\n *\n * @param {mat3} out mat3 receiving operation result\n * @param {vec2} v Scaling vector\n * @returns {mat3} out\n */\nexport function fromScaling(out, v) {\n out[0] = v[0];\n out[1] = 0;\n out[2] = 0;\n\n out[3] = 0;\n out[4] = v[1];\n out[5] = 0;\n\n out[6] = 0;\n out[7] = 0;\n out[8] = 1;\n return out;\n}\n\n/**\n * Copies the values from a mat2d into a mat3\n *\n * @param {mat3} out the receiving matrix\n * @param {mat2d} a the matrix to copy\n * @returns {mat3} out\n **/\nexport function fromMat2d(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = 0;\n\n out[3] = a[2];\n out[4] = a[3];\n out[5] = 0;\n\n out[6] = a[4];\n out[7] = a[5];\n out[8] = 1;\n return out;\n}\n\n/**\n* Calculates a 3x3 matrix from the given quaternion\n*\n* @param {mat3} out mat3 receiving operation result\n* @param {quat} q Quaternion to create matrix from\n*\n* @returns {mat3} out\n*/\nexport function fromQuat(out, q) {\n let x = q[0], y = q[1], z = q[2], w = q[3];\n let x2 = x + x;\n let y2 = y + y;\n let z2 = z + z;\n\n let xx = x * x2;\n let yx = y * x2;\n let yy = y * y2;\n let zx = z * x2;\n let zy = z * y2;\n let zz = z * z2;\n let wx = w * x2;\n let wy = w * y2;\n let wz = w * z2;\n\n out[0] = 1 - yy - zz;\n out[3] = yx - wz;\n out[6] = zx + wy;\n\n out[1] = yx + wz;\n out[4] = 1 - xx - zz;\n out[7] = zy - wx;\n\n out[2] = zx - wy;\n out[5] = zy + wx;\n out[8] = 1 - xx - yy;\n\n return out;\n}\n\n/**\n* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix\n*\n* @param {mat3} out mat3 receiving operation result\n* @param {mat4} a Mat4 to derive the normal matrix from\n*\n* @returns {mat3} out\n*/\nexport function normalFromMat4(out, a) {\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\n\n let b00 = a00 * a11 - a01 * a10;\n let b01 = a00 * a12 - a02 * a10;\n let b02 = a00 * a13 - a03 * a10;\n let b03 = a01 * a12 - a02 * a11;\n let b04 = a01 * a13 - a03 * a11;\n let b05 = a02 * a13 - a03 * a12;\n let b06 = a20 * a31 - a21 * a30;\n let b07 = a20 * a32 - a22 * a30;\n let b08 = a20 * a33 - a23 * a30;\n let b09 = a21 * a32 - a22 * a31;\n let b10 = a21 * a33 - a23 * a31;\n let b11 = a22 * a33 - a23 * a32;\n\n // Calculate the determinant\n let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n\n if (!det) {\n return null;\n }\n det = 1.0 / det;\n\n out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;\n out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;\n out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;\n\n out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;\n out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;\n out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;\n\n out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;\n out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;\n out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;\n\n return out;\n}\n\n/**\n * Generates a 2D projection matrix with the given bounds\n *\n * @param {mat3} out mat3 frustum matrix will be written into\n * @param {number} width Width of your gl context\n * @param {number} height Height of gl context\n * @returns {mat3} out\n */\nexport function projection(out, width, height) {\n out[0] = 2 / width;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = -2 / height;\n out[5] = 0;\n out[6] = -1;\n out[7] = 1;\n out[8] = 1;\n return out;\n}\n\n/**\n * Returns a string representation of a mat3\n *\n * @param {mat3} a matrix to represent as a string\n * @returns {String} string representation of the matrix\n */\nexport function str(a) {\n return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +\n a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +\n a[6] + ', ' + a[7] + ', ' + a[8] + ')';\n}\n\n/**\n * Returns Frobenius norm of a mat3\n *\n * @param {mat3} a the matrix to calculate Frobenius norm of\n * @returns {Number} Frobenius norm\n */\nexport function frob(a) {\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2)))\n}\n\n/**\n * Adds two mat3's\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the first operand\n * @param {mat3} b the second operand\n * @returns {mat3} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n out[4] = a[4] + b[4];\n out[5] = a[5] + b[5];\n out[6] = a[6] + b[6];\n out[7] = a[7] + b[7];\n out[8] = a[8] + b[8];\n return out;\n}\n\n/**\n * Subtracts matrix b from matrix a\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the first operand\n * @param {mat3} b the second operand\n * @returns {mat3} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n out[3] = a[3] - b[3];\n out[4] = a[4] - b[4];\n out[5] = a[5] - b[5];\n out[6] = a[6] - b[6];\n out[7] = a[7] - b[7];\n out[8] = a[8] - b[8];\n return out;\n}\n\n\n\n/**\n * Multiply each element of the matrix by a scalar.\n *\n * @param {mat3} out the receiving matrix\n * @param {mat3} a the matrix to scale\n * @param {Number} b amount to scale the matrix's elements by\n * @returns {mat3} out\n */\nexport function multiplyScalar(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n out[4] = a[4] * b;\n out[5] = a[5] * b;\n out[6] = a[6] * b;\n out[7] = a[7] * b;\n out[8] = a[8] * b;\n return out;\n}\n\n/**\n * Adds two mat3's after multiplying each element of the second operand by a scalar value.\n *\n * @param {mat3} out the receiving vector\n * @param {mat3} a the first operand\n * @param {mat3} b the second operand\n * @param {Number} scale the amount to scale b's elements by before adding\n * @returns {mat3} out\n */\nexport function multiplyScalarAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n out[3] = a[3] + (b[3] * scale);\n out[4] = a[4] + (b[4] * scale);\n out[5] = a[5] + (b[5] * scale);\n out[6] = a[6] + (b[6] * scale);\n out[7] = a[7] + (b[7] * scale);\n out[8] = a[8] + (b[8] * scale);\n return out;\n}\n\n/**\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\n *\n * @param {mat3} a The first matrix.\n * @param {mat3} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] &&\n a[3] === b[3] && a[4] === b[4] && a[5] === b[5] &&\n a[6] === b[6] && a[7] === b[7] && a[8] === b[8];\n}\n\n/**\n * Returns whether or not the matrices have approximately the same elements in the same position.\n *\n * @param {mat3} a The first matrix.\n * @param {mat3} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], a8 = a[8];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], b8 = b[8];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\n Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\n Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&\n Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&\n Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&\n Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)));\n}\n\n/**\n * Alias for {@link mat3.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link mat3.subtract}\n * @function\n */\nexport const sub = subtract;\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied.\n * @module mat4\n */\n\n/**\n * Creates a new identity mat4\n *\n * @returns {mat4} a new 4x4 matrix\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(16);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n }\n out[0] = 1;\n out[5] = 1;\n out[10] = 1;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a new mat4 initialized with values from an existing matrix\n *\n * @param {mat4} a matrix to clone\n * @returns {mat4} a new 4x4 matrix\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(16);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n out[9] = a[9];\n out[10] = a[10];\n out[11] = a[11];\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n return out;\n}\n\n/**\n * Copy the values from one mat4 to another\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the source matrix\n * @returns {mat4} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n out[9] = a[9];\n out[10] = a[10];\n out[11] = a[11];\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n return out;\n}\n\n/**\n * Create a new mat4 with the given values\n *\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\n * @param {Number} m03 Component in column 0, row 3 position (index 3)\n * @param {Number} m10 Component in column 1, row 0 position (index 4)\n * @param {Number} m11 Component in column 1, row 1 position (index 5)\n * @param {Number} m12 Component in column 1, row 2 position (index 6)\n * @param {Number} m13 Component in column 1, row 3 position (index 7)\n * @param {Number} m20 Component in column 2, row 0 position (index 8)\n * @param {Number} m21 Component in column 2, row 1 position (index 9)\n * @param {Number} m22 Component in column 2, row 2 position (index 10)\n * @param {Number} m23 Component in column 2, row 3 position (index 11)\n * @param {Number} m30 Component in column 3, row 0 position (index 12)\n * @param {Number} m31 Component in column 3, row 1 position (index 13)\n * @param {Number} m32 Component in column 3, row 2 position (index 14)\n * @param {Number} m33 Component in column 3, row 3 position (index 15)\n * @returns {mat4} A new mat4\n */\nexport function fromValues(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {\n let out = new glMatrix.ARRAY_TYPE(16);\n out[0] = m00;\n out[1] = m01;\n out[2] = m02;\n out[3] = m03;\n out[4] = m10;\n out[5] = m11;\n out[6] = m12;\n out[7] = m13;\n out[8] = m20;\n out[9] = m21;\n out[10] = m22;\n out[11] = m23;\n out[12] = m30;\n out[13] = m31;\n out[14] = m32;\n out[15] = m33;\n return out;\n}\n\n/**\n * Set the components of a mat4 to the given values\n *\n * @param {mat4} out the receiving matrix\n * @param {Number} m00 Component in column 0, row 0 position (index 0)\n * @param {Number} m01 Component in column 0, row 1 position (index 1)\n * @param {Number} m02 Component in column 0, row 2 position (index 2)\n * @param {Number} m03 Component in column 0, row 3 position (index 3)\n * @param {Number} m10 Component in column 1, row 0 position (index 4)\n * @param {Number} m11 Component in column 1, row 1 position (index 5)\n * @param {Number} m12 Component in column 1, row 2 position (index 6)\n * @param {Number} m13 Component in column 1, row 3 position (index 7)\n * @param {Number} m20 Component in column 2, row 0 position (index 8)\n * @param {Number} m21 Component in column 2, row 1 position (index 9)\n * @param {Number} m22 Component in column 2, row 2 position (index 10)\n * @param {Number} m23 Component in column 2, row 3 position (index 11)\n * @param {Number} m30 Component in column 3, row 0 position (index 12)\n * @param {Number} m31 Component in column 3, row 1 position (index 13)\n * @param {Number} m32 Component in column 3, row 2 position (index 14)\n * @param {Number} m33 Component in column 3, row 3 position (index 15)\n * @returns {mat4} out\n */\nexport function set(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {\n out[0] = m00;\n out[1] = m01;\n out[2] = m02;\n out[3] = m03;\n out[4] = m10;\n out[5] = m11;\n out[6] = m12;\n out[7] = m13;\n out[8] = m20;\n out[9] = m21;\n out[10] = m22;\n out[11] = m23;\n out[12] = m30;\n out[13] = m31;\n out[14] = m32;\n out[15] = m33;\n return out;\n}\n\n\n/**\n * Set a mat4 to the identity matrix\n *\n * @param {mat4} out the receiving matrix\n * @returns {mat4} out\n */\nexport function identity(out) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = 1;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Transpose the values of a mat4\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the source matrix\n * @returns {mat4} out\n */\nexport function transpose(out, a) {\n // If we are transposing ourselves we can skip a few steps but have to cache some values\n if (out === a) {\n let a01 = a[1], a02 = a[2], a03 = a[3];\n let a12 = a[6], a13 = a[7];\n let a23 = a[11];\n\n out[1] = a[4];\n out[2] = a[8];\n out[3] = a[12];\n out[4] = a01;\n out[6] = a[9];\n out[7] = a[13];\n out[8] = a02;\n out[9] = a12;\n out[11] = a[14];\n out[12] = a03;\n out[13] = a13;\n out[14] = a23;\n } else {\n out[0] = a[0];\n out[1] = a[4];\n out[2] = a[8];\n out[3] = a[12];\n out[4] = a[1];\n out[5] = a[5];\n out[6] = a[9];\n out[7] = a[13];\n out[8] = a[2];\n out[9] = a[6];\n out[10] = a[10];\n out[11] = a[14];\n out[12] = a[3];\n out[13] = a[7];\n out[14] = a[11];\n out[15] = a[15];\n }\n\n return out;\n}\n\n/**\n * Inverts a mat4\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the source matrix\n * @returns {mat4} out\n */\nexport function invert(out, a) {\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\n\n let b00 = a00 * a11 - a01 * a10;\n let b01 = a00 * a12 - a02 * a10;\n let b02 = a00 * a13 - a03 * a10;\n let b03 = a01 * a12 - a02 * a11;\n let b04 = a01 * a13 - a03 * a11;\n let b05 = a02 * a13 - a03 * a12;\n let b06 = a20 * a31 - a21 * a30;\n let b07 = a20 * a32 - a22 * a30;\n let b08 = a20 * a33 - a23 * a30;\n let b09 = a21 * a32 - a22 * a31;\n let b10 = a21 * a33 - a23 * a31;\n let b11 = a22 * a33 - a23 * a32;\n\n // Calculate the determinant\n let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n\n if (!det) {\n return null;\n }\n det = 1.0 / det;\n\n out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;\n out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;\n out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;\n out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;\n out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;\n out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;\n out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;\n out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;\n out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;\n out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;\n out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;\n out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;\n out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;\n out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;\n out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;\n out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;\n\n return out;\n}\n\n/**\n * Calculates the adjugate of a mat4\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the source matrix\n * @returns {mat4} out\n */\nexport function adjoint(out, a) {\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\n\n out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));\n out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));\n out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));\n out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));\n out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));\n out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));\n out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));\n out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));\n out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));\n out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));\n out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));\n out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));\n out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));\n out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));\n out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));\n out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));\n return out;\n}\n\n/**\n * Calculates the determinant of a mat4\n *\n * @param {mat4} a the source matrix\n * @returns {Number} determinant of a\n */\nexport function determinant(a) {\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\n\n let b00 = a00 * a11 - a01 * a10;\n let b01 = a00 * a12 - a02 * a10;\n let b02 = a00 * a13 - a03 * a10;\n let b03 = a01 * a12 - a02 * a11;\n let b04 = a01 * a13 - a03 * a11;\n let b05 = a02 * a13 - a03 * a12;\n let b06 = a20 * a31 - a21 * a30;\n let b07 = a20 * a32 - a22 * a30;\n let b08 = a20 * a33 - a23 * a30;\n let b09 = a21 * a32 - a22 * a31;\n let b10 = a21 * a33 - a23 * a31;\n let b11 = a22 * a33 - a23 * a32;\n\n // Calculate the determinant\n return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n}\n\n/**\n * Multiplies two mat4s\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the first operand\n * @param {mat4} b the second operand\n * @returns {mat4} out\n */\nexport function multiply(out, a, b) {\n let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\n let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\n let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\n let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\n\n // Cache only the current line of the second matrix\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\n out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\n out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\n out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\n\n b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];\n out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\n out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\n out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\n out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\n\n b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];\n out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\n out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\n out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\n out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\n\n b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];\n out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\n out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\n out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\n out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\n return out;\n}\n\n/**\n * Translate a mat4 by the given vector\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to translate\n * @param {vec3} v vector to translate by\n * @returns {mat4} out\n */\nexport function translate(out, a, v) {\n let x = v[0], y = v[1], z = v[2];\n let a00, a01, a02, a03;\n let a10, a11, a12, a13;\n let a20, a21, a22, a23;\n\n if (a === out) {\n out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];\n out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];\n out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];\n out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];\n } else {\n a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];\n a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];\n a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];\n\n out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03;\n out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13;\n out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23;\n\n out[12] = a00 * x + a10 * y + a20 * z + a[12];\n out[13] = a01 * x + a11 * y + a21 * z + a[13];\n out[14] = a02 * x + a12 * y + a22 * z + a[14];\n out[15] = a03 * x + a13 * y + a23 * z + a[15];\n }\n\n return out;\n}\n\n/**\n * Scales the mat4 by the dimensions in the given vec3 not using vectorization\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to scale\n * @param {vec3} v the vec3 to scale the matrix by\n * @returns {mat4} out\n **/\nexport function scale(out, a, v) {\n let x = v[0], y = v[1], z = v[2];\n\n out[0] = a[0] * x;\n out[1] = a[1] * x;\n out[2] = a[2] * x;\n out[3] = a[3] * x;\n out[4] = a[4] * y;\n out[5] = a[5] * y;\n out[6] = a[6] * y;\n out[7] = a[7] * y;\n out[8] = a[8] * z;\n out[9] = a[9] * z;\n out[10] = a[10] * z;\n out[11] = a[11] * z;\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n return out;\n}\n\n/**\n * Rotates a mat4 by the given angle around the given axis\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @param {vec3} axis the axis to rotate around\n * @returns {mat4} out\n */\nexport function rotate(out, a, rad, axis) {\n let x = axis[0], y = axis[1], z = axis[2];\n let len = Math.sqrt(x * x + y * y + z * z);\n let s, c, t;\n let a00, a01, a02, a03;\n let a10, a11, a12, a13;\n let a20, a21, a22, a23;\n let b00, b01, b02;\n let b10, b11, b12;\n let b20, b21, b22;\n\n if (len < glMatrix.EPSILON) { return null; }\n\n len = 1 / len;\n x *= len;\n y *= len;\n z *= len;\n\n s = Math.sin(rad);\n c = Math.cos(rad);\n t = 1 - c;\n\n a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];\n a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];\n a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];\n\n // Construct the elements of the rotation matrix\n b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;\n b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;\n b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;\n\n // Perform rotation-specific matrix multiplication\n out[0] = a00 * b00 + a10 * b01 + a20 * b02;\n out[1] = a01 * b00 + a11 * b01 + a21 * b02;\n out[2] = a02 * b00 + a12 * b01 + a22 * b02;\n out[3] = a03 * b00 + a13 * b01 + a23 * b02;\n out[4] = a00 * b10 + a10 * b11 + a20 * b12;\n out[5] = a01 * b10 + a11 * b11 + a21 * b12;\n out[6] = a02 * b10 + a12 * b11 + a22 * b12;\n out[7] = a03 * b10 + a13 * b11 + a23 * b12;\n out[8] = a00 * b20 + a10 * b21 + a20 * b22;\n out[9] = a01 * b20 + a11 * b21 + a21 * b22;\n out[10] = a02 * b20 + a12 * b21 + a22 * b22;\n out[11] = a03 * b20 + a13 * b21 + a23 * b22;\n\n if (a !== out) { // If the source and destination differ, copy the unchanged last row\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n }\n return out;\n}\n\n/**\n * Rotates a matrix by the given angle around the X axis\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function rotateX(out, a, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n let a10 = a[4];\n let a11 = a[5];\n let a12 = a[6];\n let a13 = a[7];\n let a20 = a[8];\n let a21 = a[9];\n let a22 = a[10];\n let a23 = a[11];\n\n if (a !== out) { // If the source and destination differ, copy the unchanged rows\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n }\n\n // Perform axis-specific matrix multiplication\n out[4] = a10 * c + a20 * s;\n out[5] = a11 * c + a21 * s;\n out[6] = a12 * c + a22 * s;\n out[7] = a13 * c + a23 * s;\n out[8] = a20 * c - a10 * s;\n out[9] = a21 * c - a11 * s;\n out[10] = a22 * c - a12 * s;\n out[11] = a23 * c - a13 * s;\n return out;\n}\n\n/**\n * Rotates a matrix by the given angle around the Y axis\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function rotateY(out, a, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n let a00 = a[0];\n let a01 = a[1];\n let a02 = a[2];\n let a03 = a[3];\n let a20 = a[8];\n let a21 = a[9];\n let a22 = a[10];\n let a23 = a[11];\n\n if (a !== out) { // If the source and destination differ, copy the unchanged rows\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n }\n\n // Perform axis-specific matrix multiplication\n out[0] = a00 * c - a20 * s;\n out[1] = a01 * c - a21 * s;\n out[2] = a02 * c - a22 * s;\n out[3] = a03 * c - a23 * s;\n out[8] = a00 * s + a20 * c;\n out[9] = a01 * s + a21 * c;\n out[10] = a02 * s + a22 * c;\n out[11] = a03 * s + a23 * c;\n return out;\n}\n\n/**\n * Rotates a matrix by the given angle around the Z axis\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to rotate\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function rotateZ(out, a, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n let a00 = a[0];\n let a01 = a[1];\n let a02 = a[2];\n let a03 = a[3];\n let a10 = a[4];\n let a11 = a[5];\n let a12 = a[6];\n let a13 = a[7];\n\n if (a !== out) { // If the source and destination differ, copy the unchanged last row\n out[8] = a[8];\n out[9] = a[9];\n out[10] = a[10];\n out[11] = a[11];\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n }\n\n // Perform axis-specific matrix multiplication\n out[0] = a00 * c + a10 * s;\n out[1] = a01 * c + a11 * s;\n out[2] = a02 * c + a12 * s;\n out[3] = a03 * c + a13 * s;\n out[4] = a10 * c - a00 * s;\n out[5] = a11 * c - a01 * s;\n out[6] = a12 * c - a02 * s;\n out[7] = a13 * c - a03 * s;\n return out;\n}\n\n/**\n * Creates a matrix from a vector translation\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.translate(dest, dest, vec);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {vec3} v Translation vector\n * @returns {mat4} out\n */\nexport function fromTranslation(out, v) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = 1;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0;\n out[12] = v[0];\n out[13] = v[1];\n out[14] = v[2];\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from a vector scaling\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.scale(dest, dest, vec);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {vec3} v Scaling vector\n * @returns {mat4} out\n */\nexport function fromScaling(out, v) {\n out[0] = v[0];\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = v[1];\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = v[2];\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from a given angle around a given axis\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.rotate(dest, dest, rad, axis);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @param {vec3} axis the axis to rotate around\n * @returns {mat4} out\n */\nexport function fromRotation(out, rad, axis) {\n let x = axis[0], y = axis[1], z = axis[2];\n let len = Math.sqrt(x * x + y * y + z * z);\n let s, c, t;\n\n if (len < glMatrix.EPSILON) { return null; }\n\n len = 1 / len;\n x *= len;\n y *= len;\n z *= len;\n\n s = Math.sin(rad);\n c = Math.cos(rad);\n t = 1 - c;\n\n // Perform rotation-specific matrix multiplication\n out[0] = x * x * t + c;\n out[1] = y * x * t + z * s;\n out[2] = z * x * t - y * s;\n out[3] = 0;\n out[4] = x * y * t - z * s;\n out[5] = y * y * t + c;\n out[6] = z * y * t + x * s;\n out[7] = 0;\n out[8] = x * z * t + y * s;\n out[9] = y * z * t - x * s;\n out[10] = z * z * t + c;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from the given angle around the X axis\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.rotateX(dest, dest, rad);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function fromXRotation(out, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n\n // Perform axis-specific matrix multiplication\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = c;\n out[6] = s;\n out[7] = 0;\n out[8] = 0;\n out[9] = -s;\n out[10] = c;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from the given angle around the Y axis\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.rotateY(dest, dest, rad);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function fromYRotation(out, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n\n // Perform axis-specific matrix multiplication\n out[0] = c;\n out[1] = 0;\n out[2] = -s;\n out[3] = 0;\n out[4] = 0;\n out[5] = 1;\n out[6] = 0;\n out[7] = 0;\n out[8] = s;\n out[9] = 0;\n out[10] = c;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from the given angle around the Z axis\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.rotateZ(dest, dest, rad);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {Number} rad the angle to rotate the matrix by\n * @returns {mat4} out\n */\nexport function fromZRotation(out, rad) {\n let s = Math.sin(rad);\n let c = Math.cos(rad);\n\n // Perform axis-specific matrix multiplication\n out[0] = c;\n out[1] = s;\n out[2] = 0;\n out[3] = 0;\n out[4] = -s;\n out[5] = c;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n}\n\n/**\n * Creates a matrix from a quaternion rotation and vector translation\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.translate(dest, vec);\n * let quatMat = mat4.create();\n * quat4.toMat4(quat, quatMat);\n * mat4.multiply(dest, quatMat);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {quat4} q Rotation quaternion\n * @param {vec3} v Translation vector\n * @returns {mat4} out\n */\nexport function fromRotationTranslation(out, q, v) {\n // Quaternion math\n let x = q[0], y = q[1], z = q[2], w = q[3];\n let x2 = x + x;\n let y2 = y + y;\n let z2 = z + z;\n\n let xx = x * x2;\n let xy = x * y2;\n let xz = x * z2;\n let yy = y * y2;\n let yz = y * z2;\n let zz = z * z2;\n let wx = w * x2;\n let wy = w * y2;\n let wz = w * z2;\n\n out[0] = 1 - (yy + zz);\n out[1] = xy + wz;\n out[2] = xz - wy;\n out[3] = 0;\n out[4] = xy - wz;\n out[5] = 1 - (xx + zz);\n out[6] = yz + wx;\n out[7] = 0;\n out[8] = xz + wy;\n out[9] = yz - wx;\n out[10] = 1 - (xx + yy);\n out[11] = 0;\n out[12] = v[0];\n out[13] = v[1];\n out[14] = v[2];\n out[15] = 1;\n\n return out;\n}\n\n/**\n * Creates a new mat4 from a dual quat.\n *\n * @param {mat4} out Matrix\n * @param {quat2} a Dual Quaternion\n * @returns {mat4} mat4 receiving operation result\n */\nexport function fromQuat2(out, a) {\n let translation = new glMatrix.ARRAY_TYPE(3);\n let bx = -a[0], by = -a[1], bz = -a[2], bw = a[3],\n ax = a[4], ay = a[5], az = a[6], aw = a[7];\n\n let magnitude = bx * bx + by * by + bz * bz + bw * bw;\n //Only scale if it makes sense\n if (magnitude > 0) {\n translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;\n translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;\n translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;\n } else {\n translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;\n translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;\n translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;\n }\n fromRotationTranslation(out, a, translation);\n return out;\n}\n\n/**\n * Returns the translation vector component of a transformation\n * matrix. If a matrix is built with fromRotationTranslation,\n * the returned vector will be the same as the translation vector\n * originally supplied.\n * @param {vec3} out Vector to receive translation component\n * @param {mat4} mat Matrix to be decomposed (input)\n * @return {vec3} out\n */\nexport function getTranslation(out, mat) {\n out[0] = mat[12];\n out[1] = mat[13];\n out[2] = mat[14];\n\n return out;\n}\n\n/**\n * Returns the scaling factor component of a transformation\n * matrix. If a matrix is built with fromRotationTranslationScale\n * with a normalized Quaternion paramter, the returned vector will be\n * the same as the scaling vector\n * originally supplied.\n * @param {vec3} out Vector to receive scaling factor component\n * @param {mat4} mat Matrix to be decomposed (input)\n * @return {vec3} out\n */\nexport function getScaling(out, mat) {\n let m11 = mat[0];\n let m12 = mat[1];\n let m13 = mat[2];\n let m21 = mat[4];\n let m22 = mat[5];\n let m23 = mat[6];\n let m31 = mat[8];\n let m32 = mat[9];\n let m33 = mat[10];\n\n out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);\n out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);\n out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);\n\n return out;\n}\n\n/**\n * Returns a quaternion representing the rotational component\n * of a transformation matrix. If a matrix is built with\n * fromRotationTranslation, the returned quaternion will be the\n * same as the quaternion originally supplied.\n * @param {quat} out Quaternion to receive the rotation component\n * @param {mat4} mat Matrix to be decomposed (input)\n * @return {quat} out\n */\nexport function getRotation(out, mat) {\n // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm\n let trace = mat[0] + mat[5] + mat[10];\n let S = 0;\n\n if (trace > 0) {\n S = Math.sqrt(trace + 1.0) * 2;\n out[3] = 0.25 * S;\n out[0] = (mat[6] - mat[9]) / S;\n out[1] = (mat[8] - mat[2]) / S;\n out[2] = (mat[1] - mat[4]) / S;\n } else if ((mat[0] > mat[5]) && (mat[0] > mat[10])) {\n S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2;\n out[3] = (mat[6] - mat[9]) / S;\n out[0] = 0.25 * S;\n out[1] = (mat[1] + mat[4]) / S;\n out[2] = (mat[8] + mat[2]) / S;\n } else if (mat[5] > mat[10]) {\n S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2;\n out[3] = (mat[8] - mat[2]) / S;\n out[0] = (mat[1] + mat[4]) / S;\n out[1] = 0.25 * S;\n out[2] = (mat[6] + mat[9]) / S;\n } else {\n S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2;\n out[3] = (mat[1] - mat[4]) / S;\n out[0] = (mat[8] + mat[2]) / S;\n out[1] = (mat[6] + mat[9]) / S;\n out[2] = 0.25 * S;\n }\n\n return out;\n}\n\n/**\n * Creates a matrix from a quaternion rotation, vector translation and vector scale\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.translate(dest, vec);\n * let quatMat = mat4.create();\n * quat4.toMat4(quat, quatMat);\n * mat4.multiply(dest, quatMat);\n * mat4.scale(dest, scale)\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {quat4} q Rotation quaternion\n * @param {vec3} v Translation vector\n * @param {vec3} s Scaling vector\n * @returns {mat4} out\n */\nexport function fromRotationTranslationScale(out, q, v, s) {\n // Quaternion math\n let x = q[0], y = q[1], z = q[2], w = q[3];\n let x2 = x + x;\n let y2 = y + y;\n let z2 = z + z;\n\n let xx = x * x2;\n let xy = x * y2;\n let xz = x * z2;\n let yy = y * y2;\n let yz = y * z2;\n let zz = z * z2;\n let wx = w * x2;\n let wy = w * y2;\n let wz = w * z2;\n let sx = s[0];\n let sy = s[1];\n let sz = s[2];\n\n out[0] = (1 - (yy + zz)) * sx;\n out[1] = (xy + wz) * sx;\n out[2] = (xz - wy) * sx;\n out[3] = 0;\n out[4] = (xy - wz) * sy;\n out[5] = (1 - (xx + zz)) * sy;\n out[6] = (yz + wx) * sy;\n out[7] = 0;\n out[8] = (xz + wy) * sz;\n out[9] = (yz - wx) * sz;\n out[10] = (1 - (xx + yy)) * sz;\n out[11] = 0;\n out[12] = v[0];\n out[13] = v[1];\n out[14] = v[2];\n out[15] = 1;\n\n return out;\n}\n\n/**\n * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin\n * This is equivalent to (but much faster than):\n *\n * mat4.identity(dest);\n * mat4.translate(dest, vec);\n * mat4.translate(dest, origin);\n * let quatMat = mat4.create();\n * quat4.toMat4(quat, quatMat);\n * mat4.multiply(dest, quatMat);\n * mat4.scale(dest, scale)\n * mat4.translate(dest, negativeOrigin);\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {quat4} q Rotation quaternion\n * @param {vec3} v Translation vector\n * @param {vec3} s Scaling vector\n * @param {vec3} o The origin vector around which to scale and rotate\n * @returns {mat4} out\n */\nexport function fromRotationTranslationScaleOrigin(out, q, v, s, o) {\n // Quaternion math\n let x = q[0], y = q[1], z = q[2], w = q[3];\n let x2 = x + x;\n let y2 = y + y;\n let z2 = z + z;\n\n let xx = x * x2;\n let xy = x * y2;\n let xz = x * z2;\n let yy = y * y2;\n let yz = y * z2;\n let zz = z * z2;\n let wx = w * x2;\n let wy = w * y2;\n let wz = w * z2;\n\n let sx = s[0];\n let sy = s[1];\n let sz = s[2];\n\n let ox = o[0];\n let oy = o[1];\n let oz = o[2];\n\n let out0 = (1 - (yy + zz)) * sx;\n let out1 = (xy + wz) * sx;\n let out2 = (xz - wy) * sx;\n let out4 = (xy - wz) * sy;\n let out5 = (1 - (xx + zz)) * sy;\n let out6 = (yz + wx) * sy;\n let out8 = (xz + wy) * sz;\n let out9 = (yz - wx) * sz;\n let out10 = (1 - (xx + yy)) * sz;\n\n out[0] = out0;\n out[1] = out1;\n out[2] = out2;\n out[3] = 0;\n out[4] = out4;\n out[5] = out5;\n out[6] = out6;\n out[7] = 0;\n out[8] = out8;\n out[9] = out9;\n out[10] = out10;\n out[11] = 0;\n out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);\n out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);\n out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);\n out[15] = 1;\n\n return out;\n}\n\n/**\n * Calculates a 4x4 matrix from the given quaternion\n *\n * @param {mat4} out mat4 receiving operation result\n * @param {quat} q Quaternion to create matrix from\n *\n * @returns {mat4} out\n */\nexport function fromQuat(out, q) {\n let x = q[0], y = q[1], z = q[2], w = q[3];\n let x2 = x + x;\n let y2 = y + y;\n let z2 = z + z;\n\n let xx = x * x2;\n let yx = y * x2;\n let yy = y * y2;\n let zx = z * x2;\n let zy = z * y2;\n let zz = z * z2;\n let wx = w * x2;\n let wy = w * y2;\n let wz = w * z2;\n\n out[0] = 1 - yy - zz;\n out[1] = yx + wz;\n out[2] = zx - wy;\n out[3] = 0;\n\n out[4] = yx - wz;\n out[5] = 1 - xx - zz;\n out[6] = zy + wx;\n out[7] = 0;\n\n out[8] = zx + wy;\n out[9] = zy - wx;\n out[10] = 1 - xx - yy;\n out[11] = 0;\n\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n\n return out;\n}\n\n/**\n * Generates a frustum matrix with the given bounds\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {Number} left Left bound of the frustum\n * @param {Number} right Right bound of the frustum\n * @param {Number} bottom Bottom bound of the frustum\n * @param {Number} top Top bound of the frustum\n * @param {Number} near Near bound of the frustum\n * @param {Number} far Far bound of the frustum\n * @returns {mat4} out\n */\nexport function frustum(out, left, right, bottom, top, near, far) {\n let rl = 1 / (right - left);\n let tb = 1 / (top - bottom);\n let nf = 1 / (near - far);\n out[0] = (near * 2) * rl;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = (near * 2) * tb;\n out[6] = 0;\n out[7] = 0;\n out[8] = (right + left) * rl;\n out[9] = (top + bottom) * tb;\n out[10] = (far + near) * nf;\n out[11] = -1;\n out[12] = 0;\n out[13] = 0;\n out[14] = (far * near * 2) * nf;\n out[15] = 0;\n return out;\n}\n\n/**\n * Generates a perspective projection matrix with the given bounds.\n * Passing null/undefined/no value for far will generate infinite projection matrix.\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {number} fovy Vertical field of view in radians\n * @param {number} aspect Aspect ratio. typically viewport width/height\n * @param {number} near Near bound of the frustum\n * @param {number} far Far bound of the frustum, can be null or Infinity\n * @returns {mat4} out\n */\nexport function perspective(out, fovy, aspect, near, far) {\n let f = 1.0 / Math.tan(fovy / 2), nf;\n out[0] = f / aspect;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = f;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[11] = -1;\n out[12] = 0;\n out[13] = 0;\n out[15] = 0;\n if (far != null && far !== Infinity) {\n nf = 1 / (near - far);\n out[10] = (far + near) * nf;\n out[14] = (2 * far * near) * nf;\n } else {\n out[10] = -1;\n out[14] = -2 * near;\n }\n return out;\n}\n\n/**\n * Generates a perspective projection matrix with the given field of view.\n * This is primarily useful for generating projection matrices to be used\n * with the still experiemental WebVR API.\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees\n * @param {number} near Near bound of the frustum\n * @param {number} far Far bound of the frustum\n * @returns {mat4} out\n */\nexport function perspectiveFromFieldOfView(out, fov, near, far) {\n let upTan = Math.tan(fov.upDegrees * Math.PI/180.0);\n let downTan = Math.tan(fov.downDegrees * Math.PI/180.0);\n let leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0);\n let rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0);\n let xScale = 2.0 / (leftTan + rightTan);\n let yScale = 2.0 / (upTan + downTan);\n\n out[0] = xScale;\n out[1] = 0.0;\n out[2] = 0.0;\n out[3] = 0.0;\n out[4] = 0.0;\n out[5] = yScale;\n out[6] = 0.0;\n out[7] = 0.0;\n out[8] = -((leftTan - rightTan) * xScale * 0.5);\n out[9] = ((upTan - downTan) * yScale * 0.5);\n out[10] = far / (near - far);\n out[11] = -1.0;\n out[12] = 0.0;\n out[13] = 0.0;\n out[14] = (far * near) / (near - far);\n out[15] = 0.0;\n return out;\n}\n\n/**\n * Generates a orthogonal projection matrix with the given bounds\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {number} left Left bound of the frustum\n * @param {number} right Right bound of the frustum\n * @param {number} bottom Bottom bound of the frustum\n * @param {number} top Top bound of the frustum\n * @param {number} near Near bound of the frustum\n * @param {number} far Far bound of the frustum\n * @returns {mat4} out\n */\nexport function ortho(out, left, right, bottom, top, near, far) {\n let lr = 1 / (left - right);\n let bt = 1 / (bottom - top);\n let nf = 1 / (near - far);\n out[0] = -2 * lr;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = -2 * bt;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 2 * nf;\n out[11] = 0;\n out[12] = (left + right) * lr;\n out[13] = (top + bottom) * bt;\n out[14] = (far + near) * nf;\n out[15] = 1;\n return out;\n}\n\n/**\n * Generates a look-at matrix with the given eye position, focal point, and up axis.\n * If you want a matrix that actually makes an object look at another object, you should use targetTo instead.\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {vec3} eye Position of the viewer\n * @param {vec3} center Point the viewer is looking at\n * @param {vec3} up vec3 pointing up\n * @returns {mat4} out\n */\nexport function lookAt(out, eye, center, up) {\n let x0, x1, x2, y0, y1, y2, z0, z1, z2, len;\n let eyex = eye[0];\n let eyey = eye[1];\n let eyez = eye[2];\n let upx = up[0];\n let upy = up[1];\n let upz = up[2];\n let centerx = center[0];\n let centery = center[1];\n let centerz = center[2];\n\n if (Math.abs(eyex - centerx) < glMatrix.EPSILON &&\n Math.abs(eyey - centery) < glMatrix.EPSILON &&\n Math.abs(eyez - centerz) < glMatrix.EPSILON) {\n return identity(out);\n }\n\n z0 = eyex - centerx;\n z1 = eyey - centery;\n z2 = eyez - centerz;\n\n len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);\n z0 *= len;\n z1 *= len;\n z2 *= len;\n\n x0 = upy * z2 - upz * z1;\n x1 = upz * z0 - upx * z2;\n x2 = upx * z1 - upy * z0;\n len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);\n if (!len) {\n x0 = 0;\n x1 = 0;\n x2 = 0;\n } else {\n len = 1 / len;\n x0 *= len;\n x1 *= len;\n x2 *= len;\n }\n\n y0 = z1 * x2 - z2 * x1;\n y1 = z2 * x0 - z0 * x2;\n y2 = z0 * x1 - z1 * x0;\n\n len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);\n if (!len) {\n y0 = 0;\n y1 = 0;\n y2 = 0;\n } else {\n len = 1 / len;\n y0 *= len;\n y1 *= len;\n y2 *= len;\n }\n\n out[0] = x0;\n out[1] = y0;\n out[2] = z0;\n out[3] = 0;\n out[4] = x1;\n out[5] = y1;\n out[6] = z1;\n out[7] = 0;\n out[8] = x2;\n out[9] = y2;\n out[10] = z2;\n out[11] = 0;\n out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);\n out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);\n out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);\n out[15] = 1;\n\n return out;\n}\n\n/**\n * Generates a matrix that makes something look at something else.\n *\n * @param {mat4} out mat4 frustum matrix will be written into\n * @param {vec3} eye Position of the viewer\n * @param {vec3} center Point the viewer is looking at\n * @param {vec3} up vec3 pointing up\n * @returns {mat4} out\n */\nexport function targetTo(out, eye, target, up) {\n let eyex = eye[0],\n eyey = eye[1],\n eyez = eye[2],\n upx = up[0],\n upy = up[1],\n upz = up[2];\n\n let z0 = eyex - target[0],\n z1 = eyey - target[1],\n z2 = eyez - target[2];\n\n let len = z0*z0 + z1*z1 + z2*z2;\n if (len > 0) {\n len = 1 / Math.sqrt(len);\n z0 *= len;\n z1 *= len;\n z2 *= len;\n }\n\n let x0 = upy * z2 - upz * z1,\n x1 = upz * z0 - upx * z2,\n x2 = upx * z1 - upy * z0;\n\n len = x0*x0 + x1*x1 + x2*x2;\n if (len > 0) {\n len = 1 / Math.sqrt(len);\n x0 *= len;\n x1 *= len;\n x2 *= len;\n }\n\n out[0] = x0;\n out[1] = x1;\n out[2] = x2;\n out[3] = 0;\n out[4] = z1 * x2 - z2 * x1;\n out[5] = z2 * x0 - z0 * x2;\n out[6] = z0 * x1 - z1 * x0;\n out[7] = 0;\n out[8] = z0;\n out[9] = z1;\n out[10] = z2;\n out[11] = 0;\n out[12] = eyex;\n out[13] = eyey;\n out[14] = eyez;\n out[15] = 1;\n return out;\n};\n\n/**\n * Returns a string representation of a mat4\n *\n * @param {mat4} a matrix to represent as a string\n * @returns {String} string representation of the matrix\n */\nexport function str(a) {\n return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +\n a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +\n a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +\n a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';\n}\n\n/**\n * Returns Frobenius norm of a mat4\n *\n * @param {mat4} a the matrix to calculate Frobenius norm of\n * @returns {Number} Frobenius norm\n */\nexport function frob(a) {\n return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) ))\n}\n\n/**\n * Adds two mat4's\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the first operand\n * @param {mat4} b the second operand\n * @returns {mat4} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n out[4] = a[4] + b[4];\n out[5] = a[5] + b[5];\n out[6] = a[6] + b[6];\n out[7] = a[7] + b[7];\n out[8] = a[8] + b[8];\n out[9] = a[9] + b[9];\n out[10] = a[10] + b[10];\n out[11] = a[11] + b[11];\n out[12] = a[12] + b[12];\n out[13] = a[13] + b[13];\n out[14] = a[14] + b[14];\n out[15] = a[15] + b[15];\n return out;\n}\n\n/**\n * Subtracts matrix b from matrix a\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the first operand\n * @param {mat4} b the second operand\n * @returns {mat4} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n out[3] = a[3] - b[3];\n out[4] = a[4] - b[4];\n out[5] = a[5] - b[5];\n out[6] = a[6] - b[6];\n out[7] = a[7] - b[7];\n out[8] = a[8] - b[8];\n out[9] = a[9] - b[9];\n out[10] = a[10] - b[10];\n out[11] = a[11] - b[11];\n out[12] = a[12] - b[12];\n out[13] = a[13] - b[13];\n out[14] = a[14] - b[14];\n out[15] = a[15] - b[15];\n return out;\n}\n\n/**\n * Multiply each element of the matrix by a scalar.\n *\n * @param {mat4} out the receiving matrix\n * @param {mat4} a the matrix to scale\n * @param {Number} b amount to scale the matrix's elements by\n * @returns {mat4} out\n */\nexport function multiplyScalar(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n out[4] = a[4] * b;\n out[5] = a[5] * b;\n out[6] = a[6] * b;\n out[7] = a[7] * b;\n out[8] = a[8] * b;\n out[9] = a[9] * b;\n out[10] = a[10] * b;\n out[11] = a[11] * b;\n out[12] = a[12] * b;\n out[13] = a[13] * b;\n out[14] = a[14] * b;\n out[15] = a[15] * b;\n return out;\n}\n\n/**\n * Adds two mat4's after multiplying each element of the second operand by a scalar value.\n *\n * @param {mat4} out the receiving vector\n * @param {mat4} a the first operand\n * @param {mat4} b the second operand\n * @param {Number} scale the amount to scale b's elements by before adding\n * @returns {mat4} out\n */\nexport function multiplyScalarAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n out[3] = a[3] + (b[3] * scale);\n out[4] = a[4] + (b[4] * scale);\n out[5] = a[5] + (b[5] * scale);\n out[6] = a[6] + (b[6] * scale);\n out[7] = a[7] + (b[7] * scale);\n out[8] = a[8] + (b[8] * scale);\n out[9] = a[9] + (b[9] * scale);\n out[10] = a[10] + (b[10] * scale);\n out[11] = a[11] + (b[11] * scale);\n out[12] = a[12] + (b[12] * scale);\n out[13] = a[13] + (b[13] * scale);\n out[14] = a[14] + (b[14] * scale);\n out[15] = a[15] + (b[15] * scale);\n return out;\n}\n\n/**\n * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\n *\n * @param {mat4} a The first matrix.\n * @param {mat4} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] &&\n a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] &&\n a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] &&\n a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];\n}\n\n/**\n * Returns whether or not the matrices have approximately the same elements in the same position.\n *\n * @param {mat4} a The first matrix.\n * @param {mat4} b The second matrix.\n * @returns {Boolean} True if the matrices are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7];\n let a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11];\n let a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15];\n\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n let b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7];\n let b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11];\n let b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];\n\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\n Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\n Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&\n Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&\n Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&\n Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)) &&\n Math.abs(a9 - b9) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a9), Math.abs(b9)) &&\n Math.abs(a10 - b10) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a10), Math.abs(b10)) &&\n Math.abs(a11 - b11) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a11), Math.abs(b11)) &&\n Math.abs(a12 - b12) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a12), Math.abs(b12)) &&\n Math.abs(a13 - b13) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a13), Math.abs(b13)) &&\n Math.abs(a14 - b14) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a14), Math.abs(b14)) &&\n Math.abs(a15 - b15) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a15), Math.abs(b15)));\n}\n\n/**\n * Alias for {@link mat4.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link mat4.subtract}\n * @function\n */\nexport const sub = subtract;\n","import * as glMatrix from \"./common.js\"\nimport * as mat3 from \"./mat3.js\"\nimport * as vec3 from \"./vec3.js\"\nimport * as vec4 from \"./vec4.js\"\n\n/**\n * Quaternion\n * @module quat\n */\n\n/**\n * Creates a new identity quat\n *\n * @returns {quat} a new quaternion\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(4);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n }\n out[3] = 1;\n return out;\n}\n\n/**\n * Set a quat to the identity quaternion\n *\n * @param {quat} out the receiving quaternion\n * @returns {quat} out\n */\nexport function identity(out) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n return out;\n}\n\n/**\n * Sets a quat from the given angle and rotation axis,\n * then returns it.\n *\n * @param {quat} out the receiving quaternion\n * @param {vec3} axis the axis around which to rotate\n * @param {Number} rad the angle in radians\n * @returns {quat} out\n **/\nexport function setAxisAngle(out, axis, rad) {\n rad = rad * 0.5;\n let s = Math.sin(rad);\n out[0] = s * axis[0];\n out[1] = s * axis[1];\n out[2] = s * axis[2];\n out[3] = Math.cos(rad);\n return out;\n}\n\n/**\n * Gets the rotation axis and angle for a given\n * quaternion. If a quaternion is created with\n * setAxisAngle, this method will return the same\n * values as providied in the original parameter list\n * OR functionally equivalent values.\n * Example: The quaternion formed by axis [0, 0, 1] and\n * angle -90 is the same as the quaternion formed by\n * [0, 0, 1] and 270. This method favors the latter.\n * @param {vec3} out_axis Vector receiving the axis of rotation\n * @param {quat} q Quaternion to be decomposed\n * @return {Number} Angle, in radians, of the rotation\n */\nexport function getAxisAngle(out_axis, q) {\n let rad = Math.acos(q[3]) * 2.0;\n let s = Math.sin(rad / 2.0);\n if (s > glMatrix.EPSILON) {\n out_axis[0] = q[0] / s;\n out_axis[1] = q[1] / s;\n out_axis[2] = q[2] / s;\n } else {\n // If s is zero, return any axis (no rotation - axis does not matter)\n out_axis[0] = 1;\n out_axis[1] = 0;\n out_axis[2] = 0;\n }\n return rad;\n}\n\n/**\n * Multiplies two quat's\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @returns {quat} out\n */\nexport function multiply(out, a, b) {\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\n let bx = b[0], by = b[1], bz = b[2], bw = b[3];\n\n out[0] = ax * bw + aw * bx + ay * bz - az * by;\n out[1] = ay * bw + aw * by + az * bx - ax * bz;\n out[2] = az * bw + aw * bz + ax * by - ay * bx;\n out[3] = aw * bw - ax * bx - ay * by - az * bz;\n return out;\n}\n\n/**\n * Rotates a quaternion by the given angle about the X axis\n *\n * @param {quat} out quat receiving operation result\n * @param {quat} a quat to rotate\n * @param {number} rad angle (in radians) to rotate\n * @returns {quat} out\n */\nexport function rotateX(out, a, rad) {\n rad *= 0.5;\n\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\n let bx = Math.sin(rad), bw = Math.cos(rad);\n\n out[0] = ax * bw + aw * bx;\n out[1] = ay * bw + az * bx;\n out[2] = az * bw - ay * bx;\n out[3] = aw * bw - ax * bx;\n return out;\n}\n\n/**\n * Rotates a quaternion by the given angle about the Y axis\n *\n * @param {quat} out quat receiving operation result\n * @param {quat} a quat to rotate\n * @param {number} rad angle (in radians) to rotate\n * @returns {quat} out\n */\nexport function rotateY(out, a, rad) {\n rad *= 0.5;\n\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\n let by = Math.sin(rad), bw = Math.cos(rad);\n\n out[0] = ax * bw - az * by;\n out[1] = ay * bw + aw * by;\n out[2] = az * bw + ax * by;\n out[3] = aw * bw - ay * by;\n return out;\n}\n\n/**\n * Rotates a quaternion by the given angle about the Z axis\n *\n * @param {quat} out quat receiving operation result\n * @param {quat} a quat to rotate\n * @param {number} rad angle (in radians) to rotate\n * @returns {quat} out\n */\nexport function rotateZ(out, a, rad) {\n rad *= 0.5;\n\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\n let bz = Math.sin(rad), bw = Math.cos(rad);\n\n out[0] = ax * bw + ay * bz;\n out[1] = ay * bw - ax * bz;\n out[2] = az * bw + aw * bz;\n out[3] = aw * bw - az * bz;\n return out;\n}\n\n/**\n * Calculates the W component of a quat from the X, Y, and Z components.\n * Assumes that quaternion is 1 unit in length.\n * Any existing W component will be ignored.\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a quat to calculate W component of\n * @returns {quat} out\n */\nexport function calculateW(out, a) {\n let x = a[0], y = a[1], z = a[2];\n\n out[0] = x;\n out[1] = y;\n out[2] = z;\n out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));\n return out;\n}\n\n/**\n * Performs a spherical linear interpolation between two quat\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {quat} out\n */\nexport function slerp(out, a, b, t) {\n // benchmarks:\n // http://jsperf.com/quaternion-slerp-implementations\n let ax = a[0], ay = a[1], az = a[2], aw = a[3];\n let bx = b[0], by = b[1], bz = b[2], bw = b[3];\n\n let omega, cosom, sinom, scale0, scale1;\n\n // calc cosine\n cosom = ax * bx + ay * by + az * bz + aw * bw;\n // adjust signs (if necessary)\n if ( cosom < 0.0 ) {\n cosom = -cosom;\n bx = - bx;\n by = - by;\n bz = - bz;\n bw = - bw;\n }\n // calculate coefficients\n if ( (1.0 - cosom) > glMatrix.EPSILON ) {\n // standard case (slerp)\n omega = Math.acos(cosom);\n sinom = Math.sin(omega);\n scale0 = Math.sin((1.0 - t) * omega) / sinom;\n scale1 = Math.sin(t * omega) / sinom;\n } else {\n // \"from\" and \"to\" quaternions are very close\n // ... so we can do a linear interpolation\n scale0 = 1.0 - t;\n scale1 = t;\n }\n // calculate final values\n out[0] = scale0 * ax + scale1 * bx;\n out[1] = scale0 * ay + scale1 * by;\n out[2] = scale0 * az + scale1 * bz;\n out[3] = scale0 * aw + scale1 * bw;\n\n return out;\n}\n\n/**\n * Generates a random quaternion\n *\n * @param {quat} out the receiving quaternion\n * @returns {quat} out\n */\nexport function random(out) {\n // Implementation of http://planning.cs.uiuc.edu/node198.html\n // TODO: Calling random 3 times is probably not the fastest solution\n let u1 = glMatrix.RANDOM();\n let u2 = glMatrix.RANDOM();\n let u3 = glMatrix.RANDOM();\n\n let sqrt1MinusU1 = Math.sqrt(1 - u1);\n let sqrtU1 = Math.sqrt(u1);\n\n out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2);\n out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2);\n out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3);\n out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3);\n return out;\n}\n\n/**\n * Calculates the inverse of a quat\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a quat to calculate inverse of\n * @returns {quat} out\n */\nexport function invert(out, a) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let dot = a0*a0 + a1*a1 + a2*a2 + a3*a3;\n let invDot = dot ? 1.0/dot : 0;\n\n // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0\n\n out[0] = -a0*invDot;\n out[1] = -a1*invDot;\n out[2] = -a2*invDot;\n out[3] = a3*invDot;\n return out;\n}\n\n/**\n * Calculates the conjugate of a quat\n * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a quat to calculate conjugate of\n * @returns {quat} out\n */\nexport function conjugate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n out[2] = -a[2];\n out[3] = a[3];\n return out;\n}\n\n/**\n * Creates a quaternion from the given 3x3 rotation matrix.\n *\n * NOTE: The resultant quaternion is not normalized, so you should be sure\n * to renormalize the quaternion yourself where necessary.\n *\n * @param {quat} out the receiving quaternion\n * @param {mat3} m rotation matrix\n * @returns {quat} out\n * @function\n */\nexport function fromMat3(out, m) {\n // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes\n // article \"Quaternion Calculus and Fast Animation\".\n let fTrace = m[0] + m[4] + m[8];\n let fRoot;\n\n if ( fTrace > 0.0 ) {\n // |w| > 1/2, may as well choose w > 1/2\n fRoot = Math.sqrt(fTrace + 1.0); // 2w\n out[3] = 0.5 * fRoot;\n fRoot = 0.5/fRoot; // 1/(4w)\n out[0] = (m[5]-m[7])*fRoot;\n out[1] = (m[6]-m[2])*fRoot;\n out[2] = (m[1]-m[3])*fRoot;\n } else {\n // |w| <= 1/2\n let i = 0;\n if ( m[4] > m[0] )\n i = 1;\n if ( m[8] > m[i*3+i] )\n i = 2;\n let j = (i+1)%3;\n let k = (i+2)%3;\n\n fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);\n out[i] = 0.5 * fRoot;\n fRoot = 0.5 / fRoot;\n out[3] = (m[j*3+k] - m[k*3+j]) * fRoot;\n out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;\n out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;\n }\n\n return out;\n}\n\n/**\n * Creates a quaternion from the given euler angle x, y, z.\n *\n * @param {quat} out the receiving quaternion\n * @param {x} Angle to rotate around X axis in degrees.\n * @param {y} Angle to rotate around Y axis in degrees.\n * @param {z} Angle to rotate around Z axis in degrees.\n * @returns {quat} out\n * @function\n */\nexport function fromEuler(out, x, y, z) {\n let halfToRad = 0.5 * Math.PI / 180.0;\n x *= halfToRad;\n y *= halfToRad;\n z *= halfToRad;\n\n let sx = Math.sin(x);\n let cx = Math.cos(x);\n let sy = Math.sin(y);\n let cy = Math.cos(y);\n let sz = Math.sin(z);\n let cz = Math.cos(z);\n\n out[0] = sx * cy * cz - cx * sy * sz;\n out[1] = cx * sy * cz + sx * cy * sz;\n out[2] = cx * cy * sz - sx * sy * cz;\n out[3] = cx * cy * cz + sx * sy * sz;\n\n return out;\n}\n\n/**\n * Returns a string representation of a quatenion\n *\n * @param {quat} a vector to represent as a string\n * @returns {String} string representation of the vector\n */\nexport function str(a) {\n return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\n}\n\n/**\n * Creates a new quat initialized with values from an existing quaternion\n *\n * @param {quat} a quaternion to clone\n * @returns {quat} a new quaternion\n * @function\n */\nexport const clone = vec4.clone;\n\n/**\n * Creates a new quat initialized with the given values\n *\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @param {Number} w W component\n * @returns {quat} a new quaternion\n * @function\n */\nexport const fromValues = vec4.fromValues;\n\n/**\n * Copy the values from one quat to another\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the source quaternion\n * @returns {quat} out\n * @function\n */\nexport const copy = vec4.copy;\n\n/**\n * Set the components of a quat to the given values\n *\n * @param {quat} out the receiving quaternion\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @param {Number} w W component\n * @returns {quat} out\n * @function\n */\nexport const set = vec4.set;\n\n/**\n * Adds two quat's\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @returns {quat} out\n * @function\n */\nexport const add = vec4.add;\n\n/**\n * Alias for {@link quat.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Scales a quat by a scalar number\n *\n * @param {quat} out the receiving vector\n * @param {quat} a the vector to scale\n * @param {Number} b amount to scale the vector by\n * @returns {quat} out\n * @function\n */\nexport const scale = vec4.scale;\n\n/**\n * Calculates the dot product of two quat's\n *\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @returns {Number} dot product of a and b\n * @function\n */\nexport const dot = vec4.dot;\n\n/**\n * Performs a linear interpolation between two quat's\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {quat} out\n * @function\n */\nexport const lerp = vec4.lerp;\n\n/**\n * Calculates the length of a quat\n *\n * @param {quat} a vector to calculate length of\n * @returns {Number} length of a\n */\nexport const length = vec4.length;\n\n/**\n * Alias for {@link quat.length}\n * @function\n */\nexport const len = length;\n\n/**\n * Calculates the squared length of a quat\n *\n * @param {quat} a vector to calculate squared length of\n * @returns {Number} squared length of a\n * @function\n */\nexport const squaredLength = vec4.squaredLength;\n\n/**\n * Alias for {@link quat.squaredLength}\n * @function\n */\nexport const sqrLen = squaredLength;\n\n/**\n * Normalize a quat\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a quaternion to normalize\n * @returns {quat} out\n * @function\n */\nexport const normalize = vec4.normalize;\n\n/**\n * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)\n *\n * @param {quat} a The first quaternion.\n * @param {quat} b The second quaternion.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport const exactEquals = vec4.exactEquals;\n\n/**\n * Returns whether or not the quaternions have approximately the same elements in the same position.\n *\n * @param {quat} a The first vector.\n * @param {quat} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport const equals = vec4.equals;\n\n/**\n * Sets a quaternion to represent the shortest rotation from one\n * vector to another.\n *\n * Both vectors are assumed to be unit length.\n *\n * @param {quat} out the receiving quaternion.\n * @param {vec3} a the initial vector\n * @param {vec3} b the destination vector\n * @returns {quat} out\n */\nexport const rotationTo = (function() {\n let tmpvec3 = vec3.create();\n let xUnitVec3 = vec3.fromValues(1,0,0);\n let yUnitVec3 = vec3.fromValues(0,1,0);\n\n return function(out, a, b) {\n let dot = vec3.dot(a, b);\n if (dot < -0.999999) {\n vec3.cross(tmpvec3, xUnitVec3, a);\n if (vec3.len(tmpvec3) < 0.000001)\n vec3.cross(tmpvec3, yUnitVec3, a);\n vec3.normalize(tmpvec3, tmpvec3);\n setAxisAngle(out, tmpvec3, Math.PI);\n return out;\n } else if (dot > 0.999999) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n return out;\n } else {\n vec3.cross(tmpvec3, a, b);\n out[0] = tmpvec3[0];\n out[1] = tmpvec3[1];\n out[2] = tmpvec3[2];\n out[3] = 1 + dot;\n return normalize(out, out);\n }\n };\n})();\n\n/**\n * Performs a spherical linear interpolation with two control points\n *\n * @param {quat} out the receiving quaternion\n * @param {quat} a the first operand\n * @param {quat} b the second operand\n * @param {quat} c the third operand\n * @param {quat} d the fourth operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {quat} out\n */\nexport const sqlerp = (function () {\n let temp1 = create();\n let temp2 = create();\n\n return function (out, a, b, c, d, t) {\n slerp(temp1, a, d, t);\n slerp(temp2, b, c, t);\n slerp(out, temp1, temp2, 2 * t * (1 - t));\n\n return out;\n };\n}());\n\n/**\n * Sets the specified quaternion with values corresponding to the given\n * axes. Each axis is a vec3 and is expected to be unit length and\n * perpendicular to all other specified axes.\n *\n * @param {vec3} view the vector representing the viewing direction\n * @param {vec3} right the vector representing the local \"right\" direction\n * @param {vec3} up the vector representing the local \"up\" direction\n * @returns {quat} out\n */\nexport const setAxes = (function() {\n let matr = mat3.create();\n\n return function(out, view, right, up) {\n matr[0] = right[0];\n matr[3] = right[1];\n matr[6] = right[2];\n\n matr[1] = up[0];\n matr[4] = up[1];\n matr[7] = up[2];\n\n matr[2] = -view[0];\n matr[5] = -view[1];\n matr[8] = -view[2];\n\n return normalize(out, fromMat3(out, matr));\n };\n})();\n","import * as glMatrix from \"./common.js\";\nimport * as quat from \"./quat.js\";\nimport * as mat4 from \"./mat4.js\";\n\n/**\n * Dual Quaternion<br>\n * Format: [real, dual]<br>\n * Quaternion format: XYZW<br>\n * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br>\n * @module quat2\n */\n\n\n/**\n * Creates a new identity dual quat\n *\n * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation]\n */\nexport function create() {\n let dq = new glMatrix.ARRAY_TYPE(8);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n dq[0] = 0;\n dq[1] = 0;\n dq[2] = 0;\n dq[4] = 0;\n dq[5] = 0;\n dq[6] = 0;\n dq[7] = 0;\n }\n dq[3] = 1;\n return dq;\n}\n\n/**\n * Creates a new quat initialized with values from an existing quaternion\n *\n * @param {quat2} a dual quaternion to clone\n * @returns {quat2} new dual quaternion\n * @function\n */\nexport function clone(a) {\n let dq = new glMatrix.ARRAY_TYPE(8);\n dq[0] = a[0];\n dq[1] = a[1];\n dq[2] = a[2];\n dq[3] = a[3];\n dq[4] = a[4];\n dq[5] = a[5];\n dq[6] = a[6];\n dq[7] = a[7];\n return dq;\n}\n\n/**\n * Creates a new dual quat initialized with the given values\n *\n * @param {Number} x1 X component\n * @param {Number} y1 Y component\n * @param {Number} z1 Z component\n * @param {Number} w1 W component\n * @param {Number} x2 X component\n * @param {Number} y2 Y component\n * @param {Number} z2 Z component\n * @param {Number} w2 W component\n * @returns {quat2} new dual quaternion\n * @function\n */\nexport function fromValues(x1, y1, z1, w1, x2, y2, z2, w2) {\n let dq = new glMatrix.ARRAY_TYPE(8);\n dq[0] = x1;\n dq[1] = y1;\n dq[2] = z1;\n dq[3] = w1;\n dq[4] = x2;\n dq[5] = y2;\n dq[6] = z2;\n dq[7] = w2;\n return dq;\n}\n\n/**\n * Creates a new dual quat from the given values (quat and translation)\n *\n * @param {Number} x1 X component\n * @param {Number} y1 Y component\n * @param {Number} z1 Z component\n * @param {Number} w1 W component\n * @param {Number} x2 X component (translation)\n * @param {Number} y2 Y component (translation)\n * @param {Number} z2 Z component (translation)\n * @returns {quat2} new dual quaternion\n * @function\n */\nexport function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) {\n let dq = new glMatrix.ARRAY_TYPE(8);\n dq[0] = x1;\n dq[1] = y1;\n dq[2] = z1;\n dq[3] = w1;\n let ax = x2 * 0.5,\n ay = y2 * 0.5,\n az = z2 * 0.5;\n dq[4] = ax * w1 + ay * z1 - az * y1;\n dq[5] = ay * w1 + az * x1 - ax * z1;\n dq[6] = az * w1 + ax * y1 - ay * x1;\n dq[7] = -ax * x1 - ay * y1 - az * z1;\n return dq;\n}\n\n/**\n * Creates a dual quat from a quaternion and a translation\n *\n * @param {quat2} dual quaternion receiving operation result\n * @param {quat} q quaternion\n * @param {vec3} t tranlation vector\n * @returns {quat2} dual quaternion receiving operation result\n * @function\n */\nexport function fromRotationTranslation(out, q, t) {\n let ax = t[0] * 0.5,\n ay = t[1] * 0.5,\n az = t[2] * 0.5,\n bx = q[0],\n by = q[1],\n bz = q[2],\n bw = q[3];\n out[0] = bx;\n out[1] = by;\n out[2] = bz;\n out[3] = bw;\n out[4] = ax * bw + ay * bz - az * by;\n out[5] = ay * bw + az * bx - ax * bz;\n out[6] = az * bw + ax * by - ay * bx;\n out[7] = -ax * bx - ay * by - az * bz;\n return out;\n}\n\n/**\n * Creates a dual quat from a translation\n *\n * @param {quat2} dual quaternion receiving operation result\n * @param {vec3} t translation vector\n * @returns {quat2} dual quaternion receiving operation result\n * @function\n */\nexport function fromTranslation(out, t) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n out[4] = t[0] * 0.5;\n out[5] = t[1] * 0.5;\n out[6] = t[2] * 0.5;\n out[7] = 0;\n return out;\n}\n\n/**\n * Creates a dual quat from a quaternion\n *\n * @param {quat2} dual quaternion receiving operation result\n * @param {quat} q the quaternion\n * @returns {quat2} dual quaternion receiving operation result\n * @function\n */\nexport function fromRotation(out, q) {\n out[0] = q[0];\n out[1] = q[1];\n out[2] = q[2];\n out[3] = q[3];\n out[4] = 0;\n out[5] = 0;\n out[6] = 0;\n out[7] = 0;\n return out;\n}\n\n/**\n * Creates a new dual quat from a matrix (4x4)\n *\n * @param {quat2} out the dual quaternion\n * @param {mat4} a the matrix\n * @returns {quat2} dual quat receiving operation result\n * @function\n */\nexport function fromMat4(out, a) {\n //TODO Optimize this\n let outer = quat.create();\n mat4.getRotation(outer, a);\n let t = new glMatrix.ARRAY_TYPE(3);\n mat4.getTranslation(t, a);\n fromRotationTranslation(out, outer, t);\n return out;\n}\n\n/**\n * Copy the values from one dual quat to another\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the source dual quaternion\n * @returns {quat2} out\n * @function\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n return out;\n}\n\n/**\n * Set a dual quat to the identity dual quaternion\n *\n * @param {quat2} out the receiving quaternion\n * @returns {quat2} out\n */\nexport function identity(out) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n out[4] = 0;\n out[5] = 0;\n out[6] = 0;\n out[7] = 0;\n return out;\n}\n\n/**\n * Set the components of a dual quat to the given values\n *\n * @param {quat2} out the receiving quaternion\n * @param {Number} x1 X component\n * @param {Number} y1 Y component\n * @param {Number} z1 Z component\n * @param {Number} w1 W component\n * @param {Number} x2 X component\n * @param {Number} y2 Y component\n * @param {Number} z2 Z component\n * @param {Number} w2 W component\n * @returns {quat2} out\n * @function\n */\nexport function set(out, x1, y1, z1, w1, x2, y2, z2, w2) {\n out[0] = x1;\n out[1] = y1;\n out[2] = z1;\n out[3] = w1;\n\n out[4] = x2;\n out[5] = y2;\n out[6] = z2;\n out[7] = w2;\n return out;\n}\n\n/**\n * Gets the real part of a dual quat\n * @param {quat} out real part\n * @param {quat2} a Dual Quaternion\n * @return {quat} real part\n */\nexport const getReal = quat.copy;\n\n/**\n * Gets the dual part of a dual quat\n * @param {quat} out dual part\n * @param {quat2} a Dual Quaternion\n * @return {quat} dual part\n */\nexport function getDual(out, a) {\n out[0] = a[4];\n out[1] = a[5];\n out[2] = a[6];\n out[3] = a[7];\n return out;\n}\n\n/**\n * Set the real component of a dual quat to the given quaternion\n *\n * @param {quat2} out the receiving quaternion\n * @param {quat} q a quaternion representing the real part\n * @returns {quat2} out\n * @function\n */\nexport const setReal = quat.copy;\n\n/**\n * Set the dual component of a dual quat to the given quaternion\n *\n * @param {quat2} out the receiving quaternion\n * @param {quat} q a quaternion representing the dual part\n * @returns {quat2} out\n * @function\n */\nexport function setDual(out, q) {\n out[4] = q[0];\n out[5] = q[1];\n out[6] = q[2];\n out[7] = q[3];\n return out;\n}\n\n/**\n * Gets the translation of a normalized dual quat\n * @param {vec3} out translation\n * @param {quat2} a Dual Quaternion to be decomposed\n * @return {vec3} translation\n */\nexport function getTranslation(out, a) {\n let ax = a[4],\n ay = a[5],\n az = a[6],\n aw = a[7],\n bx = -a[0],\n by = -a[1],\n bz = -a[2],\n bw = a[3];\n out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;\n out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;\n out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;\n return out;\n}\n\n/**\n * Translates a dual quat by the given vector\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to translate\n * @param {vec3} v vector to translate by\n * @returns {quat2} out\n */\nexport function translate(out, a, v) {\n let ax1 = a[0],\n ay1 = a[1],\n az1 = a[2],\n aw1 = a[3],\n bx1 = v[0] * 0.5,\n by1 = v[1] * 0.5,\n bz1 = v[2] * 0.5,\n ax2 = a[4],\n ay2 = a[5],\n az2 = a[6],\n aw2 = a[7];\n out[0] = ax1;\n out[1] = ay1;\n out[2] = az1;\n out[3] = aw1;\n out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2;\n out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2;\n out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2;\n out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2;\n return out;\n}\n\n/**\n * Rotates a dual quat around the X axis\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to rotate\n * @param {number} rad how far should the rotation be\n * @returns {quat2} out\n */\nexport function rotateX(out, a, rad) {\n let bx = -a[0],\n by = -a[1],\n bz = -a[2],\n bw = a[3],\n ax = a[4],\n ay = a[5],\n az = a[6],\n aw = a[7],\n ax1 = ax * bw + aw * bx + ay * bz - az * by,\n ay1 = ay * bw + aw * by + az * bx - ax * bz,\n az1 = az * bw + aw * bz + ax * by - ay * bx,\n aw1 = aw * bw - ax * bx - ay * by - az * bz;\n quat.rotateX(out, a, rad);\n bx = out[0];\n by = out[1];\n bz = out[2];\n bw = out[3];\n out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\n out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\n out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\n out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\n return out;\n}\n\n/**\n * Rotates a dual quat around the Y axis\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to rotate\n * @param {number} rad how far should the rotation be\n * @returns {quat2} out\n */\nexport function rotateY(out, a, rad) {\n let bx = -a[0],\n by = -a[1],\n bz = -a[2],\n bw = a[3],\n ax = a[4],\n ay = a[5],\n az = a[6],\n aw = a[7],\n ax1 = ax * bw + aw * bx + ay * bz - az * by,\n ay1 = ay * bw + aw * by + az * bx - ax * bz,\n az1 = az * bw + aw * bz + ax * by - ay * bx,\n aw1 = aw * bw - ax * bx - ay * by - az * bz;\n quat.rotateY(out, a, rad);\n bx = out[0];\n by = out[1];\n bz = out[2];\n bw = out[3];\n out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\n out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\n out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\n out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\n return out;\n}\n\n/**\n * Rotates a dual quat around the Z axis\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to rotate\n * @param {number} rad how far should the rotation be\n * @returns {quat2} out\n */\nexport function rotateZ(out, a, rad) {\n let bx = -a[0],\n by = -a[1],\n bz = -a[2],\n bw = a[3],\n ax = a[4],\n ay = a[5],\n az = a[6],\n aw = a[7],\n ax1 = ax * bw + aw * bx + ay * bz - az * by,\n ay1 = ay * bw + aw * by + az * bx - ax * bz,\n az1 = az * bw + aw * bz + ax * by - ay * bx,\n aw1 = aw * bw - ax * bx - ay * by - az * bz;\n quat.rotateZ(out, a, rad);\n bx = out[0];\n by = out[1];\n bz = out[2];\n bw = out[3];\n out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\n out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\n out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\n out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\n return out;\n}\n\n/**\n * Rotates a dual quat by a given quaternion (a * q)\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to rotate\n * @param {quat} q quaternion to rotate by\n * @returns {quat2} out\n */\nexport function rotateByQuatAppend(out, a, q) {\n let qx = q[0],\n qy = q[1],\n qz = q[2],\n qw = q[3],\n ax = a[0],\n ay = a[1],\n az = a[2],\n aw = a[3];\n\n out[0] = ax * qw + aw * qx + ay * qz - az * qy;\n out[1] = ay * qw + aw * qy + az * qx - ax * qz;\n out[2] = az * qw + aw * qz + ax * qy - ay * qx;\n out[3] = aw * qw - ax * qx - ay * qy - az * qz;\n ax = a[4];\n ay = a[5];\n az = a[6];\n aw = a[7];\n out[4] = ax * qw + aw * qx + ay * qz - az * qy;\n out[5] = ay * qw + aw * qy + az * qx - ax * qz;\n out[6] = az * qw + aw * qz + ax * qy - ay * qx;\n out[7] = aw * qw - ax * qx - ay * qy - az * qz;\n return out;\n}\n\n/**\n * Rotates a dual quat by a given quaternion (q * a)\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat} q quaternion to rotate by\n * @param {quat2} a the dual quaternion to rotate\n * @returns {quat2} out\n */\nexport function rotateByQuatPrepend(out, q, a) {\n let qx = q[0],\n qy = q[1],\n qz = q[2],\n qw = q[3],\n bx = a[0],\n by = a[1],\n bz = a[2],\n bw = a[3];\n\n out[0] = qx * bw + qw * bx + qy * bz - qz * by;\n out[1] = qy * bw + qw * by + qz * bx - qx * bz;\n out[2] = qz * bw + qw * bz + qx * by - qy * bx;\n out[3] = qw * bw - qx * bx - qy * by - qz * bz;\n bx = a[4];\n by = a[5];\n bz = a[6];\n bw = a[7];\n out[4] = qx * bw + qw * bx + qy * bz - qz * by;\n out[5] = qy * bw + qw * by + qz * bx - qx * bz;\n out[6] = qz * bw + qw * bz + qx * by - qy * bx;\n out[7] = qw * bw - qx * bx - qy * by - qz * bz;\n return out;\n}\n\n/**\n * Rotates a dual quat around a given axis. Does the normalisation automatically\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the dual quaternion to rotate\n * @param {vec3} axis the axis to rotate around\n * @param {Number} rad how far the rotation should be\n * @returns {quat2} out\n */\nexport function rotateAroundAxis(out, a, axis, rad) {\n //Special case for rad = 0\n if (Math.abs(rad) < glMatrix.EPSILON) {\n return copy(out, a);\n }\n let axisLength = Math.sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);\n\n rad = rad * 0.5;\n let s = Math.sin(rad);\n let bx = s * axis[0] / axisLength;\n let by = s * axis[1] / axisLength;\n let bz = s * axis[2] / axisLength;\n let bw = Math.cos(rad);\n\n let ax1 = a[0],\n ay1 = a[1],\n az1 = a[2],\n aw1 = a[3];\n out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by;\n out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz;\n out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx;\n out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz;\n\n let ax = a[4],\n ay = a[5],\n az = a[6],\n aw = a[7];\n out[4] = ax * bw + aw * bx + ay * bz - az * by;\n out[5] = ay * bw + aw * by + az * bx - ax * bz;\n out[6] = az * bw + aw * bz + ax * by - ay * bx;\n out[7] = aw * bw - ax * bx - ay * by - az * bz;\n\n return out;\n}\n\n/**\n * Adds two dual quat's\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the first operand\n * @param {quat2} b the second operand\n * @returns {quat2} out\n * @function\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n out[4] = a[4] + b[4];\n out[5] = a[5] + b[5];\n out[6] = a[6] + b[6];\n out[7] = a[7] + b[7];\n return out;\n}\n\n/**\n * Multiplies two dual quat's\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a the first operand\n * @param {quat2} b the second operand\n * @returns {quat2} out\n */\nexport function multiply(out, a, b) {\n let ax0 = a[0],\n ay0 = a[1],\n az0 = a[2],\n aw0 = a[3],\n bx1 = b[4],\n by1 = b[5],\n bz1 = b[6],\n bw1 = b[7],\n ax1 = a[4],\n ay1 = a[5],\n az1 = a[6],\n aw1 = a[7],\n bx0 = b[0],\n by0 = b[1],\n bz0 = b[2],\n bw0 = b[3];\n out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0;\n out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0;\n out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0;\n out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0;\n out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0;\n out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0;\n out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0;\n out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0;\n return out;\n}\n\n/**\n * Alias for {@link quat2.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Scales a dual quat by a scalar number\n *\n * @param {quat2} out the receiving dual quat\n * @param {quat2} a the dual quat to scale\n * @param {Number} b amount to scale the dual quat by\n * @returns {quat2} out\n * @function\n */\nexport function scale(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n out[4] = a[4] * b;\n out[5] = a[5] * b;\n out[6] = a[6] * b;\n out[7] = a[7] * b;\n return out;\n}\n\n/**\n * Calculates the dot product of two dual quat's (The dot product of the real parts)\n *\n * @param {quat2} a the first operand\n * @param {quat2} b the second operand\n * @returns {Number} dot product of a and b\n * @function\n */\nexport const dot = quat.dot;\n\n/**\n * Performs a linear interpolation between two dual quats's\n * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5)\n *\n * @param {quat2} out the receiving dual quat\n * @param {quat2} a the first operand\n * @param {quat2} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {quat2} out\n */\nexport function lerp(out, a, b, t) {\n let mt = 1 - t;\n if (dot(a, b) < 0) t = -t;\n\n out[0] = a[0] * mt + b[0] * t;\n out[1] = a[1] * mt + b[1] * t;\n out[2] = a[2] * mt + b[2] * t;\n out[3] = a[3] * mt + b[3] * t;\n out[4] = a[4] * mt + b[4] * t;\n out[5] = a[5] * mt + b[5] * t;\n out[6] = a[6] * mt + b[6] * t;\n out[7] = a[7] * mt + b[7] * t;\n\n return out;\n}\n\n/**\n * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a dual quat to calculate inverse of\n * @returns {quat2} out\n */\nexport function invert(out, a) {\n let sqlen = squaredLength(a);\n out[0] = -a[0] / sqlen;\n out[1] = -a[1] / sqlen;\n out[2] = -a[2] / sqlen;\n out[3] = a[3] / sqlen;\n out[4] = -a[4] / sqlen;\n out[5] = -a[5] / sqlen;\n out[6] = -a[6] / sqlen;\n out[7] = a[7] / sqlen;\n return out;\n}\n\n/**\n * Calculates the conjugate of a dual quat\n * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result.\n *\n * @param {quat2} out the receiving quaternion\n * @param {quat2} a quat to calculate conjugate of\n * @returns {quat2} out\n */\nexport function conjugate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n out[2] = -a[2];\n out[3] = a[3];\n out[4] = -a[4];\n out[5] = -a[5];\n out[6] = -a[6];\n out[7] = a[7];\n return out;\n}\n\n/**\n * Calculates the length of a dual quat\n *\n * @param {quat2} a dual quat to calculate length of\n * @returns {Number} length of a\n * @function\n */\nexport const length = quat.length;\n\n/**\n * Alias for {@link quat2.length}\n * @function\n */\nexport const len = length;\n\n/**\n * Calculates the squared length of a dual quat\n *\n * @param {quat2} a dual quat to calculate squared length of\n * @returns {Number} squared length of a\n * @function\n */\nexport const squaredLength = quat.squaredLength;\n\n/**\n * Alias for {@link quat2.squaredLength}\n * @function\n */\nexport const sqrLen = squaredLength;\n\n/**\n * Normalize a dual quat\n *\n * @param {quat2} out the receiving dual quaternion\n * @param {quat2} a dual quaternion to normalize\n * @returns {quat2} out\n * @function\n */\nexport function normalize(out, a) {\n let magnitude = squaredLength(a);\n if (magnitude > 0) {\n magnitude = Math.sqrt(magnitude);\n\n let a0 = a[0] / magnitude;\n let a1 = a[1] / magnitude;\n let a2 = a[2] / magnitude;\n let a3 = a[3] / magnitude;\n\n let b0 = a[4];\n let b1 = a[5];\n let b2 = a[6];\n let b3 = a[7];\n\n let a_dot_b = (a0 * b0) + (a1 * b1) + (a2 * b2) + (a3 * b3);\n\n out[0] = a0;\n out[1] = a1;\n out[2] = a2;\n out[3] = a3;\n\n out[4] = (b0 - (a0 * a_dot_b)) / magnitude;\n out[5] = (b1 - (a1 * a_dot_b)) / magnitude;\n out[6] = (b2 - (a2 * a_dot_b)) / magnitude;\n out[7] = (b3 - (a3 * a_dot_b)) / magnitude;\n }\n return out;\n}\n\n/**\n * Returns a string representation of a dual quatenion\n *\n * @param {quat2} a dual quaternion to represent as a string\n * @returns {String} string representation of the dual quat\n */\nexport function str(a) {\n return 'quat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +\n a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ')';\n}\n\n/**\n * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===)\n *\n * @param {quat2} a the first dual quaternion.\n * @param {quat2} b the second dual quaternion.\n * @returns {Boolean} true if the dual quaternions are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] &&\n a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];\n}\n\n/**\n * Returns whether or not the dual quaternions have approximately the same elements in the same position.\n *\n * @param {quat2} a the first dual quat.\n * @param {quat2} b the second dual quat.\n * @returns {Boolean} true if the dual quats are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0],\n a1 = a[1],\n a2 = a[2],\n a3 = a[3],\n a4 = a[4],\n a5 = a[5],\n a6 = a[6],\n a7 = a[7];\n let b0 = b[0],\n b1 = b[1],\n b2 = b[2],\n b3 = b[3],\n b4 = b[4],\n b5 = b[5],\n b6 = b[6],\n b7 = b[7];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\n Math.abs(a4 - b4) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\n Math.abs(a5 - b5) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&\n Math.abs(a6 - b6) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&\n Math.abs(a7 - b7) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)));\n}\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 2 Dimensional Vector\n * @module vec2\n */\n\n/**\n * Creates a new, empty vec2\n *\n * @returns {vec2} a new 2D vector\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(2);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[0] = 0;\n out[1] = 0;\n }\n return out;\n}\n\n/**\n * Creates a new vec2 initialized with values from an existing vector\n *\n * @param {vec2} a vector to clone\n * @returns {vec2} a new 2D vector\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(2);\n out[0] = a[0];\n out[1] = a[1];\n return out;\n}\n\n/**\n * Creates a new vec2 initialized with the given values\n *\n * @param {Number} x X component\n * @param {Number} y Y component\n * @returns {vec2} a new 2D vector\n */\nexport function fromValues(x, y) {\n let out = new glMatrix.ARRAY_TYPE(2);\n out[0] = x;\n out[1] = y;\n return out;\n}\n\n/**\n * Copy the values from one vec2 to another\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the source vector\n * @returns {vec2} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n return out;\n}\n\n/**\n * Set the components of a vec2 to the given values\n *\n * @param {vec2} out the receiving vector\n * @param {Number} x X component\n * @param {Number} y Y component\n * @returns {vec2} out\n */\nexport function set(out, x, y) {\n out[0] = x;\n out[1] = y;\n return out;\n}\n\n/**\n * Adds two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n return out;\n}\n\n/**\n * Subtracts vector b from vector a\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n return out;\n}\n\n/**\n * Multiplies two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function multiply(out, a, b) {\n out[0] = a[0] * b[0];\n out[1] = a[1] * b[1];\n return out;\n}\n\n/**\n * Divides two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function divide(out, a, b) {\n out[0] = a[0] / b[0];\n out[1] = a[1] / b[1];\n return out;\n}\n\n/**\n * Math.ceil the components of a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to ceil\n * @returns {vec2} out\n */\nexport function ceil(out, a) {\n out[0] = Math.ceil(a[0]);\n out[1] = Math.ceil(a[1]);\n return out;\n}\n\n/**\n * Math.floor the components of a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to floor\n * @returns {vec2} out\n */\nexport function floor(out, a) {\n out[0] = Math.floor(a[0]);\n out[1] = Math.floor(a[1]);\n return out;\n}\n\n/**\n * Returns the minimum of two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function min(out, a, b) {\n out[0] = Math.min(a[0], b[0]);\n out[1] = Math.min(a[1], b[1]);\n return out;\n}\n\n/**\n * Returns the maximum of two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec2} out\n */\nexport function max(out, a, b) {\n out[0] = Math.max(a[0], b[0]);\n out[1] = Math.max(a[1], b[1]);\n return out;\n}\n\n/**\n * Math.round the components of a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to round\n * @returns {vec2} out\n */\nexport function round (out, a) {\n out[0] = Math.round(a[0]);\n out[1] = Math.round(a[1]);\n return out;\n}\n\n/**\n * Scales a vec2 by a scalar number\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the vector to scale\n * @param {Number} b amount to scale the vector by\n * @returns {vec2} out\n */\nexport function scale(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n return out;\n}\n\n/**\n * Adds two vec2's after scaling the second operand by a scalar value\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @param {Number} scale the amount to scale b by before adding\n * @returns {vec2} out\n */\nexport function scaleAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n return out;\n}\n\n/**\n * Calculates the euclidian distance between two vec2's\n *\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {Number} distance between a and b\n */\nexport function distance(a, b) {\n var x = b[0] - a[0],\n y = b[1] - a[1];\n return Math.sqrt(x*x + y*y);\n}\n\n/**\n * Calculates the squared euclidian distance between two vec2's\n *\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {Number} squared distance between a and b\n */\nexport function squaredDistance(a, b) {\n var x = b[0] - a[0],\n y = b[1] - a[1];\n return x*x + y*y;\n}\n\n/**\n * Calculates the length of a vec2\n *\n * @param {vec2} a vector to calculate length of\n * @returns {Number} length of a\n */\nexport function length(a) {\n var x = a[0],\n y = a[1];\n return Math.sqrt(x*x + y*y);\n}\n\n/**\n * Calculates the squared length of a vec2\n *\n * @param {vec2} a vector to calculate squared length of\n * @returns {Number} squared length of a\n */\nexport function squaredLength (a) {\n var x = a[0],\n y = a[1];\n return x*x + y*y;\n}\n\n/**\n * Negates the components of a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to negate\n * @returns {vec2} out\n */\nexport function negate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n return out;\n}\n\n/**\n * Returns the inverse of the components of a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to invert\n * @returns {vec2} out\n */\nexport function inverse(out, a) {\n out[0] = 1.0 / a[0];\n out[1] = 1.0 / a[1];\n return out;\n}\n\n/**\n * Normalize a vec2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a vector to normalize\n * @returns {vec2} out\n */\nexport function normalize(out, a) {\n var x = a[0],\n y = a[1];\n var len = x*x + y*y;\n if (len > 0) {\n //TODO: evaluate use of glm_invsqrt here?\n len = 1 / Math.sqrt(len);\n out[0] = a[0] * len;\n out[1] = a[1] * len;\n }\n return out;\n}\n\n/**\n * Calculates the dot product of two vec2's\n *\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {Number} dot product of a and b\n */\nexport function dot(a, b) {\n return a[0] * b[0] + a[1] * b[1];\n}\n\n/**\n * Computes the cross product of two vec2's\n * Note that the cross product must by definition produce a 3D vector\n *\n * @param {vec3} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @returns {vec3} out\n */\nexport function cross(out, a, b) {\n var z = a[0] * b[1] - a[1] * b[0];\n out[0] = out[1] = 0;\n out[2] = z;\n return out;\n}\n\n/**\n * Performs a linear interpolation between two vec2's\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the first operand\n * @param {vec2} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {vec2} out\n */\nexport function lerp(out, a, b, t) {\n var ax = a[0],\n ay = a[1];\n out[0] = ax + t * (b[0] - ax);\n out[1] = ay + t * (b[1] - ay);\n return out;\n}\n\n/**\n * Generates a random vector with the given scale\n *\n * @param {vec2} out the receiving vector\n * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\n * @returns {vec2} out\n */\nexport function random(out, scale) {\n scale = scale || 1.0;\n var r = glMatrix.RANDOM() * 2.0 * Math.PI;\n out[0] = Math.cos(r) * scale;\n out[1] = Math.sin(r) * scale;\n return out;\n}\n\n/**\n * Transforms the vec2 with a mat2\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the vector to transform\n * @param {mat2} m matrix to transform with\n * @returns {vec2} out\n */\nexport function transformMat2(out, a, m) {\n var x = a[0],\n y = a[1];\n out[0] = m[0] * x + m[2] * y;\n out[1] = m[1] * x + m[3] * y;\n return out;\n}\n\n/**\n * Transforms the vec2 with a mat2d\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the vector to transform\n * @param {mat2d} m matrix to transform with\n * @returns {vec2} out\n */\nexport function transformMat2d(out, a, m) {\n var x = a[0],\n y = a[1];\n out[0] = m[0] * x + m[2] * y + m[4];\n out[1] = m[1] * x + m[3] * y + m[5];\n return out;\n}\n\n/**\n * Transforms the vec2 with a mat3\n * 3rd vector component is implicitly '1'\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the vector to transform\n * @param {mat3} m matrix to transform with\n * @returns {vec2} out\n */\nexport function transformMat3(out, a, m) {\n var x = a[0],\n y = a[1];\n out[0] = m[0] * x + m[3] * y + m[6];\n out[1] = m[1] * x + m[4] * y + m[7];\n return out;\n}\n\n/**\n * Transforms the vec2 with a mat4\n * 3rd vector component is implicitly '0'\n * 4th vector component is implicitly '1'\n *\n * @param {vec2} out the receiving vector\n * @param {vec2} a the vector to transform\n * @param {mat4} m matrix to transform with\n * @returns {vec2} out\n */\nexport function transformMat4(out, a, m) {\n let x = a[0];\n let y = a[1];\n out[0] = m[0] * x + m[4] * y + m[12];\n out[1] = m[1] * x + m[5] * y + m[13];\n return out;\n}\n\n/**\n * Rotate a 2D vector\n * @param {vec2} out The receiving vec2\n * @param {vec2} a The vec2 point to rotate\n * @param {vec2} b The origin of the rotation\n * @param {Number} c The angle of rotation\n * @returns {vec2} out\n */\nexport function rotate(out, a, b, c) {\n //Translate point to the origin\n let p0 = a[0] - b[0],\n p1 = a[1] - b[1],\n sinC = Math.sin(c),\n cosC = Math.cos(c);\n \n //perform rotation and translate to correct position\n out[0] = p0*cosC - p1*sinC + b[0];\n out[1] = p0*sinC + p1*cosC + b[1];\n\n return out;\n}\n\n/**\n * Get the angle between two 2D vectors\n * @param {vec2} a The first operand\n * @param {vec2} b The second operand\n * @returns {Number} The angle in radians\n */\nexport function angle(a, b) {\n let x1 = a[0],\n y1 = a[1],\n x2 = b[0],\n y2 = b[1];\n \n let len1 = x1*x1 + y1*y1;\n if (len1 > 0) {\n //TODO: evaluate use of glm_invsqrt here?\n len1 = 1 / Math.sqrt(len1);\n }\n \n let len2 = x2*x2 + y2*y2;\n if (len2 > 0) {\n //TODO: evaluate use of glm_invsqrt here?\n len2 = 1 / Math.sqrt(len2);\n }\n \n let cosine = (x1 * x2 + y1 * y2) * len1 * len2;\n \n \n if(cosine > 1.0) {\n return 0;\n }\n else if(cosine < -1.0) {\n return Math.PI;\n } else {\n return Math.acos(cosine);\n }\n}\n\n/**\n * Returns a string representation of a vector\n *\n * @param {vec2} a vector to represent as a string\n * @returns {String} string representation of the vector\n */\nexport function str(a) {\n return 'vec2(' + a[0] + ', ' + a[1] + ')';\n}\n\n/**\n * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)\n *\n * @param {vec2} a The first vector.\n * @param {vec2} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1];\n}\n\n/**\n * Returns whether or not the vectors have approximately the same elements in the same position.\n *\n * @param {vec2} a The first vector.\n * @param {vec2} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1];\n let b0 = b[0], b1 = b[1];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)));\n}\n\n/**\n * Alias for {@link vec2.length}\n * @function\n */\nexport const len = length;\n\n/**\n * Alias for {@link vec2.subtract}\n * @function\n */\nexport const sub = subtract;\n\n/**\n * Alias for {@link vec2.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link vec2.divide}\n * @function\n */\nexport const div = divide;\n\n/**\n * Alias for {@link vec2.distance}\n * @function\n */\nexport const dist = distance;\n\n/**\n * Alias for {@link vec2.squaredDistance}\n * @function\n */\nexport const sqrDist = squaredDistance;\n\n/**\n * Alias for {@link vec2.squaredLength}\n * @function\n */\nexport const sqrLen = squaredLength;\n\n/**\n * Perform some operation over an array of vec2s.\n *\n * @param {Array} a the array of vectors to iterate over\n * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed\n * @param {Number} offset Number of elements to skip at the beginning of the array\n * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array\n * @param {Function} fn Function to call for each vector in the array\n * @param {Object} [arg] additional argument to pass to fn\n * @returns {Array} a\n * @function\n */\nexport const forEach = (function() {\n let vec = create();\n\n return function(a, stride, offset, count, fn, arg) {\n let i, l;\n if(!stride) {\n stride = 2;\n }\n\n if(!offset) {\n offset = 0;\n }\n\n if(count) {\n l = Math.min((count * stride) + offset, a.length);\n } else {\n l = a.length;\n }\n\n for(i = offset; i < l; i += stride) {\n vec[0] = a[i]; vec[1] = a[i+1];\n fn(vec, vec, arg);\n a[i] = vec[0]; a[i+1] = vec[1];\n }\n\n return a;\n };\n})();\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 3 Dimensional Vector\n * @module vec3\n */\n\n/**\n * Creates a new, empty vec3\n *\n * @returns {vec3} a new 3D vector\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(3);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n }\n return out;\n}\n\n/**\n * Creates a new vec3 initialized with values from an existing vector\n *\n * @param {vec3} a vector to clone\n * @returns {vec3} a new 3D vector\n */\nexport function clone(a) {\n var out = new glMatrix.ARRAY_TYPE(3);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n return out;\n}\n\n/**\n * Calculates the length of a vec3\n *\n * @param {vec3} a vector to calculate length of\n * @returns {Number} length of a\n */\nexport function length(a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n return Math.sqrt(x*x + y*y + z*z);\n}\n\n/**\n * Creates a new vec3 initialized with the given values\n *\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @returns {vec3} a new 3D vector\n */\nexport function fromValues(x, y, z) {\n let out = new glMatrix.ARRAY_TYPE(3);\n out[0] = x;\n out[1] = y;\n out[2] = z;\n return out;\n}\n\n/**\n * Copy the values from one vec3 to another\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the source vector\n * @returns {vec3} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n return out;\n}\n\n/**\n * Set the components of a vec3 to the given values\n *\n * @param {vec3} out the receiving vector\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @returns {vec3} out\n */\nexport function set(out, x, y, z) {\n out[0] = x;\n out[1] = y;\n out[2] = z;\n return out;\n}\n\n/**\n * Adds two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n return out;\n}\n\n/**\n * Subtracts vector b from vector a\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n return out;\n}\n\n/**\n * Multiplies two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function multiply(out, a, b) {\n out[0] = a[0] * b[0];\n out[1] = a[1] * b[1];\n out[2] = a[2] * b[2];\n return out;\n}\n\n/**\n * Divides two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function divide(out, a, b) {\n out[0] = a[0] / b[0];\n out[1] = a[1] / b[1];\n out[2] = a[2] / b[2];\n return out;\n}\n\n/**\n * Math.ceil the components of a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to ceil\n * @returns {vec3} out\n */\nexport function ceil(out, a) {\n out[0] = Math.ceil(a[0]);\n out[1] = Math.ceil(a[1]);\n out[2] = Math.ceil(a[2]);\n return out;\n}\n\n/**\n * Math.floor the components of a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to floor\n * @returns {vec3} out\n */\nexport function floor(out, a) {\n out[0] = Math.floor(a[0]);\n out[1] = Math.floor(a[1]);\n out[2] = Math.floor(a[2]);\n return out;\n}\n\n/**\n * Returns the minimum of two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function min(out, a, b) {\n out[0] = Math.min(a[0], b[0]);\n out[1] = Math.min(a[1], b[1]);\n out[2] = Math.min(a[2], b[2]);\n return out;\n}\n\n/**\n * Returns the maximum of two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function max(out, a, b) {\n out[0] = Math.max(a[0], b[0]);\n out[1] = Math.max(a[1], b[1]);\n out[2] = Math.max(a[2], b[2]);\n return out;\n}\n\n/**\n * Math.round the components of a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to round\n * @returns {vec3} out\n */\nexport function round(out, a) {\n out[0] = Math.round(a[0]);\n out[1] = Math.round(a[1]);\n out[2] = Math.round(a[2]);\n return out;\n}\n\n/**\n * Scales a vec3 by a scalar number\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the vector to scale\n * @param {Number} b amount to scale the vector by\n * @returns {vec3} out\n */\nexport function scale(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n return out;\n}\n\n/**\n * Adds two vec3's after scaling the second operand by a scalar value\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @param {Number} scale the amount to scale b by before adding\n * @returns {vec3} out\n */\nexport function scaleAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n return out;\n}\n\n/**\n * Calculates the euclidian distance between two vec3's\n *\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {Number} distance between a and b\n */\nexport function distance(a, b) {\n let x = b[0] - a[0];\n let y = b[1] - a[1];\n let z = b[2] - a[2];\n return Math.sqrt(x*x + y*y + z*z);\n}\n\n/**\n * Calculates the squared euclidian distance between two vec3's\n *\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {Number} squared distance between a and b\n */\nexport function squaredDistance(a, b) {\n let x = b[0] - a[0];\n let y = b[1] - a[1];\n let z = b[2] - a[2];\n return x*x + y*y + z*z;\n}\n\n/**\n * Calculates the squared length of a vec3\n *\n * @param {vec3} a vector to calculate squared length of\n * @returns {Number} squared length of a\n */\nexport function squaredLength(a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n return x*x + y*y + z*z;\n}\n\n/**\n * Negates the components of a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to negate\n * @returns {vec3} out\n */\nexport function negate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n out[2] = -a[2];\n return out;\n}\n\n/**\n * Returns the inverse of the components of a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to invert\n * @returns {vec3} out\n */\nexport function inverse(out, a) {\n out[0] = 1.0 / a[0];\n out[1] = 1.0 / a[1];\n out[2] = 1.0 / a[2];\n return out;\n}\n\n/**\n * Normalize a vec3\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a vector to normalize\n * @returns {vec3} out\n */\nexport function normalize(out, a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n let len = x*x + y*y + z*z;\n if (len > 0) {\n //TODO: evaluate use of glm_invsqrt here?\n len = 1 / Math.sqrt(len);\n out[0] = a[0] * len;\n out[1] = a[1] * len;\n out[2] = a[2] * len;\n }\n return out;\n}\n\n/**\n * Calculates the dot product of two vec3's\n *\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {Number} dot product of a and b\n */\nexport function dot(a, b) {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n}\n\n/**\n * Computes the cross product of two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @returns {vec3} out\n */\nexport function cross(out, a, b) {\n let ax = a[0], ay = a[1], az = a[2];\n let bx = b[0], by = b[1], bz = b[2];\n\n out[0] = ay * bz - az * by;\n out[1] = az * bx - ax * bz;\n out[2] = ax * by - ay * bx;\n return out;\n}\n\n/**\n * Performs a linear interpolation between two vec3's\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {vec3} out\n */\nexport function lerp(out, a, b, t) {\n let ax = a[0];\n let ay = a[1];\n let az = a[2];\n out[0] = ax + t * (b[0] - ax);\n out[1] = ay + t * (b[1] - ay);\n out[2] = az + t * (b[2] - az);\n return out;\n}\n\n/**\n * Performs a hermite interpolation with two control points\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @param {vec3} c the third operand\n * @param {vec3} d the fourth operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {vec3} out\n */\nexport function hermite(out, a, b, c, d, t) {\n let factorTimes2 = t * t;\n let factor1 = factorTimes2 * (2 * t - 3) + 1;\n let factor2 = factorTimes2 * (t - 2) + t;\n let factor3 = factorTimes2 * (t - 1);\n let factor4 = factorTimes2 * (3 - 2 * t);\n\n out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;\n out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;\n out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;\n\n return out;\n}\n\n/**\n * Performs a bezier interpolation with two control points\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the first operand\n * @param {vec3} b the second operand\n * @param {vec3} c the third operand\n * @param {vec3} d the fourth operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {vec3} out\n */\nexport function bezier(out, a, b, c, d, t) {\n let inverseFactor = 1 - t;\n let inverseFactorTimesTwo = inverseFactor * inverseFactor;\n let factorTimes2 = t * t;\n let factor1 = inverseFactorTimesTwo * inverseFactor;\n let factor2 = 3 * t * inverseFactorTimesTwo;\n let factor3 = 3 * factorTimes2 * inverseFactor;\n let factor4 = factorTimes2 * t;\n\n out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;\n out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;\n out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;\n\n return out;\n}\n\n/**\n * Generates a random vector with the given scale\n *\n * @param {vec3} out the receiving vector\n * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\n * @returns {vec3} out\n */\nexport function random(out, scale) {\n scale = scale || 1.0;\n\n let r = glMatrix.RANDOM() * 2.0 * Math.PI;\n let z = (glMatrix.RANDOM() * 2.0) - 1.0;\n let zScale = Math.sqrt(1.0-z*z) * scale;\n\n out[0] = Math.cos(r) * zScale;\n out[1] = Math.sin(r) * zScale;\n out[2] = z * scale;\n return out;\n}\n\n/**\n * Transforms the vec3 with a mat4.\n * 4th vector component is implicitly '1'\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the vector to transform\n * @param {mat4} m matrix to transform with\n * @returns {vec3} out\n */\nexport function transformMat4(out, a, m) {\n let x = a[0], y = a[1], z = a[2];\n let w = m[3] * x + m[7] * y + m[11] * z + m[15];\n w = w || 1.0;\n out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;\n out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;\n out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;\n return out;\n}\n\n/**\n * Transforms the vec3 with a mat3.\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the vector to transform\n * @param {mat3} m the 3x3 matrix to transform with\n * @returns {vec3} out\n */\nexport function transformMat3(out, a, m) {\n let x = a[0], y = a[1], z = a[2];\n out[0] = x * m[0] + y * m[3] + z * m[6];\n out[1] = x * m[1] + y * m[4] + z * m[7];\n out[2] = x * m[2] + y * m[5] + z * m[8];\n return out;\n}\n\n/**\n * Transforms the vec3 with a quat\n * Can also be used for dual quaternions. (Multiply it with the real part)\n *\n * @param {vec3} out the receiving vector\n * @param {vec3} a the vector to transform\n * @param {quat} q quaternion to transform with\n * @returns {vec3} out\n */\nexport function transformQuat(out, a, q) {\n // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed\n let qx = q[0], qy = q[1], qz = q[2], qw = q[3];\n let x = a[0], y = a[1], z = a[2];\n // var qvec = [qx, qy, qz];\n // var uv = vec3.cross([], qvec, a);\n let uvx = qy * z - qz * y,\n uvy = qz * x - qx * z,\n uvz = qx * y - qy * x;\n // var uuv = vec3.cross([], qvec, uv);\n let uuvx = qy * uvz - qz * uvy,\n uuvy = qz * uvx - qx * uvz,\n uuvz = qx * uvy - qy * uvx;\n // vec3.scale(uv, uv, 2 * w);\n let w2 = qw * 2;\n uvx *= w2;\n uvy *= w2;\n uvz *= w2;\n // vec3.scale(uuv, uuv, 2);\n uuvx *= 2;\n uuvy *= 2;\n uuvz *= 2;\n // return vec3.add(out, a, vec3.add(out, uv, uuv));\n out[0] = x + uvx + uuvx;\n out[1] = y + uvy + uuvy;\n out[2] = z + uvz + uuvz;\n return out;\n}\n\n/**\n * Rotate a 3D vector around the x-axis\n * @param {vec3} out The receiving vec3\n * @param {vec3} a The vec3 point to rotate\n * @param {vec3} b The origin of the rotation\n * @param {Number} c The angle of rotation\n * @returns {vec3} out\n */\nexport function rotateX(out, a, b, c){\n let p = [], r=[];\n //Translate point to the origin\n p[0] = a[0] - b[0];\n p[1] = a[1] - b[1];\n p[2] = a[2] - b[2];\n\n //perform rotation\n r[0] = p[0];\n r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c);\n r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c);\n\n //translate to correct position\n out[0] = r[0] + b[0];\n out[1] = r[1] + b[1];\n out[2] = r[2] + b[2];\n\n return out;\n}\n\n/**\n * Rotate a 3D vector around the y-axis\n * @param {vec3} out The receiving vec3\n * @param {vec3} a The vec3 point to rotate\n * @param {vec3} b The origin of the rotation\n * @param {Number} c The angle of rotation\n * @returns {vec3} out\n */\nexport function rotateY(out, a, b, c){\n let p = [], r=[];\n //Translate point to the origin\n p[0] = a[0] - b[0];\n p[1] = a[1] - b[1];\n p[2] = a[2] - b[2];\n\n //perform rotation\n r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c);\n r[1] = p[1];\n r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c);\n\n //translate to correct position\n out[0] = r[0] + b[0];\n out[1] = r[1] + b[1];\n out[2] = r[2] + b[2];\n\n return out;\n}\n\n/**\n * Rotate a 3D vector around the z-axis\n * @param {vec3} out The receiving vec3\n * @param {vec3} a The vec3 point to rotate\n * @param {vec3} b The origin of the rotation\n * @param {Number} c The angle of rotation\n * @returns {vec3} out\n */\nexport function rotateZ(out, a, b, c){\n let p = [], r=[];\n //Translate point to the origin\n p[0] = a[0] - b[0];\n p[1] = a[1] - b[1];\n p[2] = a[2] - b[2];\n\n //perform rotation\n r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c);\n r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c);\n r[2] = p[2];\n\n //translate to correct position\n out[0] = r[0] + b[0];\n out[1] = r[1] + b[1];\n out[2] = r[2] + b[2];\n\n return out;\n}\n\n/**\n * Get the angle between two 3D vectors\n * @param {vec3} a The first operand\n * @param {vec3} b The second operand\n * @returns {Number} The angle in radians\n */\nexport function angle(a, b) {\n let tempA = fromValues(a[0], a[1], a[2]);\n let tempB = fromValues(b[0], b[1], b[2]);\n\n normalize(tempA, tempA);\n normalize(tempB, tempB);\n\n let cosine = dot(tempA, tempB);\n\n if(cosine > 1.0) {\n return 0;\n }\n else if(cosine < -1.0) {\n return Math.PI;\n } else {\n return Math.acos(cosine);\n }\n}\n\n/**\n * Returns a string representation of a vector\n *\n * @param {vec3} a vector to represent as a string\n * @returns {String} string representation of the vector\n */\nexport function str(a) {\n return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';\n}\n\n/**\n * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)\n *\n * @param {vec3} a The first vector.\n * @param {vec3} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];\n}\n\n/**\n * Returns whether or not the vectors have approximately the same elements in the same position.\n *\n * @param {vec3} a The first vector.\n * @param {vec3} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2];\n let b0 = b[0], b1 = b[1], b2 = b[2];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)));\n}\n\n/**\n * Alias for {@link vec3.subtract}\n * @function\n */\nexport const sub = subtract;\n\n/**\n * Alias for {@link vec3.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link vec3.divide}\n * @function\n */\nexport const div = divide;\n\n/**\n * Alias for {@link vec3.distance}\n * @function\n */\nexport const dist = distance;\n\n/**\n * Alias for {@link vec3.squaredDistance}\n * @function\n */\nexport const sqrDist = squaredDistance;\n\n/**\n * Alias for {@link vec3.length}\n * @function\n */\nexport const len = length;\n\n/**\n * Alias for {@link vec3.squaredLength}\n * @function\n */\nexport const sqrLen = squaredLength;\n\n/**\n * Perform some operation over an array of vec3s.\n *\n * @param {Array} a the array of vectors to iterate over\n * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed\n * @param {Number} offset Number of elements to skip at the beginning of the array\n * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array\n * @param {Function} fn Function to call for each vector in the array\n * @param {Object} [arg] additional argument to pass to fn\n * @returns {Array} a\n * @function\n */\nexport const forEach = (function() {\n let vec = create();\n\n return function(a, stride, offset, count, fn, arg) {\n let i, l;\n if(!stride) {\n stride = 3;\n }\n\n if(!offset) {\n offset = 0;\n }\n\n if(count) {\n l = Math.min((count * stride) + offset, a.length);\n } else {\n l = a.length;\n }\n\n for(i = offset; i < l; i += stride) {\n vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];\n fn(vec, vec, arg);\n a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];\n }\n\n return a;\n };\n})();\n","import * as glMatrix from \"./common.js\";\n\n/**\n * 4 Dimensional Vector\n * @module vec4\n */\n\n/**\n * Creates a new, empty vec4\n *\n * @returns {vec4} a new 4D vector\n */\nexport function create() {\n let out = new glMatrix.ARRAY_TYPE(4);\n if(glMatrix.ARRAY_TYPE != Float32Array) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n }\n return out;\n}\n\n/**\n * Creates a new vec4 initialized with values from an existing vector\n *\n * @param {vec4} a vector to clone\n * @returns {vec4} a new 4D vector\n */\nexport function clone(a) {\n let out = new glMatrix.ARRAY_TYPE(4);\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n}\n\n/**\n * Creates a new vec4 initialized with the given values\n *\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @param {Number} w W component\n * @returns {vec4} a new 4D vector\n */\nexport function fromValues(x, y, z, w) {\n let out = new glMatrix.ARRAY_TYPE(4);\n out[0] = x;\n out[1] = y;\n out[2] = z;\n out[3] = w;\n return out;\n}\n\n/**\n * Copy the values from one vec4 to another\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the source vector\n * @returns {vec4} out\n */\nexport function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n}\n\n/**\n * Set the components of a vec4 to the given values\n *\n * @param {vec4} out the receiving vector\n * @param {Number} x X component\n * @param {Number} y Y component\n * @param {Number} z Z component\n * @param {Number} w W component\n * @returns {vec4} out\n */\nexport function set(out, x, y, z, w) {\n out[0] = x;\n out[1] = y;\n out[2] = z;\n out[3] = w;\n return out;\n}\n\n/**\n * Adds two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n return out;\n}\n\n/**\n * Subtracts vector b from vector a\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function subtract(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n out[3] = a[3] - b[3];\n return out;\n}\n\n/**\n * Multiplies two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function multiply(out, a, b) {\n out[0] = a[0] * b[0];\n out[1] = a[1] * b[1];\n out[2] = a[2] * b[2];\n out[3] = a[3] * b[3];\n return out;\n}\n\n/**\n * Divides two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function divide(out, a, b) {\n out[0] = a[0] / b[0];\n out[1] = a[1] / b[1];\n out[2] = a[2] / b[2];\n out[3] = a[3] / b[3];\n return out;\n}\n\n/**\n * Math.ceil the components of a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to ceil\n * @returns {vec4} out\n */\nexport function ceil(out, a) {\n out[0] = Math.ceil(a[0]);\n out[1] = Math.ceil(a[1]);\n out[2] = Math.ceil(a[2]);\n out[3] = Math.ceil(a[3]);\n return out;\n}\n\n/**\n * Math.floor the components of a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to floor\n * @returns {vec4} out\n */\nexport function floor(out, a) {\n out[0] = Math.floor(a[0]);\n out[1] = Math.floor(a[1]);\n out[2] = Math.floor(a[2]);\n out[3] = Math.floor(a[3]);\n return out;\n}\n\n/**\n * Returns the minimum of two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function min(out, a, b) {\n out[0] = Math.min(a[0], b[0]);\n out[1] = Math.min(a[1], b[1]);\n out[2] = Math.min(a[2], b[2]);\n out[3] = Math.min(a[3], b[3]);\n return out;\n}\n\n/**\n * Returns the maximum of two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {vec4} out\n */\nexport function max(out, a, b) {\n out[0] = Math.max(a[0], b[0]);\n out[1] = Math.max(a[1], b[1]);\n out[2] = Math.max(a[2], b[2]);\n out[3] = Math.max(a[3], b[3]);\n return out;\n}\n\n/**\n * Math.round the components of a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to round\n * @returns {vec4} out\n */\nexport function round(out, a) {\n out[0] = Math.round(a[0]);\n out[1] = Math.round(a[1]);\n out[2] = Math.round(a[2]);\n out[3] = Math.round(a[3]);\n return out;\n}\n\n/**\n * Scales a vec4 by a scalar number\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the vector to scale\n * @param {Number} b amount to scale the vector by\n * @returns {vec4} out\n */\nexport function scale(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[3] = a[3] * b;\n return out;\n}\n\n/**\n * Adds two vec4's after scaling the second operand by a scalar value\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @param {Number} scale the amount to scale b by before adding\n * @returns {vec4} out\n */\nexport function scaleAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n out[3] = a[3] + (b[3] * scale);\n return out;\n}\n\n/**\n * Calculates the euclidian distance between two vec4's\n *\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {Number} distance between a and b\n */\nexport function distance(a, b) {\n let x = b[0] - a[0];\n let y = b[1] - a[1];\n let z = b[2] - a[2];\n let w = b[3] - a[3];\n return Math.sqrt(x*x + y*y + z*z + w*w);\n}\n\n/**\n * Calculates the squared euclidian distance between two vec4's\n *\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {Number} squared distance between a and b\n */\nexport function squaredDistance(a, b) {\n let x = b[0] - a[0];\n let y = b[1] - a[1];\n let z = b[2] - a[2];\n let w = b[3] - a[3];\n return x*x + y*y + z*z + w*w;\n}\n\n/**\n * Calculates the length of a vec4\n *\n * @param {vec4} a vector to calculate length of\n * @returns {Number} length of a\n */\nexport function length(a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n let w = a[3];\n return Math.sqrt(x*x + y*y + z*z + w*w);\n}\n\n/**\n * Calculates the squared length of a vec4\n *\n * @param {vec4} a vector to calculate squared length of\n * @returns {Number} squared length of a\n */\nexport function squaredLength(a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n let w = a[3];\n return x*x + y*y + z*z + w*w;\n}\n\n/**\n * Negates the components of a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to negate\n * @returns {vec4} out\n */\nexport function negate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n out[2] = -a[2];\n out[3] = -a[3];\n return out;\n}\n\n/**\n * Returns the inverse of the components of a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to invert\n * @returns {vec4} out\n */\nexport function inverse(out, a) {\n out[0] = 1.0 / a[0];\n out[1] = 1.0 / a[1];\n out[2] = 1.0 / a[2];\n out[3] = 1.0 / a[3];\n return out;\n}\n\n/**\n * Normalize a vec4\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a vector to normalize\n * @returns {vec4} out\n */\nexport function normalize(out, a) {\n let x = a[0];\n let y = a[1];\n let z = a[2];\n let w = a[3];\n let len = x*x + y*y + z*z + w*w;\n if (len > 0) {\n len = 1 / Math.sqrt(len);\n out[0] = x * len;\n out[1] = y * len;\n out[2] = z * len;\n out[3] = w * len;\n }\n return out;\n}\n\n/**\n * Calculates the dot product of two vec4's\n *\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @returns {Number} dot product of a and b\n */\nexport function dot(a, b) {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];\n}\n\n/**\n * Performs a linear interpolation between two vec4's\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the first operand\n * @param {vec4} b the second operand\n * @param {Number} t interpolation amount, in the range [0-1], between the two inputs\n * @returns {vec4} out\n */\nexport function lerp(out, a, b, t) {\n let ax = a[0];\n let ay = a[1];\n let az = a[2];\n let aw = a[3];\n out[0] = ax + t * (b[0] - ax);\n out[1] = ay + t * (b[1] - ay);\n out[2] = az + t * (b[2] - az);\n out[3] = aw + t * (b[3] - aw);\n return out;\n}\n\n/**\n * Generates a random vector with the given scale\n *\n * @param {vec4} out the receiving vector\n * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\n * @returns {vec4} out\n */\nexport function random(out, scale) {\n scale = scale || 1.0;\n\n // Marsaglia, George. Choosing a Point from the Surface of a\n // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646.\n // http://projecteuclid.org/euclid.aoms/1177692644;\n var v1, v2, v3, v4;\n var s1, s2;\n do {\n v1 = glMatrix.RANDOM() * 2 - 1;\n v2 = glMatrix.RANDOM() * 2 - 1;\n s1 = v1 * v1 + v2 * v2;\n } while (s1 >= 1);\n do {\n v3 = glMatrix.RANDOM() * 2 - 1;\n v4 = glMatrix.RANDOM() * 2 - 1;\n s2 = v3 * v3 + v4 * v4;\n } while (s2 >= 1);\n\n var d = Math.sqrt((1 - s1) / s2);\n out[0] = scale * v1;\n out[1] = scale * v2;\n out[2] = scale * v3 * d;\n out[3] = scale * v4 * d;\n return out;\n}\n\n/**\n * Transforms the vec4 with a mat4.\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the vector to transform\n * @param {mat4} m matrix to transform with\n * @returns {vec4} out\n */\nexport function transformMat4(out, a, m) {\n let x = a[0], y = a[1], z = a[2], w = a[3];\n out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;\n out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;\n out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;\n out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;\n return out;\n}\n\n/**\n * Transforms the vec4 with a quat\n *\n * @param {vec4} out the receiving vector\n * @param {vec4} a the vector to transform\n * @param {quat} q quaternion to transform with\n * @returns {vec4} out\n */\nexport function transformQuat(out, a, q) {\n let x = a[0], y = a[1], z = a[2];\n let qx = q[0], qy = q[1], qz = q[2], qw = q[3];\n\n // calculate quat * vec\n let ix = qw * x + qy * z - qz * y;\n let iy = qw * y + qz * x - qx * z;\n let iz = qw * z + qx * y - qy * x;\n let iw = -qx * x - qy * y - qz * z;\n\n // calculate result * inverse quat\n out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;\n out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;\n out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;\n out[3] = a[3];\n return out;\n}\n\n/**\n * Returns a string representation of a vector\n *\n * @param {vec4} a vector to represent as a string\n * @returns {String} string representation of the vector\n */\nexport function str(a) {\n return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\n}\n\n/**\n * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)\n *\n * @param {vec4} a The first vector.\n * @param {vec4} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];\n}\n\n/**\n * Returns whether or not the vectors have approximately the same elements in the same position.\n *\n * @param {vec4} a The first vector.\n * @param {vec4} b The second vector.\n * @returns {Boolean} True if the vectors are equal, false otherwise.\n */\nexport function equals(a, b) {\n let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));\n}\n\n/**\n * Alias for {@link vec4.subtract}\n * @function\n */\nexport const sub = subtract;\n\n/**\n * Alias for {@link vec4.multiply}\n * @function\n */\nexport const mul = multiply;\n\n/**\n * Alias for {@link vec4.divide}\n * @function\n */\nexport const div = divide;\n\n/**\n * Alias for {@link vec4.distance}\n * @function\n */\nexport const dist = distance;\n\n/**\n * Alias for {@link vec4.squaredDistance}\n * @function\n */\nexport const sqrDist = squaredDistance;\n\n/**\n * Alias for {@link vec4.length}\n * @function\n */\nexport const len = length;\n\n/**\n * Alias for {@link vec4.squaredLength}\n * @function\n */\nexport const sqrLen = squaredLength;\n\n/**\n * Perform some operation over an array of vec4s.\n *\n * @param {Array} a the array of vectors to iterate over\n * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed\n * @param {Number} offset Number of elements to skip at the beginning of the array\n * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array\n * @param {Function} fn Function to call for each vector in the array\n * @param {Object} [arg] additional argument to pass to fn\n * @returns {Array} a\n * @function\n */\nexport const forEach = (function() {\n let vec = create();\n\n return function(a, stride, offset, count, fn, arg) {\n let i, l;\n if(!stride) {\n stride = 4;\n }\n\n if(!offset) {\n offset = 0;\n }\n\n if(count) {\n l = Math.min((count * stride) + offset, a.length);\n } else {\n l = a.length;\n }\n\n for(i = offset; i < l; i += stride) {\n vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];\n fn(vec, vec, arg);\n a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];\n }\n\n return a;\n };\n})();\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nconst GL = WebGLRenderingContext; // For enums\n\nexport const CAP = {\n // Enable caps\n CULL_FACE: 0x001,\n BLEND: 0x002,\n DEPTH_TEST: 0x004,\n STENCIL_TEST: 0x008,\n COLOR_MASK: 0x010,\n DEPTH_MASK: 0x020,\n STENCIL_MASK: 0x040,\n};\n\nexport const MAT_STATE = {\n CAPS_RANGE: 0x000000FF,\n BLEND_SRC_SHIFT: 8,\n BLEND_SRC_RANGE: 0x00000F00,\n BLEND_DST_SHIFT: 12,\n BLEND_DST_RANGE: 0x0000F000,\n BLEND_FUNC_RANGE: 0x0000FF00,\n DEPTH_FUNC_SHIFT: 16,\n DEPTH_FUNC_RANGE: 0x000F0000,\n};\n\nexport const RENDER_ORDER = {\n // Render opaque objects first.\n OPAQUE: 0,\n\n // Render the sky after all opaque object to save fill rate.\n SKY: 1,\n\n // Render transparent objects next so that the opaqe objects show through.\n TRANSPARENT: 2,\n\n // Finally render purely additive effects like pointer rays so that they\n // can render without depth mask.\n ADDITIVE: 3,\n\n // Render order will be picked based on the material properties.\n DEFAULT: 4,\n};\n\nexport function stateToBlendFunc(state, mask, shift) {\n let value = (state & mask) >> shift;\n switch (value) {\n case 0:\n case 1:\n return value;\n default:\n return (value - 2) + GL.SRC_COLOR;\n }\n}\n\nexport class MaterialState {\n constructor() {\n this._state = CAP.CULL_FACE |\n CAP.DEPTH_TEST |\n CAP.COLOR_MASK |\n CAP.DEPTH_MASK;\n\n // Use a fairly commonly desired blend func as the default.\n this.blendFuncSrc = GL.SRC_ALPHA;\n this.blendFuncDst = GL.ONE_MINUS_SRC_ALPHA;\n\n this.depthFunc = GL.LESS;\n }\n\n get cullFace() {\n return !!(this._state & CAP.CULL_FACE);\n }\n set cullFace(value) {\n if (value) {\n this._state |= CAP.CULL_FACE;\n } else {\n this._state &= ~CAP.CULL_FACE;\n }\n }\n\n get blend() {\n return !!(this._state & CAP.BLEND);\n }\n set blend(value) {\n if (value) {\n this._state |= CAP.BLEND;\n } else {\n this._state &= ~CAP.BLEND;\n }\n }\n\n get depthTest() {\n return !!(this._state & CAP.DEPTH_TEST);\n }\n set depthTest(value) {\n if (value) {\n this._state |= CAP.DEPTH_TEST;\n } else {\n this._state &= ~CAP.DEPTH_TEST;\n }\n }\n\n get stencilTest() {\n return !!(this._state & CAP.STENCIL_TEST);\n }\n set stencilTest(value) {\n if (value) {\n this._state |= CAP.STENCIL_TEST;\n } else {\n this._state &= ~CAP.STENCIL_TEST;\n }\n }\n\n get colorMask() {\n return !!(this._state & CAP.COLOR_MASK);\n }\n set colorMask(value) {\n if (value) {\n this._state |= CAP.COLOR_MASK;\n } else {\n this._state &= ~CAP.COLOR_MASK;\n }\n }\n\n get depthMask() {\n return !!(this._state & CAP.DEPTH_MASK);\n }\n set depthMask(value) {\n if (value) {\n this._state |= CAP.DEPTH_MASK;\n } else {\n this._state &= ~CAP.DEPTH_MASK;\n }\n }\n\n get depthFunc() {\n return ((this._state & MAT_STATE.DEPTH_FUNC_RANGE) >> MAT_STATE.DEPTH_FUNC_SHIFT) + GL.NEVER;\n }\n set depthFunc(value) {\n value = value - GL.NEVER;\n this._state &= ~MAT_STATE.DEPTH_FUNC_RANGE;\n this._state |= (value << MAT_STATE.DEPTH_FUNC_SHIFT);\n }\n\n get stencilMask() {\n return !!(this._state & CAP.STENCIL_MASK);\n }\n set stencilMask(value) {\n if (value) {\n this._state |= CAP.STENCIL_MASK;\n } else {\n this._state &= ~CAP.STENCIL_MASK;\n }\n }\n\n get blendFuncSrc() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_SRC_RANGE, MAT_STATE.BLEND_SRC_SHIFT);\n }\n set blendFuncSrc(value) {\n switch (value) {\n case 0:\n case 1:\n break;\n default:\n value = (value - GL.SRC_COLOR) + 2;\n }\n this._state &= ~MAT_STATE.BLEND_SRC_RANGE;\n this._state |= (value << MAT_STATE.BLEND_SRC_SHIFT);\n }\n\n get blendFuncDst() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_DST_RANGE, MAT_STATE.BLEND_DST_SHIFT);\n }\n set blendFuncDst(value) {\n switch (value) {\n case 0:\n case 1:\n break;\n default:\n value = (value - GL.SRC_COLOR) + 2;\n }\n this._state &= ~MAT_STATE.BLEND_DST_RANGE;\n this._state |= (value << MAT_STATE.BLEND_DST_SHIFT);\n }\n}\n\nclass MaterialSampler {\n constructor(uniformName) {\n this._uniformName = uniformName;\n this._texture = null;\n }\n\n get texture() {\n return this._texture;\n }\n\n set texture(value) {\n this._texture = value;\n }\n}\n\nclass MaterialUniform {\n constructor(uniformName, defaultValue, length) {\n this._uniformName = uniformName;\n this._value = defaultValue;\n this._length = length;\n if (!this._length) {\n if (defaultValue instanceof Array) {\n this._length = defaultValue.length;\n } else {\n this._length = 1;\n }\n }\n }\n\n get value() {\n return this._value;\n }\n\n set value(value) {\n this._value = value;\n }\n}\n\nexport class Material {\n constructor() {\n this.state = new MaterialState;\n this.renderOrder = RENDER_ORDER.DEFAULT;\n this._samplers = [];\n this._uniforms = [];\n }\n\n defineSampler(uniformName) {\n let sampler = new MaterialSampler(uniformName);\n this._samplers.push(sampler);\n return sampler;\n }\n\n defineUniform(uniformName, defaultValue=null, length=0) {\n let uniform = new MaterialUniform(uniformName, defaultValue, length);\n this._uniforms.push(uniform);\n return uniform;\n }\n\n get materialName() {\n return null;\n }\n\n get vertexSource() {\n return null;\n }\n\n get fragmentSource() {\n return null;\n }\n\n getProgramDefines(renderPrimitive) {\n return {};\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Ray} from '../math/ray.js';\nimport {mat4, vec3, quat} from '../math/gl-matrix.js';\n\nconst DEFAULT_TRANSLATION = new Float32Array([0, 0, 0]);\nconst DEFAULT_ROTATION = new Float32Array([0, 0, 0, 1]);\nconst DEFAULT_SCALE = new Float32Array([1, 1, 1]);\n\nlet tmpRayMatrix = mat4.create();\n\nexport class Node {\n constructor() {\n this.name = null; // Only for debugging\n this.children = [];\n this.parent = null;\n this.visible = true;\n this.selectable = false;\n\n this._matrix = null;\n\n this._dirtyTRS = false;\n this._translation = null;\n this._rotation = null;\n this._scale = null;\n\n this._dirtyWorldMatrix = false;\n this._worldMatrix = null;\n\n this._activeFrameId = -1;\n this._hoverFrameId = -1;\n this._renderPrimitives = null;\n this._renderer = null;\n\n this._selectHandler = null;\n }\n\n _setRenderer(renderer) {\n if (this._renderer == renderer) {\n return;\n }\n\n if (this._renderer) {\n // Changing the renderer removes any previously attached renderPrimitives\n // from a different renderer.\n this.clearRenderPrimitives();\n }\n\n this._renderer = renderer;\n if (renderer) {\n this.onRendererChanged(renderer);\n\n for (let child of this.children) {\n child._setRenderer(renderer);\n }\n }\n }\n\n onRendererChanged(renderer) {\n // Override in other node types to respond to changes in the renderer.\n }\n\n // Create a clone of this node and all of it's children. Does not duplicate\n // RenderPrimitives, the cloned nodes will be treated as new instances of the\n // geometry.\n clone() {\n let cloneNode = new Node();\n cloneNode.name = this.name;\n cloneNode.visible = this.visible;\n cloneNode._renderer = this._renderer;\n\n cloneNode._dirtyTRS = this._dirtyTRS;\n\n if (this._translation) {\n cloneNode._translation = vec3.create();\n vec3.copy(cloneNode._translation, this._translation);\n }\n\n if (this._rotation) {\n cloneNode._rotation = quat.create();\n quat.copy(cloneNode._rotation, this._rotation);\n }\n\n if (this._scale) {\n cloneNode._scale = vec3.create();\n vec3.copy(cloneNode._scale, this._scale);\n }\n\n // Only copy the matrices if they're not already dirty.\n if (!cloneNode._dirtyTRS && this._matrix) {\n cloneNode._matrix = mat4.create();\n mat4.copy(cloneNode._matrix, this._matrix);\n }\n\n cloneNode._dirtyWorldMatrix = this._dirtyWorldMatrix;\n if (!cloneNode._dirtyWorldMatrix && this._worldMatrix) {\n cloneNode._worldMatrix = mat4.create();\n mat4.copy(cloneNode._worldMatrix, this._worldMatrix);\n }\n\n this.waitForComplete().then(() => {\n if (this._renderPrimitives) {\n for (let primitive of this._renderPrimitives) {\n cloneNode.addRenderPrimitive(primitive);\n }\n }\n\n for (let child of this.children) {\n cloneNode.addNode(child.clone());\n }\n });\n\n return cloneNode;\n }\n\n markActive(frameId) {\n if (this.visible && this._renderPrimitives) {\n this._activeFrameId = frameId;\n for (let primitive of this._renderPrimitives) {\n primitive.markActive(frameId);\n }\n }\n\n for (let child of this.children) {\n if (child.visible) {\n child.markActive(frameId);\n }\n }\n }\n\n addNode(value) {\n if (!value || value.parent == this) {\n return;\n }\n\n if (value.parent) {\n value.parent.removeNode(value);\n }\n value.parent = this;\n\n this.children.push(value);\n\n if (this._renderer) {\n value._setRenderer(this._renderer);\n }\n }\n\n removeNode(value) {\n let i = this.children.indexOf(value);\n if (i > -1) {\n this.children.splice(i, 1);\n value.parent = null;\n }\n }\n\n clearNodes() {\n for (let child of this.children) {\n child.parent = null;\n }\n this.children = [];\n }\n\n setMatrixDirty() {\n if (!this._dirtyWorldMatrix) {\n this._dirtyWorldMatrix = true;\n for (let child of this.children) {\n child.setMatrixDirty();\n }\n }\n }\n\n _updateLocalMatrix() {\n if (!this._matrix) {\n this._matrix = mat4.create();\n }\n\n if (this._dirtyTRS) {\n this._dirtyTRS = false;\n mat4.fromRotationTranslationScale(\n this._matrix,\n this._rotation || DEFAULT_ROTATION,\n this._translation || DEFAULT_TRANSLATION,\n this._scale || DEFAULT_SCALE);\n }\n\n return this._matrix;\n }\n\n set matrix(value) {\n if (value) {\n if (!this._matrix) {\n this._matrix = mat4.create();\n }\n mat4.copy(this._matrix, value);\n } else {\n this._matrix = null;\n }\n this.setMatrixDirty();\n this._dirtyTRS = false;\n this._translation = null;\n this._rotation = null;\n this._scale = null;\n }\n\n get matrix() {\n this.setMatrixDirty();\n\n return this._updateLocalMatrix();\n }\n\n get worldMatrix() {\n if (!this._worldMatrix) {\n this._dirtyWorldMatrix = true;\n this._worldMatrix = mat4.create();\n }\n\n if (this._dirtyWorldMatrix || this._dirtyTRS) {\n if (this.parent) {\n // TODO: Some optimizations that could be done here if the node matrix\n // is an identity matrix.\n mat4.mul(this._worldMatrix, this.parent.worldMatrix, this._updateLocalMatrix());\n } else {\n mat4.copy(this._worldMatrix, this._updateLocalMatrix());\n }\n this._dirtyWorldMatrix = false;\n }\n\n return this._worldMatrix;\n }\n\n // TODO: Decompose matrix when fetching these?\n set translation(value) {\n if (value != null) {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n }\n this._translation = value;\n }\n\n get translation() {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n if (!this._translation) {\n this._translation = vec3.clone(DEFAULT_TRANSLATION);\n }\n return this._translation;\n }\n\n set rotation(value) {\n if (value != null) {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n }\n this._rotation = value;\n }\n\n get rotation() {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n if (!this._rotation) {\n this._rotation = quat.clone(DEFAULT_ROTATION);\n }\n return this._rotation;\n }\n\n set scale(value) {\n if (value != null) {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n }\n this._scale = value;\n }\n\n get scale() {\n this._dirtyTRS = true;\n this.setMatrixDirty();\n if (!this._scale) {\n this._scale = vec3.clone(DEFAULT_SCALE);\n }\n return this._scale;\n }\n\n waitForComplete() {\n let childPromises = [];\n for (let child of this.children) {\n childPromises.push(child.waitForComplete());\n }\n if (this._renderPrimitives) {\n for (let primitive of this._renderPrimitives) {\n childPromises.push(primitive.waitForComplete());\n }\n }\n return Promise.all(childPromises).then(() => this);\n }\n\n get renderPrimitives() {\n return this._renderPrimitives;\n }\n\n addRenderPrimitive(primitive) {\n if (!this._renderPrimitives) {\n this._renderPrimitives = [primitive];\n } else {\n this._renderPrimitives.push(primitive);\n }\n primitive._instances.push(this);\n }\n\n removeRenderPrimitive(primitive) {\n if (!this._renderPrimitives) {\n return;\n }\n\n let index = this._renderPrimitives._instances.indexOf(primitive);\n if (index > -1) {\n this._renderPrimitives._instances.splice(index, 1);\n\n index = primitive._instances.indexOf(this);\n if (index > -1) {\n primitive._instances.splice(index, 1);\n }\n\n if (!this._renderPrimitives.length) {\n this._renderPrimitives = null;\n }\n }\n }\n\n clearRenderPrimitives() {\n if (this._renderPrimitives) {\n for (let primitive of this._renderPrimitives) {\n let index = primitive._instances.indexOf(this);\n if (index > -1) {\n primitive._instances.splice(index, 1);\n }\n }\n this._renderPrimitives = null;\n }\n }\n\n _hitTestSelectableNode(ray) {\n if (this._renderPrimitives) {\n let localRay = null;\n for (let primitive of this._renderPrimitives) {\n if (primitive._min) {\n if (!localRay) {\n mat4.invert(tmpRayMatrix, this.worldMatrix);\n mat4.multiply(tmpRayMatrix, tmpRayMatrix, ray.transformMatrix);\n localRay = new Ray(tmpRayMatrix);\n }\n let intersection = localRay.intersectsAABB(primitive._min, primitive._max);\n if (intersection) {\n vec3.transformMat4(intersection, intersection, this.worldMatrix);\n return intersection;\n }\n }\n }\n }\n for (let child of this.children) {\n let intersection = child._hitTestSelectableNode(ray);\n if (intersection) {\n return intersection;\n }\n }\n return null;\n }\n\n hitTest(ray) {\n if (this.selectable && this.visible) {\n let intersection = this._hitTestSelectableNode(ray);\n\n if (intersection) {\n let origin = vec3.fromValues(ray.origin.x, ray.origin.y, ray.origin.z);\n return {\n node: this,\n intersection: intersection,\n distance: vec3.distance(origin, intersection),\n };\n }\n return null;\n }\n\n let result = null;\n for (let child of this.children) {\n let childResult = child.hitTest(ray);\n if (childResult) {\n if (!result || result.distance > childResult.distance) {\n result = childResult;\n }\n }\n }\n return result;\n }\n\n onSelect(value) {\n this._selectHandler = value;\n }\n\n get selectHandler() {\n return this._selectHandler;\n }\n\n // Called when a selectable node is selected.\n handleSelect() {\n if (this._selectHandler) {\n this._selectHandler();\n }\n }\n\n // Called when a selectable element is pointed at.\n onHoverStart() {\n\n }\n\n // Called when a selectable element is no longer pointed at.\n onHoverEnd() {\n\n }\n\n _update(timestamp, frameDelta) {\n this.onUpdate(timestamp, frameDelta);\n\n for (let child of this.children) {\n child._update(timestamp, frameDelta);\n }\n }\n\n // Called every frame so that the nodes can animate themselves\n onUpdate(timestamp, frameDelta) {\n\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {vec3} from '../math/gl-matrix.js';\n\nexport class PrimitiveAttribute {\n constructor(name, buffer, componentCount, componentType, stride, byteOffset) {\n this.name = name;\n this.buffer = buffer;\n this.componentCount = componentCount || 3;\n this.componentType = componentType || 5126; // gl.FLOAT;\n this.stride = stride || 0;\n this.byteOffset = byteOffset || 0;\n this.normalized = false;\n }\n}\n\nexport class Primitive {\n constructor(attributes, elementCount, mode) {\n this.attributes = attributes || [];\n this.elementCount = elementCount || 0;\n this.mode = mode || 4; // gl.TRIANGLES;\n this.indexBuffer = null;\n this.indexByteOffset = 0;\n this.indexType = 0;\n this._min = null;\n this._max = null;\n }\n\n setIndexBuffer(indexBuffer, byteOffset, indexType) {\n this.indexBuffer = indexBuffer;\n this.indexByteOffset = byteOffset || 0;\n this.indexType = indexType || 5123; // gl.UNSIGNED_SHORT;\n }\n\n setBounds(min, max) {\n this._min = vec3.clone(min);\n this._max = vec3.clone(max);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nexport class Program {\n constructor(gl, vertSrc, fragSrc, attribMap, defines) {\n this._gl = gl;\n this.program = gl.createProgram();\n this.attrib = null;\n this.uniform = null;\n this.defines = {};\n\n this._firstUse = true;\n this._nextUseCallbacks = [];\n\n let definesString = '';\n if (defines) {\n for (let define in defines) {\n this.defines[define] = defines[define];\n definesString += `#define ${define} ${defines[define]}\\n`;\n }\n }\n\n this._vertShader = gl.createShader(gl.VERTEX_SHADER);\n gl.attachShader(this.program, this._vertShader);\n gl.shaderSource(this._vertShader, definesString + vertSrc);\n gl.compileShader(this._vertShader);\n\n this._fragShader = gl.createShader(gl.FRAGMENT_SHADER);\n gl.attachShader(this.program, this._fragShader);\n gl.shaderSource(this._fragShader, definesString + fragSrc);\n gl.compileShader(this._fragShader);\n\n if (attribMap) {\n this.attrib = {};\n for (let attribName in attribMap) {\n gl.bindAttribLocation(this.program, attribMap[attribName], attribName);\n this.attrib[attribName] = attribMap[attribName];\n }\n }\n\n gl.linkProgram(this.program);\n }\n\n onNextUse(callback) {\n this._nextUseCallbacks.push(callback);\n }\n\n use() {\n let gl = this._gl;\n\n // If this is the first time the program has been used do all the error checking and\n // attrib/uniform querying needed.\n if (this._firstUse) {\n this._firstUse = false;\n if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {\n if (!gl.getShaderParameter(this._vertShader, gl.COMPILE_STATUS)) {\n console.error('Vertex shader compile error: ' + gl.getShaderInfoLog(this._vertShader));\n } else if (!gl.getShaderParameter(this._fragShader, gl.COMPILE_STATUS)) {\n console.error('Fragment shader compile error: ' + gl.getShaderInfoLog(this._fragShader));\n } else {\n console.error('Program link error: ' + gl.getProgramInfoLog(this.program));\n }\n gl.deleteProgram(this.program);\n this.program = null;\n } else {\n if (!this.attrib) {\n this.attrib = {};\n let attribCount = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES);\n for (let i = 0; i < attribCount; i++) {\n let attribInfo = gl.getActiveAttrib(this.program, i);\n this.attrib[attribInfo.name] = gl.getAttribLocation(this.program, attribInfo.name);\n }\n }\n\n this.uniform = {};\n let uniformCount = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS);\n let uniformName = '';\n for (let i = 0; i < uniformCount; i++) {\n let uniformInfo = gl.getActiveUniform(this.program, i);\n uniformName = uniformInfo.name.replace('[0]', '');\n this.uniform[uniformName] = gl.getUniformLocation(this.program, uniformName);\n }\n }\n gl.deleteShader(this._vertShader);\n gl.deleteShader(this._fragShader);\n }\n\n gl.useProgram(this.program);\n\n if (this._nextUseCallbacks.length) {\n for (let callback of this._nextUseCallbacks) {\n callback(this);\n }\n this._nextUseCallbacks = [];\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {CAP, MAT_STATE, RENDER_ORDER, stateToBlendFunc} from './material.js';\nimport {Node} from './node.js';\nimport {Program} from './program.js';\nimport {DataTexture, VideoTexture} from './texture.js';\nimport {mat4, vec3} from '../math/gl-matrix.js';\n\nexport const ATTRIB = {\n POSITION: 1,\n NORMAL: 2,\n TANGENT: 3,\n TEXCOORD_0: 4,\n TEXCOORD_1: 5,\n COLOR_0: 6,\n};\n\nexport const ATTRIB_MASK = {\n POSITION: 0x0001,\n NORMAL: 0x0002,\n TANGENT: 0x0004,\n TEXCOORD_0: 0x0008,\n TEXCOORD_1: 0x0010,\n COLOR_0: 0x0020,\n};\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst DEF_LIGHT_DIR = new Float32Array([-0.1, -1.0, -0.2]);\nconst DEF_LIGHT_COLOR = new Float32Array([3.0, 3.0, 3.0]);\n\nconst PRECISION_REGEX = new RegExp('precision (lowp|mediump|highp) float;');\n\nconst VERTEX_SHADER_SINGLE_ENTRY = `\nuniform mat4 PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX;\n\nvoid main() {\n gl_Position = vertex_main(PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX);\n}\n`;\n\nconst VERTEX_SHADER_MULTI_ENTRY = `\n#ERROR Multiview rendering is not implemented\nvoid main() {\n gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER_ENTRY = `\nvoid main() {\n gl_FragColor = fragment_main();\n}\n`;\n\nfunction isPowerOfTwo(n) {\n return (n & (n - 1)) === 0;\n}\n\n// Creates a WebGL context and initializes it with some common default state.\nexport function createWebGLContext(glAttribs) {\n glAttribs = glAttribs || {alpha: false};\n\n let webglCanvas = document.createElement('canvas');\n let contextTypes = glAttribs.webgl2 ? ['webgl2'] : ['webgl', 'experimental-webgl'];\n let context = null;\n\n for (let contextType of contextTypes) {\n context = webglCanvas.getContext(contextType, glAttribs);\n if (context) {\n break;\n }\n }\n\n if (!context) {\n let webglType = (glAttribs.webgl2 ? 'WebGL 2' : 'WebGL');\n console.error('This browser does not support ' + webglType + '.');\n return null;\n }\n\n return context;\n}\n\nexport class RenderView {\n constructor(projectionMatrix, viewMatrix, viewport = null, eye = 'left') {\n this.projectionMatrix = projectionMatrix;\n this.viewMatrix = viewMatrix;\n this.viewport = viewport;\n // If an eye isn't given the left eye is assumed.\n this._eye = eye;\n this._eyeIndex = (eye == 'left' ? 0 : 1);\n }\n\n get eye() {\n return this._eye;\n }\n\n set eye(value) {\n this._eye = value;\n this._eyeIndex = (value == 'left' ? 0 : 1);\n }\n\n get eyeIndex() {\n return this._eyeIndex;\n }\n}\n\nclass RenderBuffer {\n constructor(target, usage, buffer, length = 0) {\n this._target = target;\n this._usage = usage;\n this._length = length;\n if (buffer instanceof Promise) {\n this._buffer = null;\n this._promise = buffer.then((buffer) => {\n this._buffer = buffer;\n return this;\n });\n } else {\n this._buffer = buffer;\n this._promise = Promise.resolve(this);\n }\n }\n\n waitForComplete() {\n return this._promise;\n }\n}\n\nclass RenderPrimitiveAttribute {\n constructor(primitiveAttribute) {\n this._attrib_index = ATTRIB[primitiveAttribute.name];\n this._componentCount = primitiveAttribute.componentCount;\n this._componentType = primitiveAttribute.componentType;\n this._stride = primitiveAttribute.stride;\n this._byteOffset = primitiveAttribute.byteOffset;\n this._normalized = primitiveAttribute.normalized;\n }\n}\n\nclass RenderPrimitiveAttributeBuffer {\n constructor(buffer) {\n this._buffer = buffer;\n this._attributes = [];\n }\n}\n\nclass RenderPrimitive {\n constructor(primitive) {\n this._activeFrameId = 0;\n this._instances = [];\n this._material = null;\n\n this.setPrimitive(primitive);\n }\n\n setPrimitive(primitive) {\n this._mode = primitive.mode;\n this._elementCount = primitive.elementCount;\n this._promise = null;\n this._vao = null;\n this._complete = false;\n this._attributeBuffers = [];\n this._attributeMask = 0;\n\n for (let attribute of primitive.attributes) {\n this._attributeMask |= ATTRIB_MASK[attribute.name];\n let renderAttribute = new RenderPrimitiveAttribute(attribute);\n let foundBuffer = false;\n for (let attributeBuffer of this._attributeBuffers) {\n if (attributeBuffer._buffer == attribute.buffer) {\n attributeBuffer._attributes.push(renderAttribute);\n foundBuffer = true;\n break;\n }\n }\n if (!foundBuffer) {\n let attributeBuffer = new RenderPrimitiveAttributeBuffer(attribute.buffer);\n attributeBuffer._attributes.push(renderAttribute);\n this._attributeBuffers.push(attributeBuffer);\n }\n }\n\n this._indexBuffer = null;\n this._indexByteOffset = 0;\n this._indexType = 0;\n\n if (primitive.indexBuffer) {\n this._indexByteOffset = primitive.indexByteOffset;\n this._indexType = primitive.indexType;\n this._indexBuffer = primitive.indexBuffer;\n }\n\n if (primitive._min) {\n this._min = vec3.clone(primitive._min);\n this._max = vec3.clone(primitive._max);\n } else {\n this._min = null;\n this._max = null;\n }\n\n if (this._material != null) {\n this.waitForComplete(); // To flip the _complete flag.\n }\n }\n\n setRenderMaterial(material) {\n this._material = material;\n this._promise = null;\n this._complete = false;\n\n if (this._material != null) {\n this.waitForComplete(); // To flip the _complete flag.\n }\n }\n\n markActive(frameId) {\n if (this._complete && this._activeFrameId != frameId) {\n if (this._material) {\n if (!this._material.markActive(frameId)) {\n return;\n }\n }\n this._activeFrameId = frameId;\n }\n }\n\n get samplers() {\n return this._material._samplerDictionary;\n }\n\n get uniforms() {\n return this._material._uniform_dictionary;\n }\n\n waitForComplete() {\n if (!this._promise) {\n if (!this._material) {\n return Promise.reject('RenderPrimitive does not have a material');\n }\n\n let completionPromises = [];\n\n for (let attributeBuffer of this._attributeBuffers) {\n if (!attributeBuffer._buffer._buffer) {\n completionPromises.push(attributeBuffer._buffer._promise);\n }\n }\n\n if (this._indexBuffer && !this._indexBuffer._buffer) {\n completionPromises.push(this._indexBuffer._promise);\n }\n\n this._promise = Promise.all(completionPromises).then(() => {\n this._complete = true;\n return this;\n });\n }\n return this._promise;\n }\n}\n\nexport class RenderTexture {\n constructor(texture) {\n this._texture = texture;\n this._complete = false;\n this._activeFrameId = 0;\n this._activeCallback = null;\n }\n\n markActive(frameId) {\n if (this._activeCallback && this._activeFrameId != frameId) {\n this._activeFrameId = frameId;\n this._activeCallback(this);\n }\n }\n}\n\nconst inverseMatrix = mat4.create();\n\nfunction setCap(gl, glEnum, cap, prevState, state) {\n let change = (state & cap) - (prevState & cap);\n if (!change) {\n return;\n }\n\n if (change > 0) {\n gl.enable(glEnum);\n } else {\n gl.disable(glEnum);\n }\n}\n\nclass RenderMaterialSampler {\n constructor(renderer, materialSampler, index) {\n this._renderer = renderer;\n this._uniformName = materialSampler._uniformName;\n this._renderTexture = renderer._getRenderTexture(materialSampler._texture);\n this._index = index;\n }\n\n set texture(value) {\n this._renderTexture = this._renderer._getRenderTexture(value);\n }\n}\n\nclass RenderMaterialUniform {\n constructor(materialUniform) {\n this._uniformName = materialUniform._uniformName;\n this._uniform = null;\n this._length = materialUniform._length;\n if (materialUniform._value instanceof Array) {\n this._value = new Float32Array(materialUniform._value);\n } else {\n this._value = new Float32Array([materialUniform._value]);\n }\n }\n\n set value(value) {\n if (this._value.length == 1) {\n this._value[0] = value;\n } else {\n for (let i = 0; i < this._value.length; ++i) {\n this._value[i] = value[i];\n }\n }\n }\n}\n\nclass RenderMaterial {\n constructor(renderer, material, program) {\n this._program = program;\n this._state = material.state._state;\n this._activeFrameId = 0;\n this._completeForActiveFrame = false;\n\n this._samplerDictionary = {};\n this._samplers = [];\n for (let i = 0; i < material._samplers.length; ++i) {\n let renderSampler = new RenderMaterialSampler(renderer, material._samplers[i], i);\n this._samplers.push(renderSampler);\n this._samplerDictionary[renderSampler._uniformName] = renderSampler;\n }\n\n this._uniform_dictionary = {};\n this._uniforms = [];\n for (let uniform of material._uniforms) {\n let renderUniform = new RenderMaterialUniform(uniform);\n this._uniforms.push(renderUniform);\n this._uniform_dictionary[renderUniform._uniformName] = renderUniform;\n }\n\n this._firstBind = true;\n\n this._renderOrder = material.renderOrder;\n if (this._renderOrder == RENDER_ORDER.DEFAULT) {\n if (this._state & CAP.BLEND) {\n this._renderOrder = RENDER_ORDER.TRANSPARENT;\n } else {\n this._renderOrder = RENDER_ORDER.OPAQUE;\n }\n }\n }\n\n bind(gl) {\n // First time we do a binding, cache the uniform locations and remove\n // unused uniforms from the list.\n if (this._firstBind) {\n for (let i = 0; i < this._samplers.length;) {\n let sampler = this._samplers[i];\n if (!this._program.uniform[sampler._uniformName]) {\n this._samplers.splice(i, 1);\n continue;\n }\n ++i;\n }\n\n for (let i = 0; i < this._uniforms.length;) {\n let uniform = this._uniforms[i];\n uniform._uniform = this._program.uniform[uniform._uniformName];\n if (!uniform._uniform) {\n this._uniforms.splice(i, 1);\n continue;\n }\n ++i;\n }\n this._firstBind = false;\n }\n\n for (let sampler of this._samplers) {\n gl.activeTexture(gl.TEXTURE0 + sampler._index);\n if (sampler._renderTexture && sampler._renderTexture._complete) {\n gl.bindTexture(gl.TEXTURE_2D, sampler._renderTexture._texture);\n } else {\n gl.bindTexture(gl.TEXTURE_2D, null);\n }\n }\n\n for (let uniform of this._uniforms) {\n switch (uniform._length) {\n case 1: gl.uniform1fv(uniform._uniform, uniform._value); break;\n case 2: gl.uniform2fv(uniform._uniform, uniform._value); break;\n case 3: gl.uniform3fv(uniform._uniform, uniform._value); break;\n case 4: gl.uniform4fv(uniform._uniform, uniform._value); break;\n }\n }\n }\n\n markActive(frameId) {\n if (this._activeFrameId != frameId) {\n this._activeFrameId = frameId;\n this._completeForActiveFrame = true;\n for (let i = 0; i < this._samplers.length; ++i) {\n let sampler = this._samplers[i];\n if (sampler._renderTexture) {\n if (!sampler._renderTexture._complete) {\n this._completeForActiveFrame = false;\n break;\n }\n sampler._renderTexture.markActive(frameId);\n }\n }\n }\n return this._completeForActiveFrame;\n }\n\n // Material State fetchers\n get cullFace() {\n return !!(this._state & CAP.CULL_FACE);\n }\n get blend() {\n return !!(this._state & CAP.BLEND);\n }\n get depthTest() {\n return !!(this._state & CAP.DEPTH_TEST);\n }\n get stencilTest() {\n return !!(this._state & CAP.STENCIL_TEST);\n }\n get colorMask() {\n return !!(this._state & CAP.COLOR_MASK);\n }\n get depthMask() {\n return !!(this._state & CAP.DEPTH_MASK);\n }\n get stencilMask() {\n return !!(this._state & CAP.STENCIL_MASK);\n }\n get depthFunc() {\n return ((this._state & MAT_STATE.DEPTH_FUNC_RANGE) >> MAT_STATE.DEPTH_FUNC_SHIFT) + GL.NEVER;\n }\n get blendFuncSrc() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_SRC_RANGE, MAT_STATE.BLEND_SRC_SHIFT);\n }\n get blendFuncDst() {\n return stateToBlendFunc(this._state, MAT_STATE.BLEND_DST_RANGE, MAT_STATE.BLEND_DST_SHIFT);\n }\n\n // Only really for use from the renderer\n _capsDiff(otherState) {\n return (otherState & MAT_STATE.CAPS_RANGE) ^ (this._state & MAT_STATE.CAPS_RANGE);\n }\n\n _blendDiff(otherState) {\n if (!(this._state & CAP.BLEND)) {\n return 0;\n }\n return (otherState & MAT_STATE.BLEND_FUNC_RANGE) ^ (this._state & MAT_STATE.BLEND_FUNC_RANGE);\n }\n\n _depthFuncDiff(otherState) {\n if (!(this._state & CAP.DEPTH_TEST)) {\n return 0;\n }\n return (otherState & MAT_STATE.DEPTH_FUNC_RANGE) ^ (this._state & MAT_STATE.DEPTH_FUNC_RANGE);\n }\n}\n\nexport class Renderer {\n constructor(gl) {\n this._gl = gl || createWebGLContext();\n this._frameId = 0;\n this._programCache = {};\n this._textureCache = {};\n this._renderPrimitives = Array(RENDER_ORDER.DEFAULT);\n this._cameraPositions = [];\n\n this._vaoExt = gl.getExtension('OES_vertex_array_object');\n\n let fragHighPrecision = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);\n this._defaultFragPrecision = fragHighPrecision.precision > 0 ? 'highp' : 'mediump';\n\n this._depthMaskNeedsReset = false;\n this._colorMaskNeedsReset = false;\n\n this._globalLightColor = vec3.clone(DEF_LIGHT_COLOR);\n this._globalLightDir = vec3.clone(DEF_LIGHT_DIR);\n }\n\n get gl() {\n return this._gl;\n }\n\n set globalLightColor(value) {\n vec3.copy(this._globalLightColor, value);\n }\n\n get globalLightColor() {\n return vec3.clone(this._globalLightColor);\n }\n\n set globalLightDir(value) {\n vec3.copy(this._globalLightDir, value);\n }\n\n get globalLightDir() {\n return vec3.clone(this._globalLightDir);\n }\n\n createRenderBuffer(target, data, usage = GL.STATIC_DRAW) {\n let gl = this._gl;\n let glBuffer = gl.createBuffer();\n\n if (data instanceof Promise) {\n let renderBuffer = new RenderBuffer(target, usage, data.then((data) => {\n gl.bindBuffer(target, glBuffer);\n gl.bufferData(target, data, usage);\n renderBuffer._length = data.byteLength;\n return glBuffer;\n }));\n return renderBuffer;\n } else {\n gl.bindBuffer(target, glBuffer);\n gl.bufferData(target, data, usage);\n return new RenderBuffer(target, usage, glBuffer, data.byteLength);\n }\n }\n\n updateRenderBuffer(buffer, data, offset = 0) {\n if (buffer._buffer) {\n let gl = this._gl;\n gl.bindBuffer(buffer._target, buffer._buffer);\n if (offset == 0 && buffer._length == data.byteLength) {\n gl.bufferData(buffer._target, data, buffer._usage);\n } else {\n gl.bufferSubData(buffer._target, offset, data);\n }\n } else {\n buffer.waitForComplete().then((buffer) => {\n this.updateRenderBuffer(buffer, data, offset);\n });\n }\n }\n\n createRenderPrimitive(primitive, material) {\n let renderPrimitive = new RenderPrimitive(primitive);\n\n let program = this._getMaterialProgram(material, renderPrimitive);\n let renderMaterial = new RenderMaterial(this, material, program);\n renderPrimitive.setRenderMaterial(renderMaterial);\n\n if (!this._renderPrimitives[renderMaterial._renderOrder]) {\n this._renderPrimitives[renderMaterial._renderOrder] = [];\n }\n\n this._renderPrimitives[renderMaterial._renderOrder].push(renderPrimitive);\n\n return renderPrimitive;\n }\n\n createMesh(primitive, material) {\n let meshNode = new Node();\n meshNode.addRenderPrimitive(this.createRenderPrimitive(primitive, material));\n return meshNode;\n }\n\n drawViews(views, rootNode) {\n if (!rootNode) {\n return;\n }\n\n let gl = this._gl;\n this._frameId++;\n\n rootNode.markActive(this._frameId);\n\n // If there's only one view then flip the algorithm a bit so that we're only\n // setting the viewport once.\n if (views.length == 1 && views[0].viewport) {\n let vp = views[0].viewport;\n this._gl.viewport(vp.x, vp.y, vp.width, vp.height);\n }\n\n // Get the positions of the 'camera' for each view matrix.\n for (let i = 0; i < views.length; ++i) {\n mat4.invert(inverseMatrix, views[i].viewMatrix);\n\n if (this._cameraPositions.length <= i) {\n this._cameraPositions.push(vec3.create());\n }\n let cameraPosition = this._cameraPositions[i];\n vec3.set(cameraPosition, 0, 0, 0);\n vec3.transformMat4(cameraPosition, cameraPosition, inverseMatrix);\n }\n\n // Draw each set of render primitives in order\n for (let renderPrimitives of this._renderPrimitives) {\n if (renderPrimitives && renderPrimitives.length) {\n this._drawRenderPrimitiveSet(views, renderPrimitives);\n }\n }\n\n if (this._vaoExt) {\n this._vaoExt.bindVertexArrayOES(null);\n }\n\n if (this._depthMaskNeedsReset) {\n gl.depthMask(true);\n }\n if (this._colorMaskNeedsReset) {\n gl.colorMask(true, true, true, true);\n }\n }\n\n _drawRenderPrimitiveSet(views, renderPrimitives) {\n let gl = this._gl;\n let program = null;\n let material = null;\n let attribMask = 0;\n\n // Loop through every primitive known to the renderer.\n for (let primitive of renderPrimitives) {\n // Skip over those that haven't been marked as active for this frame.\n if (primitive._activeFrameId != this._frameId) {\n continue;\n }\n\n // Bind the primitive material's program if it's different than the one we\n // were using for the previous primitive.\n // TODO: The ording of this could be more efficient.\n if (program != primitive._material._program) {\n program = primitive._material._program;\n program.use();\n\n if (program.uniform.LIGHT_DIRECTION) {\n gl.uniform3fv(program.uniform.LIGHT_DIRECTION, this._globalLightDir);\n }\n\n if (program.uniform.LIGHT_COLOR) {\n gl.uniform3fv(program.uniform.LIGHT_COLOR, this._globalLightColor);\n }\n\n if (views.length == 1) {\n gl.uniformMatrix4fv(program.uniform.PROJECTION_MATRIX, false, views[0].projectionMatrix);\n gl.uniformMatrix4fv(program.uniform.VIEW_MATRIX, false, views[0].viewMatrix);\n gl.uniform3fv(program.uniform.CAMERA_POSITION, this._cameraPositions[0]);\n gl.uniform1i(program.uniform.EYE_INDEX, views[0].eyeIndex);\n }\n }\n\n if (material != primitive._material) {\n this._bindMaterialState(primitive._material, material);\n primitive._material.bind(gl, program, material);\n material = primitive._material;\n }\n\n if (this._vaoExt) {\n if (primitive._vao) {\n this._vaoExt.bindVertexArrayOES(primitive._vao);\n } else {\n primitive._vao = this._vaoExt.createVertexArrayOES();\n this._vaoExt.bindVertexArrayOES(primitive._vao);\n this._bindPrimitive(primitive);\n }\n } else {\n this._bindPrimitive(primitive, attribMask);\n attribMask = primitive._attributeMask;\n }\n\n for (let i = 0; i < views.length; ++i) {\n let view = views[i];\n if (views.length > 1) {\n if (view.viewport) {\n let vp = view.viewport;\n gl.viewport(vp.x, vp.y, vp.width, vp.height);\n }\n gl.uniformMatrix4fv(program.uniform.PROJECTION_MATRIX, false, view.projectionMatrix);\n gl.uniformMatrix4fv(program.uniform.VIEW_MATRIX, false, view.viewMatrix);\n gl.uniform3fv(program.uniform.CAMERA_POSITION, this._cameraPositions[i]);\n gl.uniform1i(program.uniform.EYE_INDEX, view.eyeIndex);\n }\n\n for (let instance of primitive._instances) {\n if (instance._activeFrameId != this._frameId) {\n continue;\n }\n\n gl.uniformMatrix4fv(program.uniform.MODEL_MATRIX, false, instance.worldMatrix);\n\n if (primitive._indexBuffer) {\n gl.drawElements(primitive._mode, primitive._elementCount,\n primitive._indexType, primitive._indexByteOffset);\n } else {\n gl.drawArrays(primitive._mode, 0, primitive._elementCount);\n }\n }\n }\n }\n }\n\n _getRenderTexture(texture) {\n if (!texture) {\n return null;\n }\n\n let key = texture.textureKey;\n if (!key) {\n throw new Error('Texure does not have a valid key');\n }\n\n if (key in this._textureCache) {\n return this._textureCache[key];\n } else {\n let gl = this._gl;\n let textureHandle = gl.createTexture();\n\n let renderTexture = new RenderTexture(textureHandle);\n this._textureCache[key] = renderTexture;\n\n if (texture instanceof DataTexture) {\n gl.bindTexture(gl.TEXTURE_2D, textureHandle);\n gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.width, texture.height,\n 0, texture.format, texture._type, texture._data);\n this._setSamplerParameters(texture);\n renderTexture._complete = true;\n } else {\n texture.waitForComplete().then(() => {\n gl.bindTexture(gl.TEXTURE_2D, textureHandle);\n gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.format, gl.UNSIGNED_BYTE, texture.source);\n this._setSamplerParameters(texture);\n renderTexture._complete = true;\n\n if (texture instanceof VideoTexture) {\n // Once the video starts playing, set a callback to update it's\n // contents each frame.\n texture._video.addEventListener('playing', () => {\n renderTexture._activeCallback = () => {\n if (!texture._video.paused && !texture._video.waiting) {\n gl.bindTexture(gl.TEXTURE_2D, textureHandle);\n gl.texImage2D(gl.TEXTURE_2D, 0, texture.format, texture.format, gl.UNSIGNED_BYTE, texture.source);\n }\n };\n });\n }\n });\n }\n\n return renderTexture;\n }\n }\n\n _setSamplerParameters(texture) {\n let gl = this._gl;\n\n let sampler = texture.sampler;\n let powerOfTwo = isPowerOfTwo(texture.width) && isPowerOfTwo(texture.height);\n let mipmap = powerOfTwo && texture.mipmap;\n if (mipmap) {\n gl.generateMipmap(gl.TEXTURE_2D);\n }\n\n let minFilter = sampler.minFilter || (mipmap ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);\n let wrapS = sampler.wrapS || (powerOfTwo ? gl.REPEAT : gl.CLAMP_TO_EDGE);\n let wrapT = sampler.wrapT || (powerOfTwo ? gl.REPEAT : gl.CLAMP_TO_EDGE);\n\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, sampler.magFilter || gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);\n }\n\n _getProgramKey(name, defines) {\n let key = `${name}:`;\n\n for (let define in defines) {\n key += `${define}=${defines[define]},`;\n }\n\n return key;\n }\n\n _getMaterialProgram(material, renderPrimitive) {\n let materialName = material.materialName;\n let vertexSource = material.vertexSource;\n let fragmentSource = material.fragmentSource;\n\n // These should always be defined for every material\n if (materialName == null) {\n throw new Error('Material does not have a name');\n }\n if (vertexSource == null) {\n throw new Error(`Material \"${materialName}\" does not have a vertex source`);\n }\n if (fragmentSource == null) {\n throw new Error(`Material \"${materialName}\" does not have a fragment source`);\n }\n\n let defines = material.getProgramDefines(renderPrimitive);\n let key = this._getProgramKey(materialName, defines);\n\n if (key in this._programCache) {\n return this._programCache[key];\n } else {\n let multiview = false; // Handle this dynamically later\n let fullVertexSource = vertexSource;\n fullVertexSource += multiview ? VERTEX_SHADER_MULTI_ENTRY :\n VERTEX_SHADER_SINGLE_ENTRY;\n\n let precisionMatch = fragmentSource.match(PRECISION_REGEX);\n let fragPrecisionHeader = precisionMatch ? '' : `precision ${this._defaultFragPrecision} float;\\n`;\n\n let fullFragmentSource = fragPrecisionHeader + fragmentSource;\n fullFragmentSource += FRAGMENT_SHADER_ENTRY;\n\n let program = new Program(this._gl, fullVertexSource, fullFragmentSource, ATTRIB, defines);\n this._programCache[key] = program;\n\n program.onNextUse((program) => {\n // Bind the samplers to the right texture index. This is constant for\n // the lifetime of the program.\n for (let i = 0; i < material._samplers.length; ++i) {\n let sampler = material._samplers[i];\n let uniform = program.uniform[sampler._uniformName];\n if (uniform) {\n this._gl.uniform1i(uniform, i);\n }\n }\n });\n\n return program;\n }\n }\n\n _bindPrimitive(primitive, attribMask) {\n let gl = this._gl;\n\n // If the active attributes have changed then update the active set.\n if (attribMask != primitive._attributeMask) {\n for (let attrib in ATTRIB) {\n if (primitive._attributeMask & ATTRIB_MASK[attrib]) {\n gl.enableVertexAttribArray(ATTRIB[attrib]);\n } else {\n gl.disableVertexAttribArray(ATTRIB[attrib]);\n }\n }\n }\n\n // Bind the primitive attributes and indices.\n for (let attributeBuffer of primitive._attributeBuffers) {\n gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer._buffer._buffer);\n for (let attrib of attributeBuffer._attributes) {\n gl.vertexAttribPointer(\n attrib._attrib_index, attrib._componentCount, attrib._componentType,\n attrib._normalized, attrib._stride, attrib._byteOffset);\n }\n }\n\n if (primitive._indexBuffer) {\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, primitive._indexBuffer._buffer);\n } else {\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n }\n }\n\n _bindMaterialState(material, prevMaterial = null) {\n let gl = this._gl;\n\n let state = material._state;\n let prevState = prevMaterial ? prevMaterial._state : ~state;\n\n // Return early if both materials use identical state\n if (state == prevState) {\n return;\n }\n\n // Any caps bits changed?\n if (material._capsDiff(prevState)) {\n setCap(gl, gl.CULL_FACE, CAP.CULL_FACE, prevState, state);\n setCap(gl, gl.BLEND, CAP.BLEND, prevState, state);\n setCap(gl, gl.DEPTH_TEST, CAP.DEPTH_TEST, prevState, state);\n setCap(gl, gl.STENCIL_TEST, CAP.STENCIL_TEST, prevState, state);\n\n let colorMaskChange = (state & CAP.COLOR_MASK) - (prevState & CAP.COLOR_MASK);\n if (colorMaskChange) {\n let mask = colorMaskChange > 1;\n this._colorMaskNeedsReset = !mask;\n gl.colorMask(mask, mask, mask, mask);\n }\n\n let depthMaskChange = (state & CAP.DEPTH_MASK) - (prevState & CAP.DEPTH_MASK);\n if (depthMaskChange) {\n this._depthMaskNeedsReset = !(depthMaskChange > 1);\n gl.depthMask(depthMaskChange > 1);\n }\n\n let stencilMaskChange = (state & CAP.STENCIL_MASK) - (prevState & CAP.STENCIL_MASK);\n if (stencilMaskChange) {\n gl.stencilMask(stencilMaskChange > 1);\n }\n }\n\n // Blending enabled and blend func changed?\n if (material._blendDiff(prevState)) {\n gl.blendFunc(material.blendFuncSrc, material.blendFuncDst);\n }\n\n // Depth testing enabled and depth func changed?\n if (material._depthFuncDiff(prevState)) {\n gl.depthFunc(material.depthFunc);\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nconst GL = WebGLRenderingContext; // For enums\n\nexport class TextureSampler {\n constructor() {\n this.minFilter = null;\n this.magFilter = null;\n this.wrapS = null;\n this.wrapT = null;\n }\n}\n\nexport class Texture {\n constructor() {\n this.sampler = new TextureSampler();\n this.mipmap = true;\n // TODO: Anisotropy\n }\n\n get format() {\n return GL.RGBA;\n }\n\n get width() {\n return 0;\n }\n\n get height() {\n return 0;\n }\n\n get textureKey() {\n return null;\n }\n}\n\nexport class ImageTexture extends Texture {\n constructor(img) {\n super();\n\n this._img = img;\n this._imgBitmap = null;\n\n if (img.src && img.complete) {\n if (img.naturalWidth) {\n this._promise = this._finishImage();\n } else {\n this._promise = Promise.reject('Image provided had failed to load.');\n }\n } else {\n this._promise = new Promise((resolve, reject) => {\n img.addEventListener('load', () => resolve(this._finishImage()));\n img.addEventListener('error', reject);\n });\n }\n }\n\n _finishImage() {\n if (window.createImageBitmap) {\n return window.createImageBitmap(this._img).then((imgBitmap) => {\n this._imgBitmap = imgBitmap;\n return Promise.resolve(this);\n });\n }\n return Promise.resolve(this);\n }\n\n get format() {\n // TODO: Can be RGB in some cases.\n return GL.RGBA;\n }\n\n get width() {\n return this._img.width;\n }\n\n get height() {\n return this._img.height;\n }\n\n waitForComplete() {\n return this._promise;\n }\n\n get textureKey() {\n return this._img.src;\n }\n\n get source() {\n return this._imgBitmap || this._img;\n }\n}\n\nexport class UrlTexture extends ImageTexture {\n constructor(url) {\n let img = new Image();\n super(img);\n img.src = url;\n }\n}\n\nexport class BlobTexture extends ImageTexture {\n constructor(blob) {\n let img = new Image();\n super(img);\n img.src = window.URL.createObjectURL(blob);\n }\n}\n\nexport class VideoTexture extends Texture {\n constructor(video) {\n super();\n\n this._video = video;\n\n if (video.readyState >= 2) {\n this._promise = Promise.resolve(this);\n } else if (video.error) {\n this._promise = Promise.reject(video.error);\n } else {\n this._promise = new Promise((resolve, reject) => {\n video.addEventListener('loadeddata', () => resolve(this));\n video.addEventListener('error', reject);\n });\n }\n }\n\n get format() {\n // TODO: Can be RGB in some cases.\n return GL.RGBA;\n }\n\n get width() {\n return this._video.videoWidth;\n }\n\n get height() {\n return this._video.videoHeight;\n }\n\n waitForComplete() {\n return this._promise;\n }\n\n get textureKey() {\n return this._video.src;\n }\n\n get source() {\n return this._video;\n }\n}\n\nlet nextDataTextureIndex = 0;\n\nexport class DataTexture extends Texture {\n constructor(data, width, height, format = GL.RGBA, type = GL.UNSIGNED_BYTE) {\n super();\n\n this._data = data;\n this._width = width;\n this._height = height;\n this._format = format;\n this._type = type;\n this._key = `DATA_${nextDataTextureIndex}`;\n nextDataTextureIndex++;\n }\n\n get format() {\n return this._format;\n }\n\n get width() {\n return this._width;\n }\n\n get height() {\n return this._height;\n }\n\n get textureKey() {\n return this._key;\n }\n}\n\nexport class ColorTexture extends DataTexture {\n constructor(r, g, b, a) {\n let colorData = new Uint8Array([r*255.0, g*255.0, b*255.0, a*255.0]);\n super(colorData, 1, 1);\n\n this.mipmap = false;\n this._key = `COLOR_${colorData[0]}_${colorData[1]}_${colorData[2]}_${colorData[3]}`;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nexport {Node} from './core/node.js';\nexport {Renderer, createWebGLContext} from './core/renderer.js';\nexport {UrlTexture} from './core/texture.js';\n\nexport {PrimitiveStream} from './geometry/primitive-stream.js';\nexport {BoxBuilder} from './geometry/box-builder.js';\n\nexport {PbrMaterial} from './materials/pbr.js';\n\nexport {mat4, mat3, vec3, vec4, quat} from './math/gl-matrix.js';\n\nexport {BoundsRenderer} from './nodes/bounds-renderer.js';\nexport {ButtonNode} from './nodes/button.js';\nexport {DropShadowNode} from './nodes/drop-shadow.js';\nexport {CubeSeaNode} from './nodes/cube-sea.js';\nexport {Gltf2Node} from './nodes/gltf2.js';\nexport {SkyboxNode} from './nodes/skybox.js';\nexport {VideoNode} from './nodes/video.js';\n\nexport {WebXRView, Scene} from './scenes/scene.js';\n\nexport {FallbackHelper} from './util/fallback-helper.js';\nexport {QueryArgs} from './util/query-args.js';\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {GeometryBuilderBase} from './primitive-stream.js';\n\nexport class BoxBuilder extends GeometryBuilderBase {\n pushBox(min, max) {\n let stream = this.primitiveStream;\n\n let w = max[0] - min[0];\n let h = max[1] - min[1];\n let d = max[2] - min[2];\n\n let wh = w * 0.5;\n let hh = h * 0.5;\n let dh = d * 0.5;\n\n let cx = min[0] + wh;\n let cy = min[1] + hh;\n let cz = min[2] + dh;\n\n stream.startGeometry();\n\n // Bottom\n let idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+1, idx+2);\n stream.pushTriangle(idx, idx+2, idx+3);\n\n // X Y Z U V NX NY NZ\n stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, 0.0, -1.0, 0.0);\n stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 0.0, -1.0, 0.0);\n stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 1.0, 0.0, 0.0, -1.0, 0.0);\n stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 0.0, 0.0, 0.0, -1.0, 0.0);\n\n // Top\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+2, idx+1);\n stream.pushTriangle(idx, idx+3, idx+2);\n\n stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, 0.0, 1.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 0.0, 1.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 1.0, 1.0, 0.0, 1.0, 0.0);\n stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 0.0, 1.0, 0.0, 1.0, 0.0);\n\n // Left\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+2, idx+1);\n stream.pushTriangle(idx, idx+3, idx+2);\n\n stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, -1.0, 0.0, 0.0);\n stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, -1.0, 0.0, 0.0);\n stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 1.0, 0.0, -1.0, 0.0, 0.0);\n stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 1.0, 1.0, -1.0, 0.0, 0.0);\n\n // Right\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+1, idx+2);\n stream.pushTriangle(idx, idx+2, idx+3);\n\n stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 1.0, 0.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 1.0, 0.0, 0.0);\n stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 0.0, 0.0, 1.0, 0.0, 0.0);\n stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 0.0, 1.0, 1.0, 0.0, 0.0);\n\n // Back\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+2, idx+1);\n stream.pushTriangle(idx, idx+3, idx+2);\n\n stream.pushVertex(-wh+cx, -hh+cy, -dh+cz, 1.0, 1.0, 0.0, 0.0, -1.0);\n stream.pushVertex(+wh+cx, -hh+cy, -dh+cz, 0.0, 1.0, 0.0, 0.0, -1.0);\n stream.pushVertex(+wh+cx, +hh+cy, -dh+cz, 0.0, 0.0, 0.0, 0.0, -1.0);\n stream.pushVertex(-wh+cx, +hh+cy, -dh+cz, 1.0, 0.0, 0.0, 0.0, -1.0);\n\n // Front\n idx = stream.nextVertexIndex;\n stream.pushTriangle(idx, idx+1, idx+2);\n stream.pushTriangle(idx, idx+2, idx+3);\n\n stream.pushVertex(-wh+cx, -hh+cy, +dh+cz, 0.0, 1.0, 0.0, 0.0, 1.0);\n stream.pushVertex(+wh+cx, -hh+cy, +dh+cz, 1.0, 1.0, 0.0, 0.0, 1.0);\n stream.pushVertex(+wh+cx, +hh+cy, +dh+cz, 1.0, 0.0, 0.0, 0.0, 1.0);\n stream.pushVertex(-wh+cx, +hh+cy, +dh+cz, 0.0, 0.0, 0.0, 0.0, 1.0);\n\n stream.endGeometry();\n }\n\n pushCube(center = [0, 0, 0], size = 1.0) {\n let hs = size * 0.5;\n this.pushBox([center[0] - hs, center[1] - hs, center[2] - hs],\n [center[0] + hs, center[1] + hs, center[2] + hs]);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {mat3, vec3} from '../math/gl-matrix.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst tempVec3 = vec3.create();\n\nexport class PrimitiveStream {\n constructor(options) {\n this._vertices = [];\n this._indices = [];\n\n this._geometryStarted = false;\n\n this._vertexOffset = 0;\n this._vertexIndex = 0;\n this._highIndex = 0;\n\n this._flipWinding = false;\n this._invertNormals = false;\n this._transform = null;\n this._normalTransform = null;\n this._min = null;\n this._max = null;\n }\n\n set flipWinding(value) {\n if (this._geometryStarted) {\n throw new Error(`Cannot change flipWinding before ending the current geometry.`);\n }\n this._flipWinding = value;\n }\n\n get flipWinding() {\n this._flipWinding;\n }\n\n set invertNormals(value) {\n if (this._geometryStarted) {\n throw new Error(`Cannot change invertNormals before ending the current geometry.`);\n }\n this._invertNormals = value;\n }\n\n get invertNormals() {\n this._invertNormals;\n }\n\n set transform(value) {\n if (this._geometryStarted) {\n throw new Error(`Cannot change transform before ending the current geometry.`);\n }\n this._transform = value;\n if (this._transform) {\n if (!this._normalTransform) {\n this._normalTransform = mat3.create();\n }\n mat3.fromMat4(this._normalTransform, this._transform);\n }\n }\n\n get transform() {\n this._transform;\n }\n\n startGeometry() {\n if (this._geometryStarted) {\n throw new Error(`Attempted to start a new geometry before the previous one was ended.`);\n }\n\n this._geometryStarted = true;\n this._vertexIndex = 0;\n this._highIndex = 0;\n }\n\n endGeometry() {\n if (!this._geometryStarted) {\n throw new Error(`Attempted to end a geometry before one was started.`);\n }\n\n if (this._highIndex >= this._vertexIndex) {\n throw new Error(`Geometry contains indices that are out of bounds.\n (Contains an index of ${this._highIndex} when the vertex count is ${this._vertexIndex})`);\n }\n\n this._geometryStarted = false;\n this._vertexOffset += this._vertexIndex;\n\n // TODO: Anything else need to be done to finish processing here?\n }\n\n pushVertex(x, y, z, u = 0, v = 0, nx = 0, ny = 0, nz = 1) {\n if (!this._geometryStarted) {\n throw new Error(`Cannot push vertices before calling startGeometry().`);\n }\n\n // Transform the incoming vertex if we have a transformation matrix\n if (this._transform) {\n tempVec3[0] = x;\n tempVec3[1] = y;\n tempVec3[2] = z;\n vec3.transformMat4(tempVec3, tempVec3, this._transform);\n x = tempVec3[0];\n y = tempVec3[1];\n z = tempVec3[2];\n\n tempVec3[0] = nx;\n tempVec3[1] = ny;\n tempVec3[2] = nz;\n vec3.transformMat3(tempVec3, tempVec3, this._normalTransform);\n nx = tempVec3[0];\n ny = tempVec3[1];\n nz = tempVec3[2];\n }\n\n if (this._invertNormals) {\n nx *= -1.0;\n ny *= -1.0;\n nz *= -1.0;\n }\n\n this._vertices.push(x, y, z, u, v, nx, ny, nz);\n\n if (this._min) {\n this._min[0] = Math.min(this._min[0], x);\n this._min[1] = Math.min(this._min[1], y);\n this._min[2] = Math.min(this._min[2], z);\n this._max[0] = Math.max(this._max[0], x);\n this._max[1] = Math.max(this._max[1], y);\n this._max[2] = Math.max(this._max[2], z);\n } else {\n this._min = vec3.fromValues(x, y, z);\n this._max = vec3.fromValues(x, y, z);\n }\n\n return this._vertexIndex++;\n }\n\n get nextVertexIndex() {\n return this._vertexIndex;\n }\n\n pushTriangle(idxA, idxB, idxC) {\n if (!this._geometryStarted) {\n throw new Error(`Cannot push triangles before calling startGeometry().`);\n }\n\n this._highIndex = Math.max(this._highIndex, idxA, idxB, idxC);\n\n idxA += this._vertexOffset;\n idxB += this._vertexOffset;\n idxC += this._vertexOffset;\n\n if (this._flipWinding) {\n this._indices.push(idxC, idxB, idxA);\n } else {\n this._indices.push(idxA, idxB, idxC);\n }\n }\n\n clear() {\n if (this._geometryStarted) {\n throw new Error(`Cannot clear before ending the current geometry.`);\n }\n\n this._vertices = [];\n this._indices = [];\n this._vertexOffset = 0;\n this._min = null;\n this._max = null;\n }\n\n finishPrimitive(renderer) {\n if (!this._vertexOffset) {\n throw new Error(`Attempted to call finishPrimitive() before creating any geometry.`);\n }\n\n let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(this._vertices));\n let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(this._indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 32, 0),\n new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 32, 12),\n new PrimitiveAttribute('NORMAL', vertexBuffer, 3, GL.FLOAT, 32, 20),\n ];\n\n let primitive = new Primitive(attribs, this._indices.length);\n primitive.setIndexBuffer(indexBuffer);\n primitive.setBounds(this._min, this._max);\n\n return primitive;\n }\n}\n\nexport class GeometryBuilderBase {\n constructor(primitiveStream) {\n if (primitiveStream) {\n this._stream = primitiveStream;\n } else {\n this._stream = new PrimitiveStream();\n }\n }\n\n set primitiveStream(value) {\n this._stream = value;\n }\n\n get primitiveStream() {\n return this._stream;\n }\n\n finishPrimitive(renderer) {\n return this._stream.finishPrimitive(renderer);\n }\n\n clear() {\n this._stream.clear();\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {PbrMaterial} from '../materials/pbr.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {ImageTexture, ColorTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst GLB_MAGIC = 0x46546C67;\nconst CHUNK_TYPE = {\n JSON: 0x4E4F534A,\n BIN: 0x004E4942,\n};\n\nfunction isAbsoluteUri(uri) {\n let absRegEx = new RegExp('^'+window.location.protocol, 'i');\n return !!uri.match(absRegEx);\n}\n\nfunction isDataUri(uri) {\n let dataRegEx = /^data:/;\n return !!uri.match(dataRegEx);\n}\n\nfunction resolveUri(uri, baseUrl) {\n if (isAbsoluteUri(uri) || isDataUri(uri)) {\n return uri;\n }\n return baseUrl + uri;\n}\n\nfunction getComponentCount(type) {\n switch (type) {\n case 'SCALAR': return 1;\n case 'VEC2': return 2;\n case 'VEC3': return 3;\n case 'VEC4': return 4;\n default: return 0;\n }\n}\n\n/**\n * Gltf2SceneLoader\n * Loads glTF 2.0 scenes into a renderable node tree.\n */\n\nexport class Gltf2Loader {\n constructor(renderer) {\n this.renderer = renderer;\n this._gl = renderer._gl;\n }\n\n loadFromUrl(url) {\n return fetch(url)\n .then((response) => {\n let i = url.lastIndexOf('/');\n let baseUrl = (i !== 0) ? url.substring(0, i + 1) : '';\n\n if (url.endsWith('.gltf')) {\n return response.json().then((json) => {\n return this.loadFromJson(json, baseUrl);\n });\n } else if (url.endsWith('.glb')) {\n return response.arrayBuffer().then((arrayBuffer) => {\n return this.loadFromBinary(arrayBuffer, baseUrl);\n });\n } else {\n throw new Error('Unrecognized file extension');\n }\n });\n }\n\n loadFromBinary(arrayBuffer, baseUrl) {\n let headerView = new DataView(arrayBuffer, 0, 12);\n let magic = headerView.getUint32(0, true);\n let version = headerView.getUint32(4, true);\n let length = headerView.getUint32(8, true);\n\n if (magic != GLB_MAGIC) {\n throw new Error('Invalid magic string in binary header.');\n }\n\n if (version != 2) {\n throw new Error('Incompatible version in binary header.');\n }\n\n let chunks = {};\n let chunkOffset = 12;\n while (chunkOffset < length) {\n let chunkHeaderView = new DataView(arrayBuffer, chunkOffset, 8);\n let chunkLength = chunkHeaderView.getUint32(0, true);\n let chunkType = chunkHeaderView.getUint32(4, true);\n chunks[chunkType] = arrayBuffer.slice(chunkOffset + 8, chunkOffset + 8 + chunkLength);\n chunkOffset += chunkLength + 8;\n }\n\n if (!chunks[CHUNK_TYPE.JSON]) {\n throw new Error('File contained no json chunk.');\n }\n\n let decoder = new TextDecoder('utf-8');\n let jsonString = decoder.decode(chunks[CHUNK_TYPE.JSON]);\n let json = JSON.parse(jsonString);\n return this.loadFromJson(json, baseUrl, chunks[CHUNK_TYPE.BIN]);\n }\n\n loadFromJson(json, baseUrl, binaryChunk) {\n if (!json.asset) {\n throw new Error('Missing asset description.');\n }\n\n if (json.asset.minVersion != '2.0' && json.asset.version != '2.0') {\n throw new Error('Incompatible asset version.');\n }\n\n let buffers = [];\n if (binaryChunk) {\n buffers[0] = new Gltf2Resource({}, baseUrl, binaryChunk);\n } else {\n for (let buffer of json.buffers) {\n buffers.push(new Gltf2Resource(buffer, baseUrl));\n }\n }\n\n let bufferViews = [];\n for (let bufferView of json.bufferViews) {\n bufferViews.push(new Gltf2BufferView(bufferView, buffers));\n }\n\n let images = [];\n if (json.images) {\n for (let image of json.images) {\n images.push(new Gltf2Resource(image, baseUrl));\n }\n }\n\n let textures = [];\n if (json.textures) {\n for (let texture of json.textures) {\n let image = images[texture.source];\n let glTexture = image.texture(bufferViews);\n if (texture.sampler) {\n let sampler = sampler[texture.sampler];\n glTexture.sampler.minFilter = sampler.minFilter;\n glTexture.sampler.magFilter = sampler.magFilter;\n glTexture.sampler.wrapS = sampler.wrapS;\n glTexture.sampler.wrapT = sampler.wrapT;\n }\n textures.push(glTexture);\n }\n }\n\n function getTexture(textureInfo) {\n if (!textureInfo) {\n return null;\n }\n return textures[textureInfo.index];\n }\n\n let materials = [];\n if (json.materials) {\n for (let material of json.materials) {\n let glMaterial = new PbrMaterial();\n let pbr = material.pbrMetallicRoughness || {};\n\n glMaterial.baseColorFactor.value = pbr.baseColorFactor || [1, 1, 1, 1];\n glMaterial.baseColor.texture = getTexture(pbr.baseColorTexture);\n glMaterial.metallicRoughnessFactor.value = [\n pbr.metallicFactor || 1.0,\n pbr.roughnessFactor || 1.0,\n ];\n glMaterial.metallicRoughness.texture = getTexture(pbr.metallicRoughnessTexture);\n glMaterial.normal.texture = getTexture(json.normalTexture);\n glMaterial.occlusion.texture = getTexture(json.occlusionTexture);\n glMaterial.occlusionStrength.value = (json.occlusionTexture && json.occlusionTexture.strength) ?\n json.occlusionTexture.strength : 1.0;\n glMaterial.emissiveFactor.value = material.emissiveFactor || [0, 0, 0];\n glMaterial.emissive.texture = getTexture(json.emissiveTexture);\n if (!glMaterial.emissive.texture && json.emissiveFactor) {\n glMaterial.emissive.texture = new ColorTexture(1.0, 1.0, 1.0, 1.0);\n }\n\n switch (material.alphaMode) {\n case 'BLEND':\n glMaterial.state.blend = true;\n break;\n case 'MASK':\n // Not really supported.\n glMaterial.state.blend = true;\n break;\n default: // Includes 'OPAQUE'\n glMaterial.state.blend = false;\n }\n\n // glMaterial.alpha_mode = material.alphaMode;\n // glMaterial.alpha_cutoff = material.alphaCutoff;\n glMaterial.state.cullFace = !(material.doubleSided);\n\n materials.push(glMaterial);\n }\n }\n\n let accessors = json.accessors;\n\n let meshes = [];\n for (let mesh of json.meshes) {\n let glMesh = new Gltf2Mesh();\n meshes.push(glMesh);\n\n for (let primitive of mesh.primitives) {\n let material = null;\n if ('material' in primitive) {\n material = materials[primitive.material];\n } else {\n // Create a \"default\" material if the primitive has none.\n material = new PbrMaterial();\n }\n\n let attributes = [];\n let elementCount = 0;\n /* let glPrimitive = new Gltf2Primitive(primitive, material);\n glMesh.primitives.push(glPrimitive); */\n\n let min = null;\n let max = null;\n\n for (let name in primitive.attributes) {\n let accessor = accessors[primitive.attributes[name]];\n let bufferView = bufferViews[accessor.bufferView];\n elementCount = accessor.count;\n\n let glAttribute = new PrimitiveAttribute(\n name,\n bufferView.renderBuffer(this.renderer, GL.ARRAY_BUFFER),\n getComponentCount(accessor.type),\n accessor.componentType,\n bufferView.byteStride || 0,\n accessor.byteOffset || 0\n );\n glAttribute.normalized = accessor.normalized || false;\n\n if (name == 'POSITION') {\n min = accessor.min;\n max = accessor.max;\n }\n\n attributes.push(glAttribute);\n }\n\n let glPrimitive = new Primitive(attributes, elementCount, primitive.mode);\n\n if ('indices' in primitive) {\n let accessor = accessors[primitive.indices];\n let bufferView = bufferViews[accessor.bufferView];\n\n glPrimitive.setIndexBuffer(\n bufferView.renderBuffer(this.renderer, GL.ELEMENT_ARRAY_BUFFER),\n accessor.byteOffset || 0,\n accessor.componentType\n );\n glPrimitive.indexType = accessor.componentType;\n glPrimitive.indexByteOffset = accessor.byteOffset || 0;\n glPrimitive.elementCount = accessor.count;\n }\n\n if (min && max) {\n glPrimitive.setBounds(min, max);\n }\n\n // After all the attributes have been processed, get a program that is\n // appropriate for both the material and the primitive attributes.\n glMesh.primitives.push(\n this.renderer.createRenderPrimitive(glPrimitive, material));\n }\n }\n\n let sceneNode = new Node();\n let scene = json.scenes[json.scene];\n for (let nodeId of scene.nodes) {\n let node = json.nodes[nodeId];\n sceneNode.addNode(\n this.processNodes(node, json.nodes, meshes));\n }\n\n return sceneNode;\n }\n\n processNodes(node, nodes, meshes) {\n let glNode = new Node();\n glNode.name = node.name;\n\n if ('mesh' in node) {\n let mesh = meshes[node.mesh];\n for (let primitive of mesh.primitives) {\n glNode.addRenderPrimitive(primitive);\n }\n }\n\n if (node.matrix) {\n glNode.matrix = new Float32Array(node.matrix);\n } else if (node.translation || node.rotation || node.scale) {\n if (node.translation) {\n glNode.translation = new Float32Array(node.translation);\n }\n\n if (node.rotation) {\n glNode.rotation = new Float32Array(node.rotation);\n }\n\n if (node.scale) {\n glNode.scale = new Float32Array(node.scale);\n }\n }\n\n if (node.children) {\n for (let nodeId of node.children) {\n let node = nodes[nodeId];\n glNode.addNode(this.processNodes(node, nodes, meshes));\n }\n }\n\n return glNode;\n }\n}\n\nclass Gltf2Mesh {\n constructor() {\n this.primitives = [];\n }\n}\n\nclass Gltf2BufferView {\n constructor(json, buffers) {\n this.buffer = buffers[json.buffer];\n this.byteOffset = json.byteOffset || 0;\n this.byteLength = json.byteLength || null;\n this.byteStride = json.byteStride;\n\n this._viewPromise = null;\n this._renderBuffer = null;\n }\n\n dataView() {\n if (!this._viewPromise) {\n this._viewPromise = this.buffer.arrayBuffer().then((arrayBuffer) => {\n return new DataView(arrayBuffer, this.byteOffset, this.byteLength);\n });\n }\n return this._viewPromise;\n }\n\n renderBuffer(renderer, target) {\n if (!this._renderBuffer) {\n this._renderBuffer = renderer.createRenderBuffer(target, this.dataView());\n }\n return this._renderBuffer;\n }\n}\n\nclass Gltf2Resource {\n constructor(json, baseUrl, arrayBuffer) {\n this.json = json;\n this.baseUrl = baseUrl;\n\n this._dataPromise = null;\n this._texture = null;\n if (arrayBuffer) {\n this._dataPromise = Promise.resolve(arrayBuffer);\n }\n }\n\n arrayBuffer() {\n if (!this._dataPromise) {\n if (isDataUri(this.json.uri)) {\n let base64String = this.json.uri.replace('data:application/octet-stream;base64,', '');\n let binaryArray = Uint8Array.from(atob(base64String), (c) => c.charCodeAt(0));\n this._dataPromise = Promise.resolve(binaryArray.buffer);\n return this._dataPromise;\n }\n\n this._dataPromise = fetch(resolveUri(this.json.uri, this.baseUrl))\n .then((response) => response.arrayBuffer());\n }\n return this._dataPromise;\n }\n\n texture(bufferViews) {\n if (!this._texture) {\n let img = new Image();\n this._texture = new ImageTexture(img);\n\n if (this.json.uri) {\n if (isDataUri(this.json.uri)) {\n img.src = this.json.uri;\n } else {\n img.src = `${this.baseUrl}${this.json.uri}`;\n }\n } else {\n let view = bufferViews[this.json.bufferView];\n view.dataView().then((dataView) => {\n let blob = new Blob([dataView], {type: this.json.mimeType});\n img.src = window.URL.createObjectURL(blob);\n });\n }\n }\n return this._texture;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {ATTRIB_MASK} from '../core/renderer.js';\n\nconst VERTEX_SOURCE = `\nattribute vec3 POSITION, NORMAL;\nattribute vec2 TEXCOORD_0, TEXCOORD_1;\n\nuniform vec3 CAMERA_POSITION;\nuniform vec3 LIGHT_DIRECTION;\n\nvarying vec3 vLight; // Vector from vertex to light.\nvarying vec3 vView; // Vector from vertex to camera.\nvarying vec2 vTex;\n\n#ifdef USE_NORMAL_MAP\nattribute vec4 TANGENT;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_VERTEX_COLOR\nattribute vec4 COLOR_0;\nvarying vec4 vCol;\n#endif\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 n = normalize(vec3(model * vec4(NORMAL, 0.0)));\n#ifdef USE_NORMAL_MAP\n vec3 t = normalize(vec3(model * vec4(TANGENT.xyz, 0.0)));\n vec3 b = cross(n, t) * TANGENT.w;\n vTBN = mat3(t, b, n);\n#else\n vNorm = n;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n vCol = COLOR_0;\n#endif\n\n vTex = TEXCOORD_0;\n vec4 mPos = model * vec4(POSITION, 1.0);\n vLight = -LIGHT_DIRECTION;\n vView = CAMERA_POSITION - mPos.xyz;\n return proj * view * mPos;\n}`;\n\n// These equations are borrowed with love from this docs from Epic because I\n// just don't have anything novel to bring to the PBR scene.\n// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf\nconst EPIC_PBR_FUNCTIONS = `\nvec3 lambertDiffuse(vec3 cDiff) {\n return cDiff / M_PI;\n}\n\nfloat specD(float a, float nDotH) {\n float aSqr = a * a;\n float f = ((nDotH * nDotH) * (aSqr - 1.0) + 1.0);\n return aSqr / (M_PI * f * f);\n}\n\nfloat specG(float roughness, float nDotL, float nDotV) {\n float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n float gl = nDotL / (nDotL * (1.0 - k) + k);\n float gv = nDotV / (nDotV * (1.0 - k) + k);\n return gl * gv;\n}\n\nvec3 specF(float vDotH, vec3 F0) {\n float exponent = (-5.55473 * vDotH - 6.98316) * vDotH;\n float base = 2.0;\n return F0 + (1.0 - F0) * pow(base, exponent);\n}`;\n\nconst FRAGMENT_SOURCE = `\n#define M_PI 3.14159265\n\nuniform vec4 baseColorFactor;\n#ifdef USE_BASE_COLOR_MAP\nuniform sampler2D baseColorTex;\n#endif\n\nvarying vec3 vLight;\nvarying vec3 vView;\nvarying vec2 vTex;\n\n#ifdef USE_VERTEX_COLOR\nvarying vec4 vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\nuniform sampler2D normalTex;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_METAL_ROUGH_MAP\nuniform sampler2D metallicRoughnessTex;\n#endif\nuniform vec2 metallicRoughnessFactor;\n\n#ifdef USE_OCCLUSION\nuniform sampler2D occlusionTex;\nuniform float occlusionStrength;\n#endif\n\n#ifdef USE_EMISSIVE_TEXTURE\nuniform sampler2D emissiveTex;\n#endif\nuniform vec3 emissiveFactor;\n\nuniform vec3 LIGHT_COLOR;\n\nconst vec3 dielectricSpec = vec3(0.04);\nconst vec3 black = vec3(0.0);\n\n${EPIC_PBR_FUNCTIONS}\n\nvec4 fragment_main() {\n#ifdef USE_BASE_COLOR_MAP\n vec4 baseColor = texture2D(baseColorTex, vTex) * baseColorFactor;\n#else\n vec4 baseColor = baseColorFactor;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n baseColor *= vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\n vec3 n = texture2D(normalTex, vTex).rgb;\n n = normalize(vTBN * (2.0 * n - 1.0));\n#else\n vec3 n = normalize(vNorm);\n#endif\n\n#ifdef FULLY_ROUGH\n float metallic = 0.0;\n#else\n float metallic = metallicRoughnessFactor.x;\n#endif\n\n float roughness = metallicRoughnessFactor.y;\n\n#ifdef USE_METAL_ROUGH_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessTex, vTex);\n metallic *= metallicRoughness.b;\n roughness *= metallicRoughness.g;\n#endif\n \n vec3 l = normalize(vLight);\n vec3 v = normalize(vView);\n vec3 h = normalize(l+v);\n\n float nDotL = clamp(dot(n, l), 0.001, 1.0);\n float nDotV = abs(dot(n, v)) + 0.001;\n float nDotH = max(dot(n, h), 0.0);\n float vDotH = max(dot(v, h), 0.0);\n\n // From GLTF Spec\n vec3 cDiff = mix(baseColor.rgb * (1.0 - dielectricSpec.r), black, metallic); // Diffuse color\n vec3 F0 = mix(dielectricSpec, baseColor.rgb, metallic); // Specular color\n float a = roughness * roughness;\n\n#ifdef FULLY_ROUGH\n vec3 specular = F0 * 0.45;\n#else\n vec3 F = specF(vDotH, F0);\n float D = specD(a, nDotH);\n float G = specG(roughness, nDotL, nDotV);\n vec3 specular = (D * F * G) / (4.0 * nDotL * nDotV);\n#endif\n float halfLambert = dot(n, l) * 0.5 + 0.5;\n halfLambert *= halfLambert;\n\n vec3 color = (halfLambert * LIGHT_COLOR * lambertDiffuse(cDiff)) + specular;\n\n#ifdef USE_OCCLUSION\n float occlusion = texture2D(occlusionTex, vTex).r;\n color = mix(color, color * occlusion, occlusionStrength);\n#endif\n \n vec3 emissive = emissiveFactor;\n#ifdef USE_EMISSIVE_TEXTURE\n emissive *= texture2D(emissiveTex, vTex).rgb;\n#endif\n color += emissive;\n\n // gamma correction\n //color = pow(color, vec3(1.0/2.2));\n\n return vec4(color, baseColor.a);\n}`;\n\nexport class PbrMaterial extends Material {\n constructor() {\n super();\n\n this.baseColor = this.defineSampler('baseColorTex');\n this.metallicRoughness = this.defineSampler('metallicRoughnessTex');\n this.normal = this.defineSampler('normalTex');\n this.occlusion = this.defineSampler('occlusionTex');\n this.emissive = this.defineSampler('emissiveTex');\n\n this.baseColorFactor = this.defineUniform('baseColorFactor', [1.0, 1.0, 1.0, 1.0]);\n this.metallicRoughnessFactor = this.defineUniform('metallicRoughnessFactor', [1.0, 1.0]);\n this.occlusionStrength = this.defineUniform('occlusionStrength', 1.0);\n this.emissiveFactor = this.defineUniform('emissiveFactor', [0, 0, 0]);\n }\n\n get materialName() {\n return 'PBR';\n }\n\n get vertexSource() {\n return VERTEX_SOURCE;\n }\n\n get fragmentSource() {\n return FRAGMENT_SOURCE;\n }\n\n getProgramDefines(renderPrimitive) {\n let programDefines = {};\n\n if (renderPrimitive._attributeMask & ATTRIB_MASK.COLOR_0) {\n programDefines['USE_VERTEX_COLOR'] = 1;\n }\n\n if (renderPrimitive._attributeMask & ATTRIB_MASK.TEXCOORD_0) {\n if (this.baseColor.texture) {\n programDefines['USE_BASE_COLOR_MAP'] = 1;\n }\n\n if (this.normal.texture && (renderPrimitive._attributeMask & ATTRIB_MASK.TANGENT)) {\n programDefines['USE_NORMAL_MAP'] = 1;\n }\n\n if (this.metallicRoughness.texture) {\n programDefines['USE_METAL_ROUGH_MAP'] = 1;\n }\n\n if (this.occlusion.texture) {\n programDefines['USE_OCCLUSION'] = 1;\n }\n\n if (this.emissive.texture) {\n programDefines['USE_EMISSIVE_TEXTURE'] = 1;\n }\n }\n\n if ((!this.metallicRoughness.texture ||\n !(renderPrimitive._attributeMask & ATTRIB_MASK.TEXCOORD_0)) &&\n this.metallicRoughnessFactor.value[1] == 1.0) {\n programDefines['FULLY_ROUGH'] = 1;\n }\n\n return programDefines;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport * as glMatrix from '../../node_modules/gl-matrix/src/gl-matrix/common.js';\nimport * as mat2 from '../../node_modules/gl-matrix/src/gl-matrix/mat2.js';\nimport * as mat2d from '../../node_modules/gl-matrix/src/gl-matrix/mat2d.js';\nimport * as mat3 from '../../node_modules/gl-matrix/src/gl-matrix/mat3.js';\nimport * as mat4 from '../../node_modules/gl-matrix/src/gl-matrix/mat4.js';\nimport * as quat from '../../node_modules/gl-matrix/src/gl-matrix/quat.js';\nimport * as quat2 from '../../node_modules/gl-matrix/src/gl-matrix/quat2.js';\nimport * as vec2 from '../../node_modules/gl-matrix/src/gl-matrix/vec2.js';\nimport * as vec3 from '../../node_modules/gl-matrix/src/gl-matrix/vec3.js';\nimport * as vec4 from '../../node_modules/gl-matrix/src/gl-matrix/vec4.js';\n\nexport {\n glMatrix,\n mat2,\n mat2d,\n mat3,\n mat4,\n quat,\n quat2,\n vec2,\n vec3,\n vec4,\n};\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {mat3, vec3} from './gl-matrix.js';\n\nlet normalMat = mat3.create();\n\nconst RAY_INTERSECTION_OFFSET = 0.02;\n\nexport class Ray {\n constructor(matrix = null) {\n this.origin = vec3.create();\n\n this._dir = vec3.create();\n this._dir[2] = -1.0;\n\n if (matrix) {\n vec3.transformMat4(this.origin, this.origin, matrix);\n mat3.fromMat4(normalMat, matrix);\n vec3.transformMat3(this._dir, this._dir, normalMat);\n }\n\n // To force the inverse and sign calculations.\n this.dir = this._dir;\n }\n\n get dir() {\n return this._dir;\n }\n\n set dir(value) {\n this._dir = vec3.copy(this._dir, value);\n vec3.normalize(this._dir, this._dir);\n\n this.inv_dir = vec3.fromValues(\n 1.0 / this._dir[0],\n 1.0 / this._dir[1],\n 1.0 / this._dir[2]);\n\n this.sign = [\n (this.inv_dir[0] < 0) ? 1 : 0,\n (this.inv_dir[1] < 0) ? 1 : 0,\n (this.inv_dir[2] < 0) ? 1 : 0,\n ];\n }\n\n // Borrowed from:\n // eslint-disable-next-line max-len\n // https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection\n intersectsAABB(min, max) {\n let r = this;\n\n let bounds = [min, max];\n\n let tmin = (bounds[r.sign[0]][0] - r.origin[0]) * r.inv_dir[0];\n let tmax = (bounds[1-r.sign[0]][0] - r.origin[0]) * r.inv_dir[0];\n let tymin = (bounds[r.sign[1]][1] - r.origin[1]) * r.inv_dir[1];\n let tymax = (bounds[1-r.sign[1]][1] - r.origin[1]) * r.inv_dir[1];\n\n if ((tmin > tymax) || (tymin > tmax)) {\n return null;\n }\n if (tymin > tmin) {\n tmin = tymin;\n }\n if (tymax < tmax) {\n tmax = tymax;\n }\n\n let tzmin = (bounds[r.sign[2]][2] - r.origin[2]) * r.inv_dir[2];\n let tzmax = (bounds[1-r.sign[2]][2] - r.origin[2]) * r.inv_dir[2];\n\n if ((tmin > tzmax) || (tzmin > tmax)) {\n return null;\n }\n if (tzmin > tmin) {\n tmin = tzmin;\n }\n if (tzmax < tmax) {\n tmax = tzmax;\n }\n\n let t = -1;\n if (tmin > 0 && tmax > 0) {\n t = Math.min(tmin, tmax);\n } else if (tmin > 0) {\n t = tmin;\n } else if (tmax > 0) {\n t = tmax;\n } else {\n // Intersection is behind the ray origin.\n return null;\n }\n\n // Push ray intersection point back along the ray a bit so that cursors\n // don't accidentally intersect with the hit surface.\n t -= RAY_INTERSECTION_OFFSET;\n\n // Return the point where the ray first intersected with the AABB.\n let intersectionPoint = vec3.clone(this._dir);\n vec3.scale(intersectionPoint, intersectionPoint, t);\n vec3.add(intersectionPoint, intersectionPoint, this.origin);\n return intersectionPoint;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nThis file renders a passed in XRStageBounds object and attempts\nto render geometry on the floor to indicate where the bounds is.\nXRStageBounds' `geometry` is a series of XRStageBoundsPoints (in\nclockwise-order) with `x` and `z` properties for each.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nclass BoundsMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n this.state.blendFuncSrc = GL.SRC_ALPHA;\n this.state.blendFuncDst = GL.ONE;\n this.state.depthTest = false;\n }\n\n get materialName() {\n return 'BOUNDS_RENDERER';\n }\n\n get vertexSource() {\n return `\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n\n vec4 fragment_main() {\n return vec4(0.0, 1.0, 0.0, 0.3);\n }`;\n }\n}\n\nexport class BoundsRenderer extends Node {\n constructor() {\n super();\n\n this._stageBounds = null;\n }\n\n onRendererChanged(renderer) {\n this.stageBounds = this._stageBounds;\n }\n\n get stageBounds() {\n return this._stageBounds;\n }\n\n set stageBounds(stageBounds) {\n if (this._stageBounds) {\n this.clearRenderPrimitives();\n }\n this._stageBounds = stageBounds;\n if (!stageBounds || stageBounds.length === 0 || !this._renderer) {\n return;\n }\n\n let verts = [];\n let indices = [];\n\n // Tessellate the bounding points from XRStageBounds and connect\n // each point to a neighbor and 0,0,0.\n const pointCount = stageBounds.geometry.length;\n for (let i = 0; i < pointCount; i++) {\n const point = stageBounds.geometry[i];\n verts.push(point.x, 0, point.z);\n indices.push(i, i === 0 ? pointCount - 1 : i - 1, pointCount);\n }\n // Center point\n verts.push(0, 0, 0);\n\n let vertexBuffer = this._renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(verts));\n let indexBuffer = this._renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 12, 0),\n ];\n\n let primitive = new Primitive(attribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n\n let renderPrimitive = this._renderer.createRenderPrimitive(primitive, new BoundsMaterial());\n this.addRenderPrimitive(renderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {PrimitiveStream} from '../geometry/primitive-stream.js';\n\nconst BUTTON_SIZE = 0.1;\nconst BUTTON_CORNER_RADIUS = 0.025;\nconst BUTTON_CORNER_SEGMENTS = 8;\nconst BUTTON_ICON_SIZE = 0.07;\nconst BUTTON_LAYER_DISTANCE = 0.005;\nconst BUTTON_COLOR = 0.75;\nconst BUTTON_ALPHA = 0.85;\nconst BUTTON_HOVER_COLOR = 0.9;\nconst BUTTON_HOVER_ALPHA = 1.0;\nconst BUTTON_HOVER_SCALE = 1.1;\nconst BUTTON_HOVER_TRANSITION_TIME_MS = 200;\n\nclass ButtonMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n\n this.defineUniform('hoverAmount', 0);\n }\n\n get materialName() {\n return 'BUTTON_MATERIAL';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n\n uniform float hoverAmount;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n float scale = mix(1.0, ${BUTTON_HOVER_SCALE}, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform float hoverAmount;\n\n const vec4 default_color = vec4(${BUTTON_COLOR}, ${BUTTON_COLOR}, ${BUTTON_COLOR}, ${BUTTON_ALPHA});\n const vec4 hover_color = vec4(${BUTTON_HOVER_COLOR}, ${BUTTON_HOVER_COLOR},\n ${BUTTON_HOVER_COLOR}, ${BUTTON_HOVER_ALPHA});\n\n vec4 fragment_main() {\n return mix(default_color, hover_color, hoverAmount);\n }`;\n }\n}\n\nclass ButtonIconMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n\n this.defineUniform('hoverAmount', 0);\n this.icon = this.defineSampler('icon');\n }\n\n get materialName() {\n return 'BUTTON_ICON_MATERIAL';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n uniform float hoverAmount;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n float scale = mix(1.0, ${BUTTON_HOVER_SCALE}, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform sampler2D icon;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(icon, vTexCoord);\n }`;\n }\n}\n\nexport class ButtonNode extends Node {\n constructor(iconTexture, callback) {\n super();\n\n // All buttons are selectable by default.\n this.selectable = true;\n\n this._selectHandler = callback;\n this._iconTexture = iconTexture;\n this._hovered = false;\n this._hoverT = 0;\n }\n\n get iconTexture() {\n return this._iconTexture;\n }\n\n set iconTexture(value) {\n if (this._iconTexture == value) {\n return;\n }\n\n this._iconTexture = value;\n this._iconRenderPrimitive.samplers.icon.texture = value;\n }\n\n onRendererChanged(renderer) {\n let stream = new PrimitiveStream();\n\n let hd = BUTTON_LAYER_DISTANCE * 0.5;\n\n // Build a rounded rect for the background.\n let hs = BUTTON_SIZE * 0.5;\n let ihs = hs - BUTTON_CORNER_RADIUS;\n stream.startGeometry();\n\n // Rounded corners and sides\n let segments = BUTTON_CORNER_SEGMENTS * 4;\n for (let i = 0; i < segments; ++i) {\n let rad = i * ((Math.PI * 2.0) / segments);\n let x = Math.cos(rad) * BUTTON_CORNER_RADIUS;\n let y = Math.sin(rad) * BUTTON_CORNER_RADIUS;\n let section = Math.floor(i / BUTTON_CORNER_SEGMENTS);\n switch (section) {\n case 0:\n x += ihs;\n y += ihs;\n break;\n case 1:\n x -= ihs;\n y += ihs;\n break;\n case 2:\n x -= ihs;\n y -= ihs;\n break;\n case 3:\n x += ihs;\n y -= ihs;\n break;\n }\n\n stream.pushVertex(x, y, -hd, 0, 0, 0, 0, 1);\n\n if (i > 1) {\n stream.pushTriangle(0, i-1, i);\n }\n }\n\n stream.endGeometry();\n\n let buttonPrimitive = stream.finishPrimitive(renderer);\n this._buttonRenderPrimitive = renderer.createRenderPrimitive(buttonPrimitive, new ButtonMaterial());\n this.addRenderPrimitive(this._buttonRenderPrimitive);\n\n // Build a simple textured quad for the foreground.\n hs = BUTTON_ICON_SIZE * 0.5;\n stream.clear();\n stream.startGeometry();\n\n stream.pushVertex(-hs, hs, hd, 0, 0, 0, 0, 1);\n stream.pushVertex(-hs, -hs, hd, 0, 1, 0, 0, 1);\n stream.pushVertex(hs, -hs, hd, 1, 1, 0, 0, 1);\n stream.pushVertex(hs, hs, hd, 1, 0, 0, 0, 1);\n\n stream.pushTriangle(0, 1, 2);\n stream.pushTriangle(0, 2, 3);\n\n stream.endGeometry();\n\n let iconPrimitive = stream.finishPrimitive(renderer);\n let iconMaterial = new ButtonIconMaterial();\n iconMaterial.icon.texture = this._iconTexture;\n this._iconRenderPrimitive = renderer.createRenderPrimitive(iconPrimitive, iconMaterial);\n this.addRenderPrimitive(this._iconRenderPrimitive);\n }\n\n onHoverStart() {\n this._hovered = true;\n }\n\n onHoverEnd() {\n this._hovered = false;\n }\n\n _updateHoverState() {\n let t = this._hoverT / BUTTON_HOVER_TRANSITION_TIME_MS;\n // Cubic Ease In/Out\n // TODO: Get a better animation system\n let hoverAmount = t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1;\n this._buttonRenderPrimitive.uniforms.hoverAmount.value = hoverAmount;\n this._iconRenderPrimitive.uniforms.hoverAmount.value = hoverAmount;\n }\n\n onUpdate(timestamp, frameDelta) {\n if (this._hovered && this._hoverT < BUTTON_HOVER_TRANSITION_TIME_MS) {\n this._hoverT = Math.min(BUTTON_HOVER_TRANSITION_TIME_MS, this._hoverT + frameDelta);\n this._updateHoverState();\n } else if (!this._hovered && this._hoverT > 0) {\n this._hoverT = Math.max(0.0, this._hoverT - frameDelta);\n this._updateHoverState();\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {UrlTexture} from '../core/texture.js';\nimport {BoxBuilder} from '../geometry/box-builder.js';\nimport {mat4} from '../math/gl-matrix.js';\n\nclass CubeSeaMaterial extends Material {\n constructor(heavy = false) {\n super();\n\n this.heavy = heavy;\n\n this.baseColor = this.defineSampler('baseColor');\n }\n\n get materialName() {\n return 'CUBE_SEA';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n attribute vec3 NORMAL;\n\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n const vec3 lightDir = vec3(0.75, 0.5, 1.0);\n const vec3 ambientColor = vec3(0.5, 0.5, 0.5);\n const vec3 lightColor = vec3(0.75, 0.75, 0.75);\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 normalRotated = vec3(model * vec4(NORMAL, 0.0));\n float lightFactor = max(dot(normalize(lightDir), normalRotated), 0.0);\n vLight = ambientColor + (lightColor * lightFactor);\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n if (!this.heavy) {\n return `\n precision mediump float;\n uniform sampler2D baseColor;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec4 fragment_main() {\n return vec4(vLight, 1.0) * texture2D(baseColor, vTexCoord);\n }`;\n } else {\n // Used when we want to stress the GPU a bit more.\n // Stolen with love from https://www.clicktorelease.com/code/codevember-2016/4/\n return `\n precision mediump float;\n\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec2 dimensions = vec2(64, 64);\n float seed = 0.42;\n\n vec2 hash( vec2 p ) {\n p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3)));\n return fract(sin(p)*18.5453);\n }\n\n vec3 hash3( vec2 p ) {\n vec3 q = vec3( dot(p,vec2(127.1,311.7)),\n dot(p,vec2(269.5,183.3)),\n dot(p,vec2(419.2,371.9)) );\n return fract(sin(q)*43758.5453);\n }\n\n float iqnoise( in vec2 x, float u, float v ) {\n vec2 p = floor(x);\n vec2 f = fract(x);\n float k = 1.0+63.0*pow(1.0-v,4.0);\n float va = 0.0;\n float wt = 0.0;\n for( int j=-2; j<=2; j++ )\n for( int i=-2; i<=2; i++ ) {\n vec2 g = vec2( float(i),float(j) );\n vec3 o = hash3( p + g )*vec3(u,u,1.0);\n vec2 r = g - f + o.xy;\n float d = dot(r,r);\n float ww = pow( 1.0-smoothstep(0.0,1.414,sqrt(d)), k );\n va += o.z*ww;\n wt += ww;\n }\n return va/wt;\n }\n\n // return distance, and cell id\n vec2 voronoi( in vec2 x ) {\n vec2 n = floor( x );\n vec2 f = fract( x );\n vec3 m = vec3( 8.0 );\n for( int j=-1; j<=1; j++ )\n for( int i=-1; i<=1; i++ ) {\n vec2 g = vec2( float(i), float(j) );\n vec2 o = hash( n + g );\n vec2 r = g - f + (0.5+0.5*sin(seed+6.2831*o));\n float d = dot( r, r );\n if( d<m.x )\n m = vec3( d, o );\n }\n return vec2( sqrt(m.x), m.y+m.z );\n }\n\n vec4 fragment_main() {\n vec2 uv = ( vTexCoord );\n uv *= vec2( 10., 10. );\n uv += seed;\n vec2 p = 0.5 - 0.5*sin( 0.*vec2(1.01,1.71) );\n\n vec2 c = voronoi( uv );\n vec3 col = vec3( c.y / 2. );\n\n float f = iqnoise( 1. * uv + c.y, p.x, p.y );\n col *= 1.0 + .25 * vec3( f );\n\n return vec4(vLight, 1.0) * texture2D(diffuse, vTexCoord) * vec4( col, 1. );\n }`;\n }\n }\n}\n\nexport class CubeSeaNode extends Node {\n constructor(options = {}) {\n super();\n\n // Test variables\n // If true, use a very heavyweight shader to stress the GPU.\n this.heavyGpu = !!options.heavyGpu;\n\n // Number and size of the static cubes. Warning, large values\n // don't render right due to overflow of the int16 indices.\n this.cubeCount = options.cubeCount || (this.heavyGpu ? 12 : 10);\n this.cubeScale = options.cubeScale || 1.0;\n\n // Draw only half the world cubes. Helps test variable render cost\n // when combined with heavyGpu.\n this.halfOnly = !!options.halfOnly;\n\n // Automatically spin the world cubes. Intended for automated testing,\n // not recommended for viewing in a headset.\n this.autoRotate = !!options.autoRotate;\n\n this._texture = new UrlTexture(options.imageUrl || 'media/textures/cube-sea.png');\n\n this._material = new CubeSeaMaterial(this.heavyGpu);\n this._material.baseColor.texture = this._texture;\n\n this._renderPrimitive = null;\n }\n\n onRendererChanged(renderer) {\n this._renderPrimitive = null;\n\n let boxBuilder = new BoxBuilder();\n\n // Build the spinning \"hero\" cubes\n boxBuilder.pushCube([0, 0.25, -0.8], 0.1);\n boxBuilder.pushCube([0.8, 0.25, 0], 0.1);\n boxBuilder.pushCube([0, 0.25, 0.8], 0.1);\n boxBuilder.pushCube([-0.8, 0.25, 0], 0.1);\n\n let heroPrimitive = boxBuilder.finishPrimitive(renderer);\n\n this.heroNode = renderer.createMesh(heroPrimitive, this._material);\n\n this.rebuildCubes(boxBuilder);\n\n this.cubeSeaNode = new Node();\n this.cubeSeaNode.addRenderPrimitive(this._renderPrimitive);\n\n this.addNode(this.cubeSeaNode);\n this.addNode(this.heroNode);\n\n return this.waitForComplete();\n }\n\n rebuildCubes(boxBuilder) {\n if (!this._renderer) {\n return;\n }\n\n if (!boxBuilder) {\n boxBuilder = new BoxBuilder();\n } else {\n boxBuilder.clear();\n }\n\n let size = 0.4 * this.cubeScale;\n\n // Build the cube sea\n let halfGrid = this.cubeCount * 0.5;\n for (let x = 0; x < this.cubeCount; ++x) {\n for (let y = 0; y < this.cubeCount; ++y) {\n for (let z = 0; z < this.cubeCount; ++z) {\n let pos = [x - halfGrid, y - halfGrid, z - halfGrid];\n // Only draw cubes on one side. Useful for testing variable render\n // cost that depends on view direction.\n if (this.halfOnly && pos[0] < 0) {\n continue;\n }\n\n // Don't place a cube in the center of the grid.\n if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0) {\n continue;\n }\n\n boxBuilder.pushCube(pos, size);\n }\n }\n }\n\n if (this.cubeCount > 12) {\n // Each cube has 6 sides with 2 triangles and 3 indices per triangle, so\n // the total number of indices needed is cubeCount^3 * 36. This exceeds\n // the short index range past 12 cubes.\n boxBuilder.indexType = 5125; // gl.UNSIGNED_INT\n }\n let cubeSeaPrimitive = boxBuilder.finishPrimitive(this._renderer);\n\n if (!this._renderPrimitive) {\n this._renderPrimitive = this._renderer.createRenderPrimitive(cubeSeaPrimitive, this._material);\n } else {\n this._renderPrimitive.setPrimitive(cubeSeaPrimitive);\n }\n }\n\n onUpdate(timestamp, frameDelta) {\n if (this.autoRotate) {\n mat4.fromRotation(this.cubeSeaNode.matrix, timestamp / 500, [0, -1, 0]);\n }\n mat4.fromRotation(this.heroNode.matrix, timestamp / 2000, [0, 1, 0]);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {PrimitiveStream} from '../geometry/primitive-stream.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nconst SHADOW_SEGMENTS = 32;\nconst SHADOW_GROUND_OFFSET = 0.01;\nconst SHADOW_CENTER_ALPHA = 0.7;\nconst SHADOW_INNER_ALPHA = 0.3;\nconst SHADOW_OUTER_ALPHA = 0.0;\nconst SHADOW_INNER_RADIUS = 0.6;\nconst SHADOW_OUTER_RADIUS = 1.0;\n\nclass DropShadowMaterial extends Material {\n constructor() {\n super();\n\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.blendFuncDst = GL.ONE_MINUS_SRC_ALPHA;\n this.state.depthFunc = GL.LEQUAL;\n this.state.depthMask = false;\n }\n\n get materialName() {\n return 'DROP_SHADOW_MATERIAL';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying float vShadow;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vShadow = TEXCOORD_0.x;\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n varying float vShadow;\n\n vec4 fragment_main() {\n return vec4(0.0, 0.0, 0.0, vShadow);\n }`;\n }\n}\n\nexport class DropShadowNode extends Node {\n constructor(iconTexture, callback) {\n super();\n }\n\n onRendererChanged(renderer) {\n let stream = new PrimitiveStream();\n\n stream.startGeometry();\n\n // Shadow center\n stream.pushVertex(0, SHADOW_GROUND_OFFSET, 0, SHADOW_CENTER_ALPHA);\n\n let segRad = ((Math.PI * 2.0) / SHADOW_SEGMENTS);\n\n let idx;\n for (let i = 0; i < SHADOW_SEGMENTS; ++i) {\n idx = stream.nextVertexIndex;\n\n let rad = i * segRad;\n let x = Math.cos(rad);\n let y = Math.sin(rad);\n stream.pushVertex(x * SHADOW_INNER_RADIUS, SHADOW_GROUND_OFFSET, y * SHADOW_INNER_RADIUS, SHADOW_INNER_ALPHA);\n stream.pushVertex(x * SHADOW_OUTER_RADIUS, SHADOW_GROUND_OFFSET, y * SHADOW_OUTER_RADIUS, SHADOW_OUTER_ALPHA);\n\n if (i > 0) {\n // Inner circle\n stream.pushTriangle(0, idx, idx-2);\n\n // Outer circle\n stream.pushTriangle(idx, idx+1, idx-1);\n stream.pushTriangle(idx, idx-1, idx-2);\n }\n }\n\n stream.pushTriangle(0, 1, idx);\n\n stream.pushTriangle(1, 2, idx+1);\n stream.pushTriangle(1, idx+1, idx);\n\n stream.endGeometry();\n\n let shadowPrimitive = stream.finishPrimitive(renderer);\n this._shadowRenderPrimitive = renderer.createRenderPrimitive(shadowPrimitive, new DropShadowMaterial());\n this.addRenderPrimitive(this._shadowRenderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Node} from '../core/node.js';\nimport {Gltf2Loader} from '../loaders/gltf2.js';\n\n// Using a weak map here allows us to cache a loader per-renderer without\n// modifying the renderer object or leaking memory when it's garbage collected.\nlet gltfLoaderMap = new WeakMap();\n\nexport class Gltf2Node extends Node {\n constructor(options) {\n super();\n this._url = options.url;\n\n this._promise = null;\n this._resolver = null;\n this._rejecter = null;\n }\n\n onRendererChanged(renderer) {\n let loader = gltfLoaderMap.get(renderer);\n if (!loader) {\n loader = new Gltf2Loader(renderer);\n gltfLoaderMap.set(renderer, loader);\n }\n\n // Do we have a previously resolved promise? If so clear it.\n if (!this._resolver && this._promise) {\n this._promise = null;\n }\n\n this._ensurePromise();\n\n loader.loadFromUrl(this._url).then((sceneNode) => {\n this.addNode(sceneNode);\n this._resolver(sceneNode.waitForComplete());\n this._resolver = null;\n this._rejecter = null;\n }).catch((err) => {\n this._rejecter(err);\n this._resolver = null;\n this._rejecter = null;\n });\n }\n\n _ensurePromise() {\n if (!this._promise) {\n this._promise = new Promise((resolve, reject) => {\n this._resolver = resolve;\n this._rejecter = reject;\n });\n }\n return this._promise;\n }\n\n waitForComplete() {\n return this._ensurePromise();\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {Material, RENDER_ORDER} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {DataTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\n// Laser texture data, 48x1 RGBA (not premultiplied alpha). This represents a\n// \"cross section\" of the laser beam with a bright core and a feathered edge.\n// Borrowed from Chromium source code.\nconst LASER_TEXTURE_DATA = new Uint8Array([\n0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x02, 0xbf, 0xbf, 0xbf, 0x04, 0xcc, 0xcc, 0xcc, 0x05,\n0xdb, 0xdb, 0xdb, 0x07, 0xcc, 0xcc, 0xcc, 0x0a, 0xd8, 0xd8, 0xd8, 0x0d, 0xd2, 0xd2, 0xd2, 0x11,\n0xce, 0xce, 0xce, 0x15, 0xce, 0xce, 0xce, 0x1a, 0xce, 0xce, 0xce, 0x1f, 0xcd, 0xcd, 0xcd, 0x24,\n0xc8, 0xc8, 0xc8, 0x2a, 0xc9, 0xc9, 0xc9, 0x2f, 0xc9, 0xc9, 0xc9, 0x34, 0xc9, 0xc9, 0xc9, 0x39,\n0xc9, 0xc9, 0xc9, 0x3d, 0xc8, 0xc8, 0xc8, 0x41, 0xcb, 0xcb, 0xcb, 0x44, 0xee, 0xee, 0xee, 0x87,\n0xfa, 0xfa, 0xfa, 0xc8, 0xf9, 0xf9, 0xf9, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xfa, 0xfa, 0xfa, 0xc9,\n0xfa, 0xfa, 0xfa, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xf9, 0xf9, 0xf9, 0xc9, 0xfa, 0xfa, 0xfa, 0xc8,\n0xee, 0xee, 0xee, 0x87, 0xcb, 0xcb, 0xcb, 0x44, 0xc8, 0xc8, 0xc8, 0x41, 0xc9, 0xc9, 0xc9, 0x3d,\n0xc9, 0xc9, 0xc9, 0x39, 0xc9, 0xc9, 0xc9, 0x34, 0xc9, 0xc9, 0xc9, 0x2f, 0xc8, 0xc8, 0xc8, 0x2a,\n0xcd, 0xcd, 0xcd, 0x24, 0xce, 0xce, 0xce, 0x1f, 0xce, 0xce, 0xce, 0x1a, 0xce, 0xce, 0xce, 0x15,\n0xd2, 0xd2, 0xd2, 0x11, 0xd8, 0xd8, 0xd8, 0x0d, 0xcc, 0xcc, 0xcc, 0x0a, 0xdb, 0xdb, 0xdb, 0x07,\n0xcc, 0xcc, 0xcc, 0x05, 0xbf, 0xbf, 0xbf, 0x04, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0x01,\n]);\n\nconst LASER_LENGTH = 1.0;\nconst LASER_DIAMETER = 0.01;\nconst LASER_FADE_END = 0.535;\nconst LASER_FADE_POINT = 0.5335;\nconst LASER_DEFAULT_COLOR = [1.0, 1.0, 1.0, 0.25];\n\nconst CURSOR_RADIUS = 0.004;\nconst CURSOR_SHADOW_RADIUS = 0.007;\nconst CURSOR_SHADOW_INNER_LUMINANCE = 0.5;\nconst CURSOR_SHADOW_OUTER_LUMINANCE = 0.0;\nconst CURSOR_SHADOW_INNER_OPACITY = 0.75;\nconst CURSOR_SHADOW_OUTER_OPACITY = 0.0;\nconst CURSOR_OPACITY = 0.9;\nconst CURSOR_SEGMENTS = 16;\nconst CURSOR_DEFAULT_COLOR = [1.0, 1.0, 1.0, 1.0];\nconst CURSOR_DEFAULT_HIDDEN_COLOR = [0.5, 0.5, 0.5, 0.25];\n\nconst DEFAULT_RESET_OPTIONS = {\n controllers: true,\n lasers: true,\n cursors: true,\n};\n\nclass LaserMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.ADDITIVE;\n this.state.cullFace = false;\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.blendFuncDst = GL.ONE;\n this.state.depthMask = false;\n\n this.laser = this.defineSampler('diffuse');\n this.laser.texture = new DataTexture(LASER_TEXTURE_DATA, 48, 1);\n this.laserColor = this.defineUniform('laserColor', LASER_DEFAULT_COLOR);\n }\n\n get materialName() {\n return 'INPUT_LASER';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n\n uniform vec4 laserColor;\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n const float fadePoint = ${LASER_FADE_POINT};\n const float fadeEnd = ${LASER_FADE_END};\n\n vec4 fragment_main() {\n vec2 uv = vTexCoord;\n float front_fade_factor = 1.0 - clamp(1.0 - (uv.y - fadePoint) / (1.0 - fadePoint), 0.0, 1.0);\n float back_fade_factor = clamp((uv.y - fadePoint) / (fadeEnd - fadePoint), 0.0, 1.0);\n vec4 color = laserColor * texture2D(diffuse, vTexCoord);\n float opacity = color.a * front_fade_factor * back_fade_factor;\n return vec4(color.rgb * opacity, opacity);\n }`;\n }\n}\n\nconst CURSOR_VERTEX_SHADER = `\nattribute vec4 POSITION;\n\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vLuminance = POSITION.z;\n vOpacity = POSITION.w;\n\n // Billboarded, constant size vertex transform.\n vec4 screenPos = proj * view * model * vec4(0.0, 0.0, 0.0, 1.0);\n screenPos /= screenPos.w;\n screenPos.xy += POSITION.xy;\n return screenPos;\n}`;\n\nconst CURSOR_FRAGMENT_SHADER = `\nprecision mediump float;\n\nuniform vec4 cursorColor;\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 fragment_main() {\n vec3 color = cursorColor.rgb * vLuminance;\n float opacity = cursorColor.a * vOpacity;\n return vec4(color * opacity, opacity);\n}`;\n\n// Cursors are drawn as billboards that always face the camera and are rendered\n// as a fixed size no matter how far away they are.\nclass CursorMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.ADDITIVE;\n this.state.cullFace = false;\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.depthMask = false;\n\n this.cursorColor = this.defineUniform('cursorColor', CURSOR_DEFAULT_COLOR);\n }\n\n get materialName() {\n return 'INPUT_CURSOR';\n }\n\n get vertexSource() {\n return CURSOR_VERTEX_SHADER;\n }\n\n get fragmentSource() {\n return CURSOR_FRAGMENT_SHADER;\n }\n}\n\nclass CursorHiddenMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.ADDITIVE;\n this.state.cullFace = false;\n this.state.blend = true;\n this.state.blendFuncSrc = GL.ONE;\n this.state.depthFunc = GL.GEQUAL;\n this.state.depthMask = false;\n\n this.cursorColor = this.defineUniform('cursorColor', CURSOR_DEFAULT_HIDDEN_COLOR);\n }\n\n // TODO: Rename to \"program_name\"\n get materialName() {\n return 'INPUT_CURSOR_2';\n }\n\n get vertexSource() {\n return CURSOR_VERTEX_SHADER;\n }\n\n get fragmentSource() {\n return CURSOR_FRAGMENT_SHADER;\n }\n}\n\nexport class InputRenderer extends Node {\n constructor() {\n super();\n\n this._maxInputElements = 32;\n\n this._controllers = [];\n this._controllerNode = null;\n this._controllerNodeHandedness = null;\n this._lasers = null;\n this._cursors = null;\n\n this._activeControllers = 0;\n this._activeLasers = 0;\n this._activeCursors = 0;\n }\n\n onRendererChanged(renderer) {\n this._controllers = [];\n this._controllerNode = null;\n this._controllerNodeHandedness = null;\n this._lasers = null;\n this._cursors = null;\n\n this._activeControllers = 0;\n this._activeLasers = 0;\n this._activeCursors = 0;\n }\n\n setControllerMesh(controllerNode, handedness = 'right') {\n this._controllerNode = controllerNode;\n this._controllerNode.visible = false;\n // FIXME: Temporary fix to initialize for cloning.\n this.addNode(this._controllerNode);\n this._controllerNodeHandedness = handedness;\n }\n\n addController(gripMatrix) {\n if (!this._controllerNode) {\n return;\n }\n\n let controller = null;\n if (this._activeControllers < this._controllers.length) {\n controller = this._controllers[this._activeControllers];\n } else {\n controller = this._controllerNode.clone();\n this.addNode(controller);\n this._controllers.push(controller);\n }\n this._activeControllers = (this._activeControllers + 1) % this._maxInputElements;\n\n controller.matrix = gripMatrix;\n controller.visible = true;\n }\n\n addLaserPointer(targetRay) {\n // Create the laser pointer mesh if needed.\n if (!this._lasers && this._renderer) {\n this._lasers = [this._createLaserMesh()];\n this.addNode(this._lasers[0]);\n }\n\n let laser = null;\n if (this._activeLasers < this._lasers.length) {\n laser = this._lasers[this._activeLasers];\n } else {\n laser = this._lasers[0].clone();\n this.addNode(laser);\n this._lasers.push(laser);\n }\n this._activeLasers = (this._activeLasers + 1) % this._maxInputElements;\n\n laser.matrix = targetRay.transformMatrix;\n laser.visible = true;\n }\n\n addCursor(cursorPos) {\n // Create the cursor mesh if needed.\n if (!this._cursors && this._renderer) {\n this._cursors = [this._createCursorMesh()];\n this.addNode(this._cursors[0]);\n }\n\n let cursor = null;\n if (this._activeCursors < this._cursors.length) {\n cursor = this._cursors[this._activeCursors];\n } else {\n cursor = this._cursors[0].clone();\n this.addNode(cursor);\n this._cursors.push(cursor);\n }\n this._activeCursors = (this._activeCursors + 1) % this._maxInputElements;\n\n cursor.translation = cursorPos;\n cursor.visible = true;\n }\n\n reset(options) {\n if (!options) {\n options = DEFAULT_RESET_OPTIONS;\n }\n if (this._controllers && options.controllers) {\n for (let controller of this._controllers) {\n controller.visible = false;\n }\n this._activeControllers = 0;\n }\n if (this._lasers && options.lasers) {\n for (let laser of this._lasers) {\n laser.visible = false;\n }\n this._activeLasers = 0;\n }\n if (this._cursors && options.cursors) {\n for (let cursor of this._cursors) {\n cursor.visible = false;\n }\n this._activeCursors = 0;\n }\n }\n\n _createLaserMesh() {\n let gl = this._renderer._gl;\n\n let lr = LASER_DIAMETER * 0.5;\n let ll = LASER_LENGTH;\n\n // Laser is rendered as cross-shaped beam\n let laserVerts = [\n // X Y Z U V\n 0.0, lr, 0.0, 0.0, 1.0,\n 0.0, lr, -ll, 0.0, 0.0,\n 0.0, -lr, 0.0, 1.0, 1.0,\n 0.0, -lr, -ll, 1.0, 0.0,\n\n lr, 0.0, 0.0, 0.0, 1.0,\n lr, 0.0, -ll, 0.0, 0.0,\n -lr, 0.0, 0.0, 1.0, 1.0,\n -lr, 0.0, -ll, 1.0, 0.0,\n\n 0.0, -lr, 0.0, 0.0, 1.0,\n 0.0, -lr, -ll, 0.0, 0.0,\n 0.0, lr, 0.0, 1.0, 1.0,\n 0.0, lr, -ll, 1.0, 0.0,\n\n -lr, 0.0, 0.0, 0.0, 1.0,\n -lr, 0.0, -ll, 0.0, 0.0,\n lr, 0.0, 0.0, 1.0, 1.0,\n lr, 0.0, -ll, 1.0, 0.0,\n ];\n let laserIndices = [\n 0, 1, 2, 1, 3, 2,\n 4, 5, 6, 5, 7, 6,\n 8, 9, 10, 9, 11, 10,\n 12, 13, 14, 13, 15, 14,\n ];\n\n let laserVertexBuffer = this._renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(laserVerts));\n let laserIndexBuffer = this._renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(laserIndices));\n\n let laserIndexCount = laserIndices.length;\n\n let laserAttribs = [\n new PrimitiveAttribute('POSITION', laserVertexBuffer, 3, gl.FLOAT, 20, 0),\n new PrimitiveAttribute('TEXCOORD_0', laserVertexBuffer, 2, gl.FLOAT, 20, 12),\n ];\n\n let laserPrimitive = new Primitive(laserAttribs, laserIndexCount);\n laserPrimitive.setIndexBuffer(laserIndexBuffer);\n\n let laserMaterial = new LaserMaterial();\n\n let laserRenderPrimitive = this._renderer.createRenderPrimitive(laserPrimitive, laserMaterial);\n let meshNode = new Node();\n meshNode.addRenderPrimitive(laserRenderPrimitive);\n return meshNode;\n }\n\n _createCursorMesh() {\n let gl = this._renderer._gl;\n\n // Cursor is a circular white dot with a dark \"shadow\" skirt around the edge\n // that fades from black to transparent as it moves out from the center.\n // Cursor verts are packed as [X, Y, Luminance, Opacity]\n let cursorVerts = [];\n let cursorIndices = [];\n\n let segRad = (2.0 * Math.PI) / CURSOR_SEGMENTS;\n\n // Cursor center\n for (let i = 0; i < CURSOR_SEGMENTS; ++i) {\n let rad = i * segRad;\n let x = Math.cos(rad);\n let y = Math.sin(rad);\n cursorVerts.push(x * CURSOR_RADIUS, y * CURSOR_RADIUS, 1.0, CURSOR_OPACITY);\n\n if (i > 1) {\n cursorIndices.push(0, i-1, i);\n }\n }\n\n let indexOffset = CURSOR_SEGMENTS;\n\n // Cursor Skirt\n for (let i = 0; i < CURSOR_SEGMENTS; ++i) {\n let rad = i * segRad;\n let x = Math.cos(rad);\n let y = Math.sin(rad);\n cursorVerts.push(x * CURSOR_RADIUS, y * CURSOR_RADIUS,\n CURSOR_SHADOW_INNER_LUMINANCE, CURSOR_SHADOW_INNER_OPACITY);\n cursorVerts.push(x * CURSOR_SHADOW_RADIUS, y * CURSOR_SHADOW_RADIUS,\n CURSOR_SHADOW_OUTER_LUMINANCE, CURSOR_SHADOW_OUTER_OPACITY);\n\n if (i > 0) {\n let idx = indexOffset + (i * 2);\n cursorIndices.push(idx-2, idx-1, idx);\n cursorIndices.push(idx-1, idx+1, idx);\n }\n }\n\n let idx = indexOffset + (CURSOR_SEGMENTS * 2);\n cursorIndices.push(idx-2, idx-1, indexOffset);\n cursorIndices.push(idx-1, indexOffset+1, indexOffset);\n\n let cursorVertexBuffer = this._renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(cursorVerts));\n let cursorIndexBuffer = this._renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cursorIndices));\n\n let cursorIndexCount = cursorIndices.length;\n\n let cursorAttribs = [\n new PrimitiveAttribute('POSITION', cursorVertexBuffer, 4, gl.FLOAT, 16, 0),\n ];\n\n let cursorPrimitive = new Primitive(cursorAttribs, cursorIndexCount);\n cursorPrimitive.setIndexBuffer(cursorIndexBuffer);\n\n let cursorMaterial = new CursorMaterial();\n let cursorHiddenMaterial = new CursorHiddenMaterial();\n\n // Cursor renders two parts: The bright opaque cursor for areas where it's\n // not obscured and a more transparent, darker version for areas where it's\n // behind another object.\n let cursorRenderPrimitive = this._renderer.createRenderPrimitive(cursorPrimitive, cursorMaterial);\n let cursorHiddenRenderPrimitive = this._renderer.createRenderPrimitive(cursorPrimitive, cursorHiddenMaterial);\n let meshNode = new Node();\n meshNode.addRenderPrimitive(cursorRenderPrimitive);\n meshNode.addRenderPrimitive(cursorHiddenRenderPrimitive);\n return meshNode;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nRenders simple text using a seven-segment LED style pattern. Only really good\nfor numbers and a limited number of other characters.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\n\nconst TEXT_KERNING = 2.0;\n\nclass SevenSegmentMaterial extends Material {\n get materialName() {\n return 'SEVEN_SEGMENT_TEXT';\n }\n\n get vertexSource() {\n return `\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 0.0, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n const vec4 color = vec4(0.0, 1.0, 0.0, 1.0);\n\n vec4 fragment_main() {\n return color;\n }`;\n }\n}\n\nexport class SevenSegmentText extends Node {\n constructor() {\n super();\n\n this._text = '';\n this._charNodes = [];\n }\n\n onRendererChanged(renderer) {\n this.clearNodes();\n this._charNodes = [];\n\n let vertices = [];\n let segmentIndices = {};\n let indices = [];\n\n const width = 0.5;\n const thickness = 0.25;\n\n function defineSegment(id, left, top, right, bottom) {\n let idx = vertices.length / 2;\n vertices.push(\n left, top,\n right, top,\n right, bottom,\n left, bottom);\n\n segmentIndices[id] = [\n idx, idx+2, idx+1,\n idx, idx+3, idx+2,\n ];\n }\n\n let characters = {};\n function defineCharacter(c, segments) {\n let character = {\n character: c,\n offset: indices.length * 2,\n count: 0,\n };\n\n for (let i = 0; i < segments.length; ++i) {\n let idx = segments[i];\n let segment = segmentIndices[idx];\n character.count += segment.length;\n indices.push(...segment);\n }\n\n characters[c] = character;\n }\n\n /* Segment layout is as follows:\n\n |-0-|\n 3 4\n |-1-|\n 5 6\n |-2-|\n\n */\n\n defineSegment(0, -1, 1, width, 1-thickness);\n defineSegment(1, -1, thickness*0.5, width, -thickness*0.5);\n defineSegment(2, -1, -1+thickness, width, -1);\n defineSegment(3, -1, 1, -1+thickness, -thickness*0.5);\n defineSegment(4, width-thickness, 1, width, -thickness*0.5);\n defineSegment(5, -1, thickness*0.5, -1+thickness, -1);\n defineSegment(6, width-thickness, thickness*0.5, width, -1);\n\n\n defineCharacter('0', [0, 2, 3, 4, 5, 6]);\n defineCharacter('1', [4, 6]);\n defineCharacter('2', [0, 1, 2, 4, 5]);\n defineCharacter('3', [0, 1, 2, 4, 6]);\n defineCharacter('4', [1, 3, 4, 6]);\n defineCharacter('5', [0, 1, 2, 3, 6]);\n defineCharacter('6', [0, 1, 2, 3, 5, 6]);\n defineCharacter('7', [0, 4, 6]);\n defineCharacter('8', [0, 1, 2, 3, 4, 5, 6]);\n defineCharacter('9', [0, 1, 2, 3, 4, 6]);\n defineCharacter('A', [0, 1, 3, 4, 5, 6]);\n defineCharacter('B', [1, 2, 3, 5, 6]);\n defineCharacter('C', [0, 2, 3, 5]);\n defineCharacter('D', [1, 2, 4, 5, 6]);\n defineCharacter('E', [0, 1, 2, 4, 6]);\n defineCharacter('F', [0, 1, 3, 5]);\n defineCharacter('P', [0, 1, 3, 4, 5]);\n defineCharacter('-', [1]);\n defineCharacter(' ', []);\n defineCharacter('_', [2]); // Used for undefined characters\n\n let gl = renderer.gl;\n let vertexBuffer = renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(vertices));\n let indexBuffer = renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let vertexAttribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 2, gl.FLOAT, 8, 0),\n ];\n\n let primitive = new Primitive(vertexAttribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n\n let material = new SevenSegmentMaterial();\n\n this._charPrimitives = {};\n for (let char in characters) {\n let charDef = characters[char];\n primitive.elementCount = charDef.count;\n primitive.indexByteOffset = charDef.offset;\n this._charPrimitives[char] = renderer.createRenderPrimitive(primitive, material);\n }\n\n this.text = this._text;\n }\n\n get text() {\n return this._text;\n }\n\n set text(value) {\n this._text = value;\n\n let i = 0;\n let charPrimitive = null;\n for (; i < value.length; ++i) {\n if (value[i] in this._charPrimitives) {\n charPrimitive = this._charPrimitives[value[i]];\n } else {\n charPrimitive = this._charPrimitives['_'];\n }\n\n if (this._charNodes.length <= i) {\n let node = new Node();\n node.addRenderPrimitive(charPrimitive);\n let offset = i * TEXT_KERNING;\n node.translation = [offset, 0, 0];\n this._charNodes.push(node);\n this.addNode(node);\n } else {\n // This is sort of an abuse of how these things are expected to work,\n // but it's the cheapest thing I could think of that didn't break the\n // world.\n this._charNodes[i].clearRenderPrimitives();\n this._charNodes[i].addRenderPrimitive(charPrimitive);\n this._charNodes[i].visible = true;\n }\n }\n\n // If there's any nodes left over make them invisible\n for (; i < this._charNodes.length; ++i) {\n this._charNodes[i].visible = false;\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nNode for displaying 360 equirect images as a skybox.\n*/\n\nimport {Material, RENDER_ORDER} from '../core/material.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {Node} from '../core/node.js';\nimport {UrlTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nclass SkyboxMaterial extends Material {\n constructor() {\n super();\n this.renderOrder = RENDER_ORDER.SKY;\n this.state.depthFunc = GL.LEQUAL;\n this.state.depthMask = false;\n\n this.image = this.defineSampler('diffuse');\n\n this.texCoordScaleOffset = this.defineUniform('texCoordScaleOffset',\n [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0], 4);\n }\n\n get materialName() {\n return 'SKYBOX';\n }\n\n get vertexSource() {\n return `\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n // Drop the translation portion of the view matrix\n view[3].xyz = vec3(0.0, 0.0, 0.0);\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n\n // Returning the W component for both Z and W forces the geometry depth to\n // the far plane. When combined with a depth func of LEQUAL this makes the\n // sky write to any depth fragment that has not been written to yet.\n return out_vec.xyww;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }`;\n }\n}\n\nexport class SkyboxNode extends Node {\n constructor(options) {\n super();\n\n this._url = options.url;\n this._displayMode = options.displayMode || 'mono';\n this._rotationY = options.rotationY || 0;\n }\n\n onRendererChanged(renderer) {\n let vertices = [];\n let indices = [];\n\n let latSegments = 40;\n let lonSegments = 40;\n\n // Create the vertices/indices\n for (let i=0; i <= latSegments; ++i) {\n let theta = i * Math.PI / latSegments;\n let sinTheta = Math.sin(theta);\n let cosTheta = Math.cos(theta);\n\n let idxOffsetA = i * (lonSegments+1);\n let idxOffsetB = (i+1) * (lonSegments+1);\n\n for (let j=0; j <= lonSegments; ++j) {\n let phi = (j * 2 * Math.PI / lonSegments) + this._rotationY;\n let x = Math.sin(phi) * sinTheta;\n let y = cosTheta;\n let z = -Math.cos(phi) * sinTheta;\n let u = (j / lonSegments);\n let v = (i / latSegments);\n\n // Vertex shader will force the geometry to the far plane, so the\n // radius of the sphere is immaterial.\n vertices.push(x, y, z, u, v);\n\n if (i < latSegments && j < lonSegments) {\n let idxA = idxOffsetA+j;\n let idxB = idxOffsetB+j;\n\n indices.push(idxA, idxB, idxA+1,\n idxB, idxB+1, idxA+1);\n }\n }\n }\n\n let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(vertices));\n let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 20, 0),\n new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 20, 12),\n ];\n\n let primitive = new Primitive(attribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n\n let material = new SkyboxMaterial();\n material.image.texture = new UrlTexture(this._url);\n\n switch (this._displayMode) {\n case 'mono':\n material.texCoordScaleOffset.value = [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0];\n break;\n case 'stereoTopBottom':\n material.texCoordScaleOffset.value = [1.0, 0.5, 0.0, 0.0,\n 1.0, 0.5, 0.0, 0.5];\n break;\n case 'stereoLeftRight':\n material.texCoordScaleOffset.value = [0.5, 1.0, 0.0, 0.0,\n 0.5, 1.0, 0.5, 0.0];\n break;\n }\n\n let renderPrimitive = renderer.createRenderPrimitive(primitive, material);\n this.addRenderPrimitive(renderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nHeavily inspired by Mr. Doobs stats.js, this FPS counter is rendered completely\nwith WebGL, allowing it to be shown in cases where overlaid HTML elements aren't\nusable (like WebXR), or if you want the FPS counter to be rendered as part of\nyour scene.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Node} from '../core/node.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {SevenSegmentText} from './seven-segment-text.js';\n\nconst SEGMENTS = 30;\nconst MAX_FPS = 90;\n\nclass StatsMaterial extends Material {\n get materialName() {\n return 'STATS_VIEWER';\n }\n\n get vertexSource() {\n return `\n attribute vec3 POSITION;\n attribute vec3 COLOR_0;\n varying vec4 vColor;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vColor = vec4(COLOR_0, 1.0);\n return proj * view * model * vec4(POSITION, 1.0);\n }`;\n }\n\n get fragmentSource() {\n return `\n precision mediump float;\n varying vec4 vColor;\n\n vec4 fragment_main() {\n return vColor;\n }`;\n }\n}\n\nfunction segmentToX(i) {\n return ((0.9/SEGMENTS) * i) - 0.45;\n}\n\nfunction fpsToY(value) {\n return (Math.min(value, MAX_FPS) * (0.7 / MAX_FPS)) - 0.45;\n}\n\nfunction fpsToRGB(value) {\n return {\n r: Math.max(0.0, Math.min(1.0, 1.0 - (value/60))),\n g: Math.max(0.0, Math.min(1.0, ((value-15)/(MAX_FPS-15)))),\n b: Math.max(0.0, Math.min(1.0, ((value-15)/(MAX_FPS-15)))),\n };\n}\n\nlet now = (window.performance && performance.now) ? performance.now.bind(performance) : Date.now;\n\nexport class StatsViewer extends Node {\n constructor() {\n super();\n\n this._performanceMonitoring = false;\n\n this._startTime = now();\n this._prevFrameTime = this._startTime;\n this._prevGraphUpdateTime = this._startTime;\n this._frames = 0;\n this._fpsAverage = 0;\n this._fpsMin = 0;\n this._fpsStep = this._performanceMonitoring ? 1000 : 250;\n this._lastSegment = 0;\n\n this._fpsVertexBuffer = null;\n this._fpsRenderPrimitive = null;\n this._fpsNode = null;\n\n this._sevenSegmentNode = new SevenSegmentText();\n // Hard coded because it doesn't change:\n // Scale by 0.075 in X and Y\n // Translate into upper left corner w/ z = 0.02\n this._sevenSegmentNode.matrix = new Float32Array([\n 0.075, 0, 0, 0,\n 0, 0.075, 0, 0,\n 0, 0, 1, 0,\n -0.3625, 0.3625, 0.02, 1,\n ]);\n }\n\n onRendererChanged(renderer) {\n this.clearNodes();\n\n let gl = renderer.gl;\n\n let fpsVerts = [];\n let fpsIndices = [];\n\n // Graph geometry\n for (let i = 0; i < SEGMENTS; ++i) {\n // Bar top\n fpsVerts.push(segmentToX(i), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n fpsVerts.push(segmentToX(i+1), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n\n // Bar bottom\n fpsVerts.push(segmentToX(i), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n fpsVerts.push(segmentToX(i+1), fpsToY(0), 0.02, 0.0, 1.0, 1.0);\n\n let idx = i * 4;\n fpsIndices.push(idx, idx+3, idx+1,\n idx+3, idx, idx+2);\n }\n\n function addBGSquare(left, bottom, right, top, z, r, g, b) {\n let idx = fpsVerts.length / 6;\n\n fpsVerts.push(left, bottom, z, r, g, b);\n fpsVerts.push(right, top, z, r, g, b);\n fpsVerts.push(left, top, z, r, g, b);\n fpsVerts.push(right, bottom, z, r, g, b);\n\n fpsIndices.push(idx, idx+1, idx+2,\n idx, idx+3, idx+1);\n }\n\n // Panel Background\n addBGSquare(-0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.125);\n\n // FPS Background\n addBGSquare(-0.45, -0.45, 0.45, 0.25, 0.01, 0.0, 0.0, 0.4);\n\n // 30 FPS line\n addBGSquare(-0.45, fpsToY(30), 0.45, fpsToY(32), 0.015, 0.5, 0.0, 0.5);\n\n // 60 FPS line\n addBGSquare(-0.45, fpsToY(60), 0.45, fpsToY(62), 0.015, 0.2, 0.0, 0.75);\n\n this._fpsVertexBuffer = renderer.createRenderBuffer(gl.ARRAY_BUFFER, new Float32Array(fpsVerts), gl.DYNAMIC_DRAW);\n let fpsIndexBuffer = renderer.createRenderBuffer(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(fpsIndices));\n\n let fpsAttribs = [\n new PrimitiveAttribute('POSITION', this._fpsVertexBuffer, 3, gl.FLOAT, 24, 0),\n new PrimitiveAttribute('COLOR_0', this._fpsVertexBuffer, 3, gl.FLOAT, 24, 12),\n ];\n\n let fpsPrimitive = new Primitive(fpsAttribs, fpsIndices.length);\n fpsPrimitive.setIndexBuffer(fpsIndexBuffer);\n fpsPrimitive.setBounds([-0.5, -0.5, 0.0], [0.5, 0.5, 0.015]);\n\n this._fpsRenderPrimitive = renderer.createRenderPrimitive(fpsPrimitive, new StatsMaterial());\n this._fpsNode = new Node();\n this._fpsNode.addRenderPrimitive(this._fpsRenderPrimitive);\n\n this.addNode(this._fpsNode);\n this.addNode(this._sevenSegmentNode);\n }\n\n get performanceMonitoring() {\n return this._performanceMonitoring;\n }\n\n set performanceMonitoring(value) {\n this._performanceMonitoring = value;\n this._fpsStep = value ? 1000 : 250;\n }\n\n begin() {\n this._startTime = now();\n }\n\n end() {\n let time = now();\n\n let frameFps = 1000 / (time - this._prevFrameTime);\n this._prevFrameTime = time;\n this._fpsMin = this._frames ? Math.min(this._fpsMin, frameFps) : frameFps;\n this._frames++;\n\n if (time > this._prevGraphUpdateTime + this._fpsStep) {\n let intervalTime = time - this._prevGraphUpdateTime;\n this._fpsAverage = Math.round(1000 / (intervalTime / this._frames));\n\n // Draw both average and minimum FPS for this period\n // so that dropped frames are more clearly visible.\n this._updateGraph(this._fpsMin, this._fpsAverage);\n if (this._performanceMonitoring) {\n console.log(`Average FPS: ${this._fpsAverage} Min FPS: ${this._fpsMin}`);\n }\n\n this._prevGraphUpdateTime = time;\n this._frames = 0;\n this._fpsMin = 0;\n }\n }\n\n _updateGraph(valueLow, valueHigh) {\n let color = fpsToRGB(valueLow);\n // Draw a range from the low to high value. Artificially widen the\n // range a bit to ensure that near-equal values still remain\n // visible - the logic here should match that used by the\n // \"60 FPS line\" setup below. Hitting 60fps consistently will\n // keep the top half of the 60fps background line visible.\n let y0 = fpsToY(valueLow - 1);\n let y1 = fpsToY(valueHigh + 1);\n\n // Update the current segment with the new FPS value\n let updateVerts = [\n segmentToX(this._lastSegment), y1, 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1), y1, 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment), y0, 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1), y0, 0.02, color.r, color.g, color.b,\n ];\n\n // Re-shape the next segment into the green \"progress\" line\n color.r = 0.2;\n color.g = 1.0;\n color.b = 0.2;\n\n if (this._lastSegment == SEGMENTS - 1) {\n // If we're updating the last segment we need to do two bufferSubDatas\n // to update the segment and turn the first segment into the progress line.\n this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts),\n this._lastSegment * 24 * 4);\n updateVerts = [\n segmentToX(0), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(.25), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(0), fpsToY(0), 0.02, color.r, color.g, color.b,\n segmentToX(.25), fpsToY(0), 0.02, color.r, color.g, color.b,\n ];\n this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts), 0);\n } else {\n updateVerts.push(\n segmentToX(this._lastSegment+1), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1.25), fpsToY(MAX_FPS), 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1), fpsToY(0), 0.02, color.r, color.g, color.b,\n segmentToX(this._lastSegment+1.25), fpsToY(0), 0.02, color.r, color.g, color.b\n );\n this._renderer.updateRenderBuffer(this._fpsVertexBuffer, new Float32Array(updateVerts),\n this._lastSegment * 24 * 4);\n }\n\n this._lastSegment = (this._lastSegment+1) % SEGMENTS;\n\n this._sevenSegmentNode.text = `${this._fpsAverage} FP5`;\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nNode for displaying 2D or stereo videos on a quad.\n*/\n\nimport {Material} from '../core/material.js';\nimport {Primitive, PrimitiveAttribute} from '../core/primitive.js';\nimport {Node} from '../core/node.js';\nimport {VideoTexture} from '../core/texture.js';\n\nconst GL = WebGLRenderingContext; // For enums\n\nclass VideoMaterial extends Material {\n constructor() {\n super();\n\n this.image = this.defineSampler('diffuse');\n\n this.texCoordScaleOffset = this.defineUniform('texCoordScaleOffset',\n [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0], 4);\n }\n\n get materialName() {\n return 'VIDEO_PLAYER';\n }\n\n get vertexSource() {\n return `\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n return out_vec;\n }`;\n }\n\n get fragmentSource() {\n return `\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }`;\n }\n}\n\nexport class VideoNode extends Node {\n constructor(options) {\n super();\n\n this._video = options.video;\n this._displayMode = options.displayMode || 'mono';\n\n this._video_texture = new VideoTexture(this._video);\n }\n\n get aspectRatio() {\n let width = this._video.videoWidth;\n let height = this._video.videoHeight;\n\n switch (this._displayMode) {\n case 'stereoTopBottom': height *= 0.5; break;\n case 'stereoLeftRight': width *= 0.5; break;\n }\n\n if (!height || !width) {\n return 1;\n }\n\n return width / height;\n }\n\n onRendererChanged(renderer) {\n let vertices = [\n -1.0, 1.0, 0.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 1.0, 0.0,\n 1.0, -1.0, 0.0, 1.0, 1.0,\n -1.0, -1.0, 0.0, 0.0, 1.0,\n ];\n let indices = [\n 0, 2, 1,\n 0, 3, 2,\n ];\n\n let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(vertices));\n let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));\n\n let attribs = [\n new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 20, 0),\n new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 20, 12),\n ];\n\n let primitive = new Primitive(attribs, indices.length);\n primitive.setIndexBuffer(indexBuffer);\n primitive.setBounds([-1.0, -1.0, 0.0], [1.0, 1.0, 0.015]);\n\n let material = new VideoMaterial();\n material.image.texture = this._video_texture;\n\n switch (this._displayMode) {\n case 'mono':\n material.texCoordScaleOffset.value = [1.0, 1.0, 0.0, 0.0,\n 1.0, 1.0, 0.0, 0.0];\n break;\n case 'stereoTopBottom':\n material.texCoordScaleOffset.value = [1.0, 0.5, 0.0, 0.0,\n 1.0, 0.5, 0.0, 0.5];\n break;\n case 'stereoLeftRight':\n material.texCoordScaleOffset.value = [0.5, 1.0, 0.0, 0.0,\n 0.5, 1.0, 0.5, 0.0];\n break;\n }\n\n let renderPrimitive = renderer.createRenderPrimitive(primitive, material);\n this.addRenderPrimitive(renderPrimitive);\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {RenderView} from '../core/renderer.js';\nimport {InputRenderer} from '../nodes/input-renderer.js';\nimport {StatsViewer} from '../nodes/stats-viewer.js';\nimport {Node} from '../core/node.js';\nimport {vec3, quat} from '../math/gl-matrix.js';\n\nexport class WebXRView extends RenderView {\n constructor(view, layer) {\n super(\n view ? view.projectionMatrix : null,\n view ? view.viewMatrix : null,\n (layer && view) ? layer.getViewport(view) : null,\n view ? view.eye : 'left'\n );\n }\n}\n\nexport class Scene extends Node {\n constructor() {\n super();\n\n this._timestamp = -1;\n this._frameDelta = 0;\n this._statsStanding = false;\n this._stats = null;\n this._statsEnabled = false;\n this.enableStats(true); // Ensure the stats are added correctly by default.\n\n this._inputRenderer = null;\n this._resetInputEndFrame = true;\n\n this._lastTimestamp = 0;\n\n this._hoverFrame = 0;\n this._hoveredNodes = [];\n\n this.clear = true;\n }\n\n setRenderer(renderer) {\n this._setRenderer(renderer);\n }\n\n loseRenderer() {\n if (this._renderer) {\n this._stats = null;\n this._renderer = null;\n this._inputRenderer = null;\n }\n }\n\n get inputRenderer() {\n if (!this._inputRenderer) {\n this._inputRenderer = new InputRenderer();\n this.addNode(this._inputRenderer);\n }\n return this._inputRenderer;\n }\n\n // Helper function that automatically adds the appropriate visual elements for\n // all input sources.\n updateInputSources(frame, frameOfRef) {\n // FIXME: Check for the existence of the API first. This check should be\n // removed once the input API is part of the official spec.\n if (!frame.session.getInputSources) {\n return;\n }\n\n let inputSources = frame.session.getInputSources();\n\n let newHoveredNodes = [];\n let lastHoverFrame = this._hoverFrame;\n this._hoverFrame++;\n\n for (let inputSource of inputSources) {\n let inputPose = frame.getInputPose(inputSource, frameOfRef);\n\n if (!inputPose) {\n continue;\n }\n\n // Any time that we have a grip matrix, we'll render a controller.\n if (inputPose.gripMatrix) {\n this.inputRenderer.addController(inputPose.gripMatrix);\n }\n\n if (inputPose.targetRay) {\n if (inputSource.targetRayMode == 'tracked-pointer') {\n // If we have a pointer matrix and the pointer origin is the users\n // hand (as opposed to their head or the screen) use it to render\n // a ray coming out of the input device to indicate the pointer\n // direction.\n this.inputRenderer.addLaserPointer(inputPose.targetRay);\n }\n\n // If we have a pointer matrix we can also use it to render a cursor\n // for both handheld and gaze-based input sources.\n\n // Check and see if the pointer is pointing at any selectable objects.\n let hitResult = this.hitTest(inputPose.targetRay);\n\n if (hitResult) {\n // Render a cursor at the intersection point.\n this.inputRenderer.addCursor(hitResult.intersection);\n\n if (hitResult.node._hoverFrameId != lastHoverFrame) {\n hitResult.node.onHoverStart();\n }\n hitResult.node._hoverFrameId = this._hoverFrame;\n newHoveredNodes.push(hitResult.node);\n } else {\n // Statically render the cursor 1 meters down the ray since we didn't\n // hit anything selectable.\n let cursorDistance = 1.0;\n let cursorPos = vec3.fromValues(\n inputPose.targetRay.origin.x,\n inputPose.targetRay.origin.y,\n inputPose.targetRay.origin.z\n );\n vec3.add(cursorPos, cursorPos, [\n inputPose.targetRay.direction.x * cursorDistance,\n inputPose.targetRay.direction.y * cursorDistance,\n inputPose.targetRay.direction.z * cursorDistance,\n ]);\n // let cursorPos = vec3.fromValues(0, 0, -1.0);\n // vec3.transformMat4(cursorPos, cursorPos, inputPose.targetRay);\n this.inputRenderer.addCursor(cursorPos);\n }\n }\n }\n\n for (let hoverNode of this._hoveredNodes) {\n if (hoverNode._hoverFrameId != this._hoverFrame) {\n hoverNode.onHoverEnd();\n }\n }\n\n this._hoveredNodes = newHoveredNodes;\n }\n\n handleSelect(inputSource, frame, frameOfRef) {\n let inputPose = frame.getInputPose(inputSource, frameOfRef);\n\n if (!inputPose) {\n return;\n }\n\n this.handleSelectPointer(inputPose.targetRay);\n }\n\n handleSelectPointer(targetRay) {\n if (targetRay) {\n // Check and see if the pointer is pointing at any selectable objects.\n let hitResult = this.hitTest(targetRay);\n\n if (hitResult) {\n // Render a cursor at the intersection point.\n hitResult.node.handleSelect();\n }\n }\n }\n\n enableStats(enable) {\n if (enable == this._statsEnabled) {\n return;\n }\n\n this._statsEnabled = enable;\n\n if (enable) {\n this._stats = new StatsViewer();\n this._stats.selectable = true;\n this.addNode(this._stats);\n\n if (this._statsStanding) {\n this._stats.translation = [0, 1.4, -0.75];\n } else {\n this._stats.translation = [0, -0.3, -0.5];\n }\n this._stats.scale = [0.3, 0.3, 0.3];\n quat.fromEuler(this._stats.rotation, -45.0, 0.0, 0.0);\n } else if (!enable) {\n if (this._stats) {\n this.removeNode(this._stats);\n this._stats = null;\n }\n }\n }\n\n standingStats(enable) {\n this._statsStanding = enable;\n if (this._stats) {\n if (this._statsStanding) {\n this._stats.translation = [0, 1.4, -0.75];\n } else {\n this._stats.translation = [0, -0.3, -0.5];\n }\n this._stats.scale = [0.3, 0.3, 0.3];\n quat.fromEuler(this._stats.rotation, -45.0, 0.0, 0.0);\n }\n }\n\n draw(projectionMatrix, viewMatrix, eye) {\n let view = new RenderView();\n view.projectionMatrix = projectionMatrix;\n view.viewMatrix = viewMatrix;\n if (eye) {\n view.eye = eye;\n }\n\n this.drawViewArray([view]);\n }\n\n /** Draws the scene into the base layer of the XRFrame's session */\n drawXRFrame(xrFrame, pose) {\n if (!this._renderer || !pose) {\n return;\n }\n\n let gl = this._renderer.gl;\n let session = xrFrame.session;\n // Assumed to be a XRWebGLLayer for now.\n let layer = session.baseLayer;\n\n if (!gl) {\n return;\n }\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);\n\n if (this.clear) {\n gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n }\n\n let views = [];\n for (let view of pose.views) {\n views.push(new WebXRView(view, layer));\n }\n\n this.drawViewArray(views);\n }\n\n drawViewArray(views) {\n // Don't draw when we don't have a valid context\n if (!this._renderer) {\n return;\n }\n\n this._renderer.drawViews(views, this);\n }\n\n startFrame() {\n let prevTimestamp = this._timestamp;\n this._timestamp = performance.now();\n if (this._stats) {\n this._stats.begin();\n }\n\n if (prevTimestamp >= 0) {\n this._frameDelta = this._timestamp - prevTimestamp;\n } else {\n this._frameDelta = 0;\n }\n\n this._update(this._timestamp, this._frameDelta);\n\n return this._frameDelta;\n }\n\n endFrame() {\n if (this._inputRenderer && this._resetInputEndFrame) {\n this._inputRenderer.reset();\n }\n\n if (this._stats) {\n this._stats.end();\n }\n }\n\n // Override to load scene resources on construction or context restore.\n onLoadScene(renderer) {\n return Promise.resolve();\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport {mat4} from '../math/gl-matrix.js';\n\nconst LOOK_SPEED = 0.0025;\n\nexport class FallbackHelper {\n constructor(scene, gl) {\n this.scene = scene;\n this.gl = gl;\n this._emulateStage = false;\n\n this.lookYaw = 0;\n this.lookPitch = 0;\n\n this.viewMatrix = mat4.create();\n\n let projectionMatrix = mat4.create();\n this.projectionMatrix = projectionMatrix;\n\n // Using a simple identity matrix for the view.\n mat4.identity(this.viewMatrix);\n\n // We need to track the canvas size in order to resize the WebGL\n // backbuffer width and height, as well as update the projection matrix\n // and adjust the viewport.\n function onResize() {\n gl.canvas.width = gl.canvas.offsetWidth * window.devicePixelRatio;\n gl.canvas.height = gl.canvas.offsetHeight * window.devicePixelRatio;\n mat4.perspective(projectionMatrix, Math.PI*0.4,\n gl.canvas.width/gl.canvas.height,\n 0.1, 1000.0);\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n }\n window.addEventListener('resize', onResize);\n onResize();\n\n // Upding the view matrix with touch or mouse events.\n let canvas = gl.canvas;\n let lastTouchX = 0;\n let lastTouchY = 0;\n canvas.addEventListener('touchstart', (ev) => {\n if (ev.touches.length == 2) {\n lastTouchX = ev.touches[1].pageX;\n lastTouchY = ev.touches[1].pageY;\n }\n });\n canvas.addEventListener('touchmove', (ev) => {\n // Rotate the view when two fingers are being used.\n if (ev.touches.length == 2) {\n this.onLook(ev.touches[1].pageX - lastTouchX, ev.touches[1].pageY - lastTouchY);\n lastTouchX = ev.touches[1].pageX;\n lastTouchY = ev.touches[1].pageY;\n }\n });\n canvas.addEventListener('mousemove', (ev) => {\n // Only rotate when the right button is pressed.\n if (ev.buttons & 2) {\n this.onLook(ev.movementX, ev.movementY);\n }\n });\n canvas.addEventListener('contextmenu', (ev) => {\n // Prevent context menus on the canvas so that we can use right click to rotate.\n ev.preventDefault();\n });\n\n this.boundOnFrame = this.onFrame.bind(this);\n window.requestAnimationFrame(this.boundOnFrame);\n }\n\n onLook(yaw, pitch) {\n this.lookYaw += yaw * LOOK_SPEED;\n this.lookPitch += pitch * LOOK_SPEED;\n\n // Clamp pitch rotation beyond looking straight up or down.\n if (this.lookPitch < -Math.PI*0.5) {\n this.lookPitch = -Math.PI*0.5;\n }\n if (this.lookPitch > Math.PI*0.5) {\n this.lookPitch = Math.PI*0.5;\n }\n\n this.updateView();\n }\n\n onFrame(t) {\n let gl = this.gl;\n window.requestAnimationFrame(this.boundOnFrame);\n\n this.scene.startFrame();\n\n // We can skip setting the framebuffer and viewport every frame, because\n // it won't change from frame to frame and we're updating the viewport\n // only when we resize for efficency.\n gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n\n // We're drawing with our own projection and view matrix now, and we\n // don't have a list of view to loop through, but otherwise all of the\n // WebGL drawing logic is exactly the same.\n this.scene.draw(this.projectionMatrix, this.viewMatrix);\n\n this.scene.endFrame();\n }\n\n get emulateStage() {\n return this._emulateStage;\n }\n\n set emulateStage(value) {\n this._emulateStage = value;\n this.updateView();\n }\n\n updateView() {\n mat4.identity(this.viewMatrix);\n\n mat4.rotateX(this.viewMatrix, this.viewMatrix, -this.lookPitch);\n mat4.rotateY(this.viewMatrix, this.viewMatrix, -this.lookYaw);\n\n // If we're emulating a stage frame of reference we'll need to move the view\n // matrix roughly a meter and a half up in the air.\n if (this._emulateStage) {\n mat4.translate(this.viewMatrix, this.viewMatrix, [0, -1.6, 0]);\n }\n }\n}\n","// Copyright 2018 The Immersive Web Community Group\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/*\nProvides a simple way to get values from the query string if they're present\nand use a default value if not. Not strictly a \"WebGL\" utility, but I use it\nfrequently enough for debugging that I wanted to include it here.\n\nExample:\nFor the URL http://example.com/index.html?particleCount=1000\n\nQueryArgs.getInt(\"particleCount\", 100); // URL overrides, returns 1000\nQueryArgs.getInt(\"particleSize\", 10); // Not in URL, returns default of 10\n*/\n\nlet urlArgs = null;\nwindow.onhashchange = function() {\n // Force re-parsing on next access\n urlArgs = null;\n};\n\nfunction ensureArgsCached() {\n if (!urlArgs) {\n urlArgs = {};\n let query = window.location.search.substring(1) || window.location.hash.substring(1);\n let vars = query.split('&');\n for (let i = 0; i < vars.length; i++) {\n let pair = vars[i].split('=');\n urlArgs[pair[0].toLowerCase()] = decodeURIComponent(pair[1]);\n }\n }\n}\n\nexport class QueryArgs {\n static getString(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return urlArgs[lcaseName];\n }\n return defaultValue;\n }\n\n static getInt(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return parseInt(urlArgs[lcaseName], 10);\n }\n return defaultValue;\n }\n\n static getFloat(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return parseFloat(urlArgs[lcaseName]);\n }\n return defaultValue;\n }\n\n static getBool(name, defaultValue) {\n ensureArgsCached();\n let lcaseName = name.toLowerCase();\n if (lcaseName in urlArgs) {\n return parseInt(urlArgs[lcaseName], 10) != 0;\n }\n return defaultValue;\n }\n}\n"],"sourceRoot":""} \ No newline at end of file
diff --git a/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.js b/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.js index dcdef5d..a7a02da 100644 --- a/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.js +++ b/third_party/webxr_test_pages/webxr-samples/js/cottontail/build/cottontail.js
@@ -19,4 +19,4 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var r=e();for(var n in r)("object"==typeof exports?exports:t)[n]=r[n]}}(window,function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},r.r=function(t){Object.defineProperty(t,"__esModule",{value:!0})},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=35)}([function(t,e,r){"use strict";r.r(e),r.d(e,"EPSILON",function(){return n}),r.d(e,"ARRAY_TYPE",function(){return i}),r.d(e,"RANDOM",function(){return o}),r.d(e,"setMatrixArrayType",function(){return a}),r.d(e,"toRadian",function(){return s}),r.d(e,"equals",function(){return c});const n=1e-6;let i="undefined"!=typeof Float32Array?Float32Array:Array;const o=Math.random;function a(t){i=t}const u=Math.PI/180;function s(t){return t*u}function c(t,e){return Math.abs(t-e)<=n*Math.max(1,Math.abs(t),Math.abs(e))}},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"fromValues",function(){return a}),r.d(e,"copy",function(){return u}),r.d(e,"set",function(){return s}),r.d(e,"add",function(){return c}),r.d(e,"subtract",function(){return f}),r.d(e,"multiply",function(){return l}),r.d(e,"divide",function(){return h}),r.d(e,"ceil",function(){return d}),r.d(e,"floor",function(){return v}),r.d(e,"min",function(){return _}),r.d(e,"max",function(){return m}),r.d(e,"round",function(){return p}),r.d(e,"scale",function(){return y}),r.d(e,"scaleAndAdd",function(){return b}),r.d(e,"distance",function(){return g}),r.d(e,"squaredDistance",function(){return M}),r.d(e,"length",function(){return x}),r.d(e,"squaredLength",function(){return T}),r.d(e,"negate",function(){return w}),r.d(e,"inverse",function(){return E}),r.d(e,"normalize",function(){return O}),r.d(e,"dot",function(){return R}),r.d(e,"lerp",function(){return P}),r.d(e,"random",function(){return S}),r.d(e,"transformMat4",function(){return A}),r.d(e,"transformQuat",function(){return N}),r.d(e,"str",function(){return C}),r.d(e,"exactEquals",function(){return I}),r.d(e,"equals",function(){return k}),r.d(e,"sub",function(){return L}),r.d(e,"mul",function(){return F}),r.d(e,"div",function(){return D}),r.d(e,"dist",function(){return B}),r.d(e,"sqrDist",function(){return j}),r.d(e,"len",function(){return U}),r.d(e,"sqrLen",function(){return V}),r.d(e,"forEach",function(){return Y});var n=r(0);function i(){let t=new n.ARRAY_TYPE(4);return t[0]=0,t[1]=0,t[2]=0,t[3]=0,t}function o(t){let e=new n.ARRAY_TYPE(4);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function a(t,e,r,i){let o=new n.ARRAY_TYPE(4);return o[0]=t,o[1]=e,o[2]=r,o[3]=i,o}function u(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t}function s(t,e,r,n,i){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t}function c(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t}function f(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t}function l(t,e,r){return t[0]=e[0]*r[0],t[1]=e[1]*r[1],t[2]=e[2]*r[2],t[3]=e[3]*r[3],t}function h(t,e,r){return t[0]=e[0]/r[0],t[1]=e[1]/r[1],t[2]=e[2]/r[2],t[3]=e[3]/r[3],t}function d(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2]),t[3]=Math.ceil(e[3]),t}function v(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2]),t[3]=Math.floor(e[3]),t}function _(t,e,r){return t[0]=Math.min(e[0],r[0]),t[1]=Math.min(e[1],r[1]),t[2]=Math.min(e[2],r[2]),t[3]=Math.min(e[3],r[3]),t}function m(t,e,r){return t[0]=Math.max(e[0],r[0]),t[1]=Math.max(e[1],r[1]),t[2]=Math.max(e[2],r[2]),t[3]=Math.max(e[3],r[3]),t}function p(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t[2]=Math.round(e[2]),t[3]=Math.round(e[3]),t}function y(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t}function b(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t}function g(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2],o=e[3]-t[3];return Math.sqrt(r*r+n*n+i*i+o*o)}function M(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2],o=e[3]-t[3];return r*r+n*n+i*i+o*o}function x(t){let e=t[0],r=t[1],n=t[2],i=t[3];return Math.sqrt(e*e+r*r+n*n+i*i)}function T(t){let e=t[0],r=t[1],n=t[2],i=t[3];return e*e+r*r+n*n+i*i}function w(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=-e[3],t}function E(t,e){return t[0]=1/e[0],t[1]=1/e[1],t[2]=1/e[2],t[3]=1/e[3],t}function O(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r*r+n*n+i*i+o*o;return a>0&&(a=1/Math.sqrt(a),t[0]=r*a,t[1]=n*a,t[2]=i*a,t[3]=o*a),t}function R(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]+t[3]*e[3]}function P(t,e,r,n){let i=e[0],o=e[1],a=e[2],u=e[3];return t[0]=i+n*(r[0]-i),t[1]=o+n*(r[1]-o),t[2]=a+n*(r[2]-a),t[3]=u+n*(r[3]-u),t}function S(t,e){return e=e||1,t[0]=n.RANDOM(),t[1]=n.RANDOM(),t[2]=n.RANDOM(),t[3]=n.RANDOM(),O(t,t),y(t,t,e),t}function A(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3];return t[0]=r[0]*n+r[4]*i+r[8]*o+r[12]*a,t[1]=r[1]*n+r[5]*i+r[9]*o+r[13]*a,t[2]=r[2]*n+r[6]*i+r[10]*o+r[14]*a,t[3]=r[3]*n+r[7]*i+r[11]*o+r[15]*a,t}function N(t,e,r){let n=e[0],i=e[1],o=e[2],a=r[0],u=r[1],s=r[2],c=r[3],f=c*n+u*o-s*i,l=c*i+s*n-a*o,h=c*o+a*i-u*n,d=-a*n-u*i-s*o;return t[0]=f*c+d*-a+l*-s-h*-u,t[1]=l*c+d*-u+h*-a-f*-s,t[2]=h*c+d*-s+f*-u-l*-a,t[3]=e[3],t}function C(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}function I(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]}function k(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=e[0],s=e[1],c=e[2],f=e[3];return Math.abs(r-u)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(u))&&Math.abs(i-s)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(s))&&Math.abs(o-c)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(c))&&Math.abs(a-f)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(f))}const L=f,F=l,D=h,B=g,j=M,U=x,V=T,Y=function(){let t=i();return function(e,r,n,i,o,a){let u,s;for(r||(r=4),n||(n=0),s=i?Math.min(i*r+n,e.length):e.length,u=n;u<s;u+=r)t[0]=e[u],t[1]=e[u+1],t[2]=e[u+2],t[3]=e[u+3],o(t,t,a),e[u]=t[0],e[u+1]=t[1],e[u+2]=t[2],e[u+3]=t[3];return e}}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Node=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(34),o=r(6);var a=new Float32Array([0,0,0]),u=new Float32Array([0,0,0,1]),s=new Float32Array([1,1,1]),c=o.mat4.create();e.Node=function(){function t(){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.name=null,this.children=[],this.parent=null,this.visible=!0,this.selectable=!1,this._matrix=null,this._dirtyTRS=!1,this._translation=null,this._rotation=null,this._scale=null,this._dirtyWorldMatrix=!1,this._worldMatrix=null,this._activeFrameId=-1,this._hoverFrameId=-1,this._renderPrimitives=null,this._renderer=null,this._selectHandler=null}return n(t,[{key:"_setRenderer",value:function(t){if(this._renderer!=t&&(this._renderer&&this.clearRenderPrimitives(),this._renderer=t,t)){this.onRendererChanged(t);var e=!0,r=!1,n=void 0;try{for(var i,o=this.children[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){i.value._setRenderer(t)}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}}}},{key:"onRendererChanged",value:function(t){}},{key:"clone",value:function(){var e=this,r=new t;return r.name=this.name,r.visible=this.visible,r._renderer=this._renderer,r._dirtyTRS=this._dirtyTRS,this._translation&&(r._translation=o.vec3.create(),o.vec3.copy(r._translation,this._translation)),this._rotation&&(r._rotation=o.quat.create(),o.quat.copy(r._rotation,this._rotation)),this._scale&&(r._scale=o.vec3.create(),o.vec3.copy(r._scale,this._scale)),!r._dirtyTRS&&this._matrix&&(r._matrix=o.mat4.create(),o.mat4.copy(r._matrix,this._matrix)),r._dirtyWorldMatrix=this._dirtyWorldMatrix,!r._dirtyWorldMatrix&&this._worldMatrix&&(r._worldMatrix=o.mat4.create(),o.mat4.copy(r._worldMatrix,this._worldMatrix)),this.waitForComplete().then(function(){if(e._renderPrimitives){var t=!0,n=!1,i=void 0;try{for(var o,a=e._renderPrimitives[Symbol.iterator]();!(t=(o=a.next()).done);t=!0){var u=o.value;r.addRenderPrimitive(u)}}catch(t){n=!0,i=t}finally{try{!t&&a.return&&a.return()}finally{if(n)throw i}}}var s=!0,c=!1,f=void 0;try{for(var l,h=e.children[Symbol.iterator]();!(s=(l=h.next()).done);s=!0){var d=l.value;r.addNode(d.clone())}}catch(t){c=!0,f=t}finally{try{!s&&h.return&&h.return()}finally{if(c)throw f}}}),r}},{key:"markActive",value:function(t){if(this.visible&&this._renderPrimitives){this._activeFrameId=t;var e=!0,r=!1,n=void 0;try{for(var i,o=this._renderPrimitives[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){i.value.markActive(t)}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}}var a=!0,u=!1,s=void 0;try{for(var c,f=this.children[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){var l=c.value;l.visible&&l.markActive(t)}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}}},{key:"addNode",value:function(t){t&&t.parent!=this&&(t.parent&&t.parent.removeNode(t),t.parent=this,this.children.push(t),this._renderer&&t._setRenderer(this._renderer))}},{key:"removeNode",value:function(t){var e=this.children.indexOf(t);e>-1&&(this.children.splice(e,1),t.parent=null)}},{key:"clearNodes",value:function(){var t=!0,e=!1,r=void 0;try{for(var n,i=this.children[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){n.value.parent=null}}catch(t){e=!0,r=t}finally{try{!t&&i.return&&i.return()}finally{if(e)throw r}}this.children=[]}},{key:"setMatrixDirty",value:function(){if(!this._dirtyWorldMatrix){this._dirtyWorldMatrix=!0;var t=!0,e=!1,r=void 0;try{for(var n,i=this.children[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){n.value.setMatrixDirty()}}catch(t){e=!0,r=t}finally{try{!t&&i.return&&i.return()}finally{if(e)throw r}}}}},{key:"_updateLocalMatrix",value:function(){return this._matrix||(this._matrix=o.mat4.create()),this._dirtyTRS&&(this._dirtyTRS=!1,o.mat4.fromRotationTranslationScale(this._matrix,this._rotation||u,this._translation||a,this._scale||s)),this._matrix}},{key:"waitForComplete",value:function(){var t=this,e=[],r=!0,n=!1,i=void 0;try{for(var o,a=this.children[Symbol.iterator]();!(r=(o=a.next()).done);r=!0){var u=o.value;e.push(u.waitForComplete())}}catch(t){n=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(n)throw i}}if(this._renderPrimitives){var s=!0,c=!1,f=void 0;try{for(var l,h=this._renderPrimitives[Symbol.iterator]();!(s=(l=h.next()).done);s=!0){var d=l.value;e.push(d.waitForComplete())}}catch(t){c=!0,f=t}finally{try{!s&&h.return&&h.return()}finally{if(c)throw f}}}return Promise.all(e).then(function(){return t})}},{key:"addRenderPrimitive",value:function(t){this._renderPrimitives?this._renderPrimitives.push(t):this._renderPrimitives=[t],t._instances.push(this)}},{key:"removeRenderPrimitive",value:function(t){if(this._renderPrimitives){var e=this._renderPrimitives._instances.indexOf(t);e>-1&&(this._renderPrimitives._instances.splice(e,1),(e=t._instances.indexOf(this))>-1&&t._instances.splice(e,1),this._renderPrimitives.length||(this._renderPrimitives=null))}}},{key:"clearRenderPrimitives",value:function(){if(this._renderPrimitives){var t=!0,e=!1,r=void 0;try{for(var n,i=this._renderPrimitives[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){var o=n.value,a=o._instances.indexOf(this);a>-1&&o._instances.splice(a,1)}}catch(t){e=!0,r=t}finally{try{!t&&i.return&&i.return()}finally{if(e)throw r}}this._renderPrimitives=null}}},{key:"_hitTestSelectableNode",value:function(t){if(this._renderPrimitives){var e=null,r=!0,n=!1,a=void 0;try{for(var u,s=this._renderPrimitives[Symbol.iterator]();!(r=(u=s.next()).done);r=!0){var f=u.value;if(f._min){e||(o.mat4.invert(c,this.worldMatrix),o.mat4.multiply(c,c,t.transformMatrix),e=new i.Ray(c));var l=e.intersectsAABB(f._min,f._max);if(l)return o.vec3.transformMat4(l,l,this.worldMatrix),l}}}catch(t){n=!0,a=t}finally{try{!r&&s.return&&s.return()}finally{if(n)throw a}}}var h=!0,d=!1,v=void 0;try{for(var _,m=this.children[Symbol.iterator]();!(h=(_=m.next()).done);h=!0){var p=_.value._hitTestSelectableNode(t);if(p)return p}}catch(t){d=!0,v=t}finally{try{!h&&m.return&&m.return()}finally{if(d)throw v}}return null}},{key:"hitTest",value:function(t){if(this.selectable&&this.visible){var e=this._hitTestSelectableNode(t);if(e){var r=o.vec3.fromValues(t.origin.x,t.origin.y,t.origin.z);return{node:this,intersection:e,distance:o.vec3.distance(r,e)}}return null}var n=null,i=!0,a=!1,u=void 0;try{for(var s,c=this.children[Symbol.iterator]();!(i=(s=c.next()).done);i=!0){var f=s.value.hitTest(t);f&&(!n||n.distance>f.distance)&&(n=f)}}catch(t){a=!0,u=t}finally{try{!i&&c.return&&c.return()}finally{if(a)throw u}}return n}},{key:"onSelect",value:function(t){this._selectHandler=t}},{key:"handleSelect",value:function(){this._selectHandler&&this._selectHandler()}},{key:"onHoverStart",value:function(){}},{key:"onHoverEnd",value:function(){}},{key:"_update",value:function(t,e){this.onUpdate(t,e);var r=!0,n=!1,i=void 0;try{for(var o,a=this.children[Symbol.iterator]();!(r=(o=a.next()).done);r=!0){o.value._update(t,e)}}catch(t){n=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(n)throw i}}}},{key:"onUpdate",value:function(t,e){}},{key:"matrix",set:function(t){t?(this._matrix||(this._matrix=o.mat4.create()),o.mat4.copy(this._matrix,t)):this._matrix=null,this.setMatrixDirty(),this._dirtyTRS=!1,this._translation=null,this._rotation=null,this._scale=null},get:function(){return this.setMatrixDirty(),this._updateLocalMatrix()}},{key:"worldMatrix",get:function(){return this._worldMatrix||(this._dirtyWorldMatrix=!0,this._worldMatrix=o.mat4.create()),(this._dirtyWorldMatrix||this._dirtyTRS)&&(this.parent?o.mat4.mul(this._worldMatrix,this.parent.worldMatrix,this._updateLocalMatrix()):o.mat4.copy(this._worldMatrix,this._updateLocalMatrix()),this._dirtyWorldMatrix=!1),this._worldMatrix}},{key:"translation",set:function(t){null!=t&&(this._dirtyTRS=!0,this.setMatrixDirty()),this._translation=t},get:function(){return this._dirtyTRS=!0,this.setMatrixDirty(),this._translation||(this._translation=o.vec3.clone(a)),this._translation}},{key:"rotation",set:function(t){null!=t&&(this._dirtyTRS=!0,this.setMatrixDirty()),this._rotation=t},get:function(){return this._dirtyTRS=!0,this.setMatrixDirty(),this._rotation||(this._rotation=o.quat.clone(u)),this._rotation}},{key:"scale",set:function(t){null!=t&&(this._dirtyTRS=!0,this.setMatrixDirty()),this._scale=t},get:function(){return this._dirtyTRS=!0,this.setMatrixDirty(),this._scale||(this._scale=o.vec3.clone(s)),this._scale}},{key:"renderPrimitives",get:function(){return this._renderPrimitives}},{key:"selectHandler",get:function(){return this._selectHandler}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}e.stateToBlendFunc=c;var o=WebGLRenderingContext,a=e.CAP={CULL_FACE:1,BLEND:2,DEPTH_TEST:4,STENCIL_TEST:8,COLOR_MASK:16,DEPTH_MASK:32,STENCIL_MASK:64},u=e.MAT_STATE={CAPS_RANGE:255,BLEND_SRC_SHIFT:8,BLEND_SRC_RANGE:3840,BLEND_DST_SHIFT:12,BLEND_DST_RANGE:61440,BLEND_FUNC_RANGE:65280,DEPTH_FUNC_SHIFT:16,DEPTH_FUNC_RANGE:983040},s=e.RENDER_ORDER={OPAQUE:0,SKY:1,TRANSPARENT:2,ADDITIVE:3,DEFAULT:4};function c(t,e,r){var n=(t&e)>>r;switch(n){case 0:case 1:return n;default:return n-2+o.SRC_COLOR}}var f=e.MaterialState=function(){function t(){i(this,t),this._state=a.CULL_FACE|a.DEPTH_TEST|a.COLOR_MASK|a.DEPTH_MASK,this.blendFuncSrc=o.SRC_ALPHA,this.blendFuncDst=o.ONE_MINUS_SRC_ALPHA,this.depthFunc=o.LESS}return n(t,[{key:"cullFace",get:function(){return!!(this._state&a.CULL_FACE)},set:function(t){t?this._state|=a.CULL_FACE:this._state&=~a.CULL_FACE}},{key:"blend",get:function(){return!!(this._state&a.BLEND)},set:function(t){t?this._state|=a.BLEND:this._state&=~a.BLEND}},{key:"depthTest",get:function(){return!!(this._state&a.DEPTH_TEST)},set:function(t){t?this._state|=a.DEPTH_TEST:this._state&=~a.DEPTH_TEST}},{key:"stencilTest",get:function(){return!!(this._state&a.STENCIL_TEST)},set:function(t){t?this._state|=a.STENCIL_TEST:this._state&=~a.STENCIL_TEST}},{key:"colorMask",get:function(){return!!(this._state&a.COLOR_MASK)},set:function(t){t?this._state|=a.COLOR_MASK:this._state&=~a.COLOR_MASK}},{key:"depthMask",get:function(){return!!(this._state&a.DEPTH_MASK)},set:function(t){t?this._state|=a.DEPTH_MASK:this._state&=~a.DEPTH_MASK}},{key:"depthFunc",get:function(){return((this._state&u.DEPTH_FUNC_RANGE)>>u.DEPTH_FUNC_SHIFT)+o.NEVER},set:function(t){t-=o.NEVER,this._state&=~u.DEPTH_FUNC_RANGE,this._state|=t<<u.DEPTH_FUNC_SHIFT}},{key:"stencilMask",get:function(){return!!(this._state&a.STENCIL_MASK)},set:function(t){t?this._state|=a.STENCIL_MASK:this._state&=~a.STENCIL_MASK}},{key:"blendFuncSrc",get:function(){return c(this._state,u.BLEND_SRC_RANGE,u.BLEND_SRC_SHIFT)},set:function(t){switch(t){case 0:case 1:break;default:t=t-o.SRC_COLOR+2}this._state&=~u.BLEND_SRC_RANGE,this._state|=t<<u.BLEND_SRC_SHIFT}},{key:"blendFuncDst",get:function(){return c(this._state,u.BLEND_DST_RANGE,u.BLEND_DST_SHIFT)},set:function(t){switch(t){case 0:case 1:break;default:t=t-o.SRC_COLOR+2}this._state&=~u.BLEND_DST_RANGE,this._state|=t<<u.BLEND_DST_SHIFT}}]),t}(),l=function(){function t(e){i(this,t),this._uniformName=e,this._texture=null}return n(t,[{key:"texture",get:function(){return this._texture},set:function(t){this._texture=t}}]),t}(),h=function(){function t(e,r,n){i(this,t),this._uniformName=e,this._value=r,this._length=n,this._length||(r instanceof Array?this._length=r.length:this._length=1)}return n(t,[{key:"value",get:function(){return this._value},set:function(t){this._value=t}}]),t}();e.Material=function(){function t(){i(this,t),this.state=new f,this.renderOrder=s.DEFAULT,this._samplers=[],this._uniforms=[]}return n(t,[{key:"defineSampler",value:function(t){var e=new l(t);return this._samplers.push(e),e}},{key:"defineUniform",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,n=new h(t,e,r);return this._uniforms.push(n),n}},{key:"getProgramDefines",value:function(t){return{}}},{key:"materialName",get:function(){return null}},{key:"vertexSource",get:function(){return null}},{key:"fragmentSource",get:function(){return null}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"length",function(){return a}),r.d(e,"fromValues",function(){return u}),r.d(e,"copy",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"add",function(){return f}),r.d(e,"subtract",function(){return l}),r.d(e,"multiply",function(){return h}),r.d(e,"divide",function(){return d}),r.d(e,"ceil",function(){return v}),r.d(e,"floor",function(){return _}),r.d(e,"min",function(){return m}),r.d(e,"max",function(){return p}),r.d(e,"round",function(){return y}),r.d(e,"scale",function(){return b}),r.d(e,"scaleAndAdd",function(){return g}),r.d(e,"distance",function(){return M}),r.d(e,"squaredDistance",function(){return x}),r.d(e,"squaredLength",function(){return T}),r.d(e,"negate",function(){return w}),r.d(e,"inverse",function(){return E}),r.d(e,"normalize",function(){return O}),r.d(e,"dot",function(){return R}),r.d(e,"cross",function(){return P}),r.d(e,"lerp",function(){return S}),r.d(e,"hermite",function(){return A}),r.d(e,"bezier",function(){return N}),r.d(e,"random",function(){return C}),r.d(e,"transformMat4",function(){return I}),r.d(e,"transformMat3",function(){return k}),r.d(e,"transformQuat",function(){return L}),r.d(e,"rotateX",function(){return F}),r.d(e,"rotateY",function(){return D}),r.d(e,"rotateZ",function(){return B}),r.d(e,"angle",function(){return j}),r.d(e,"str",function(){return U}),r.d(e,"exactEquals",function(){return V}),r.d(e,"equals",function(){return Y}),r.d(e,"sub",function(){return G}),r.d(e,"mul",function(){return H}),r.d(e,"div",function(){return q}),r.d(e,"dist",function(){return X}),r.d(e,"sqrDist",function(){return W}),r.d(e,"len",function(){return K}),r.d(e,"sqrLen",function(){return z}),r.d(e,"forEach",function(){return Q});var n=r(0);function i(){let t=new n.ARRAY_TYPE(3);return t[0]=0,t[1]=0,t[2]=0,t}function o(t){var e=new n.ARRAY_TYPE(3);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e}function a(t){let e=t[0],r=t[1],n=t[2];return Math.sqrt(e*e+r*r+n*n)}function u(t,e,r){let i=new n.ARRAY_TYPE(3);return i[0]=t,i[1]=e,i[2]=r,i}function s(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t}function c(t,e,r,n){return t[0]=e,t[1]=r,t[2]=n,t}function f(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t}function l(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t}function h(t,e,r){return t[0]=e[0]*r[0],t[1]=e[1]*r[1],t[2]=e[2]*r[2],t}function d(t,e,r){return t[0]=e[0]/r[0],t[1]=e[1]/r[1],t[2]=e[2]/r[2],t}function v(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2]),t}function _(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2]),t}function m(t,e,r){return t[0]=Math.min(e[0],r[0]),t[1]=Math.min(e[1],r[1]),t[2]=Math.min(e[2],r[2]),t}function p(t,e,r){return t[0]=Math.max(e[0],r[0]),t[1]=Math.max(e[1],r[1]),t[2]=Math.max(e[2],r[2]),t}function y(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t[2]=Math.round(e[2]),t}function b(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t}function g(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t}function M(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2];return Math.sqrt(r*r+n*n+i*i)}function x(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2];return r*r+n*n+i*i}function T(t){let e=t[0],r=t[1],n=t[2];return e*e+r*r+n*n}function w(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t}function E(t,e){return t[0]=1/e[0],t[1]=1/e[1],t[2]=1/e[2],t}function O(t,e){let r=e[0],n=e[1],i=e[2],o=r*r+n*n+i*i;return o>0&&(o=1/Math.sqrt(o),t[0]=e[0]*o,t[1]=e[1]*o,t[2]=e[2]*o),t}function R(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function P(t,e,r){let n=e[0],i=e[1],o=e[2],a=r[0],u=r[1],s=r[2];return t[0]=i*s-o*u,t[1]=o*a-n*s,t[2]=n*u-i*a,t}function S(t,e,r,n){let i=e[0],o=e[1],a=e[2];return t[0]=i+n*(r[0]-i),t[1]=o+n*(r[1]-o),t[2]=a+n*(r[2]-a),t}function A(t,e,r,n,i,o){let a=o*o,u=a*(2*o-3)+1,s=a*(o-2)+o,c=a*(o-1),f=a*(3-2*o);return t[0]=e[0]*u+r[0]*s+n[0]*c+i[0]*f,t[1]=e[1]*u+r[1]*s+n[1]*c+i[1]*f,t[2]=e[2]*u+r[2]*s+n[2]*c+i[2]*f,t}function N(t,e,r,n,i,o){let a=1-o,u=a*a,s=o*o,c=u*a,f=3*o*u,l=3*s*a,h=s*o;return t[0]=e[0]*c+r[0]*f+n[0]*l+i[0]*h,t[1]=e[1]*c+r[1]*f+n[1]*l+i[1]*h,t[2]=e[2]*c+r[2]*f+n[2]*l+i[2]*h,t}function C(t,e){e=e||1;let r=2*n.RANDOM()*Math.PI,i=2*n.RANDOM()-1,o=Math.sqrt(1-i*i)*e;return t[0]=Math.cos(r)*o,t[1]=Math.sin(r)*o,t[2]=i*e,t}function I(t,e,r){let n=e[0],i=e[1],o=e[2],a=r[3]*n+r[7]*i+r[11]*o+r[15];return a=a||1,t[0]=(r[0]*n+r[4]*i+r[8]*o+r[12])/a,t[1]=(r[1]*n+r[5]*i+r[9]*o+r[13])/a,t[2]=(r[2]*n+r[6]*i+r[10]*o+r[14])/a,t}function k(t,e,r){let n=e[0],i=e[1],o=e[2];return t[0]=n*r[0]+i*r[3]+o*r[6],t[1]=n*r[1]+i*r[4]+o*r[7],t[2]=n*r[2]+i*r[5]+o*r[8],t}function L(t,e,r){let n=r[0],i=r[1],o=r[2],a=r[3],u=e[0],s=e[1],c=e[2],f=i*c-o*s,l=o*u-n*c,h=n*s-i*u,d=i*h-o*l,v=o*f-n*h,_=n*l-i*f,m=2*a;return f*=m,l*=m,h*=m,d*=2,v*=2,_*=2,t[0]=u+f+d,t[1]=s+l+v,t[2]=c+h+_,t}function F(t,e,r,n){let i=[],o=[];return i[0]=e[0]-r[0],i[1]=e[1]-r[1],i[2]=e[2]-r[2],o[0]=i[0],o[1]=i[1]*Math.cos(n)-i[2]*Math.sin(n),o[2]=i[1]*Math.sin(n)+i[2]*Math.cos(n),t[0]=o[0]+r[0],t[1]=o[1]+r[1],t[2]=o[2]+r[2],t}function D(t,e,r,n){let i=[],o=[];return i[0]=e[0]-r[0],i[1]=e[1]-r[1],i[2]=e[2]-r[2],o[0]=i[2]*Math.sin(n)+i[0]*Math.cos(n),o[1]=i[1],o[2]=i[2]*Math.cos(n)-i[0]*Math.sin(n),t[0]=o[0]+r[0],t[1]=o[1]+r[1],t[2]=o[2]+r[2],t}function B(t,e,r,n){let i=[],o=[];return i[0]=e[0]-r[0],i[1]=e[1]-r[1],i[2]=e[2]-r[2],o[0]=i[0]*Math.cos(n)-i[1]*Math.sin(n),o[1]=i[0]*Math.sin(n)+i[1]*Math.cos(n),o[2]=i[2],t[0]=o[0]+r[0],t[1]=o[1]+r[1],t[2]=o[2]+r[2],t}function j(t,e){let r=u(t[0],t[1],t[2]),n=u(e[0],e[1],e[2]);O(r,r),O(n,n);let i=R(r,n);return i>1?0:i<-1?Math.PI:Math.acos(i)}function U(t){return"vec3("+t[0]+", "+t[1]+", "+t[2]+")"}function V(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]}function Y(t,e){let r=t[0],i=t[1],o=t[2],a=e[0],u=e[1],s=e[2];return Math.abs(r-a)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(a))&&Math.abs(i-u)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(u))&&Math.abs(o-s)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(s))}const G=l,H=h,q=d,X=M,W=x,K=a,z=T,Q=function(){let t=i();return function(e,r,n,i,o,a){let u,s;for(r||(r=3),n||(n=0),s=i?Math.min(i*r+n,e.length):e.length,u=n;u<s;u+=r)t[0]=e[u],t[1]=e[u+1],t[2]=e[u+2],o(t,t,a),e[u]=t[0],e[u+1]=t[1],e[u+2]=t[2];return e}}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return u}),r.d(e,"identity",function(){return s}),r.d(e,"setAxisAngle",function(){return c}),r.d(e,"getAxisAngle",function(){return f}),r.d(e,"multiply",function(){return l}),r.d(e,"rotateX",function(){return h}),r.d(e,"rotateY",function(){return d}),r.d(e,"rotateZ",function(){return v}),r.d(e,"calculateW",function(){return _}),r.d(e,"slerp",function(){return m}),r.d(e,"invert",function(){return p}),r.d(e,"conjugate",function(){return y}),r.d(e,"fromMat3",function(){return b}),r.d(e,"fromEuler",function(){return g}),r.d(e,"str",function(){return M}),r.d(e,"clone",function(){return x}),r.d(e,"fromValues",function(){return T}),r.d(e,"copy",function(){return w}),r.d(e,"set",function(){return E}),r.d(e,"add",function(){return O}),r.d(e,"mul",function(){return R}),r.d(e,"scale",function(){return P}),r.d(e,"dot",function(){return S}),r.d(e,"lerp",function(){return A}),r.d(e,"length",function(){return N}),r.d(e,"len",function(){return C}),r.d(e,"squaredLength",function(){return I}),r.d(e,"sqrLen",function(){return k}),r.d(e,"normalize",function(){return L}),r.d(e,"exactEquals",function(){return F}),r.d(e,"equals",function(){return D}),r.d(e,"rotationTo",function(){return B}),r.d(e,"sqlerp",function(){return j}),r.d(e,"setAxes",function(){return U});var n=r(0),i=r(12),o=r(4),a=r(1);function u(){let t=new n.ARRAY_TYPE(4);return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t}function s(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t}function c(t,e,r){r*=.5;let n=Math.sin(r);return t[0]=n*e[0],t[1]=n*e[1],t[2]=n*e[2],t[3]=Math.cos(r),t}function f(t,e){let r=2*Math.acos(e[3]),n=Math.sin(r/2);return 0!=n?(t[0]=e[0]/n,t[1]=e[1]/n,t[2]=e[2]/n):(t[0]=1,t[1]=0,t[2]=0),r}function l(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1],c=r[2],f=r[3];return t[0]=n*f+a*u+i*c-o*s,t[1]=i*f+a*s+o*u-n*c,t[2]=o*f+a*c+n*s-i*u,t[3]=a*f-n*u-i*s-o*c,t}function h(t,e,r){r*=.5;let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s+a*u,t[1]=i*s+o*u,t[2]=o*s-i*u,t[3]=a*s-n*u,t}function d(t,e,r){r*=.5;let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s-o*u,t[1]=i*s+a*u,t[2]=o*s+n*u,t[3]=a*s-i*u,t}function v(t,e,r){r*=.5;let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s+i*u,t[1]=i*s-n*u,t[2]=o*s+a*u,t[3]=a*s-o*u,t}function _(t,e){let r=e[0],n=e[1],i=e[2];return t[0]=r,t[1]=n,t[2]=i,t[3]=Math.sqrt(Math.abs(1-r*r-n*n-i*i)),t}function m(t,e,r,n){let i,o,a,u,s,c=e[0],f=e[1],l=e[2],h=e[3],d=r[0],v=r[1],_=r[2],m=r[3];return(o=c*d+f*v+l*_+h*m)<0&&(o=-o,d=-d,v=-v,_=-_,m=-m),1-o>1e-6?(i=Math.acos(o),a=Math.sin(i),u=Math.sin((1-n)*i)/a,s=Math.sin(n*i)/a):(u=1-n,s=n),t[0]=u*c+s*d,t[1]=u*f+s*v,t[2]=u*l+s*_,t[3]=u*h+s*m,t}function p(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r*r+n*n+i*i+o*o,u=a?1/a:0;return t[0]=-r*u,t[1]=-n*u,t[2]=-i*u,t[3]=o*u,t}function y(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=e[3],t}function b(t,e){let r,n=e[0]+e[4]+e[8];if(n>0)r=Math.sqrt(n+1),t[3]=.5*r,r=.5/r,t[0]=(e[5]-e[7])*r,t[1]=(e[6]-e[2])*r,t[2]=(e[1]-e[3])*r;else{let n=0;e[4]>e[0]&&(n=1),e[8]>e[3*n+n]&&(n=2);let i=(n+1)%3,o=(n+2)%3;r=Math.sqrt(e[3*n+n]-e[3*i+i]-e[3*o+o]+1),t[n]=.5*r,r=.5/r,t[3]=(e[3*i+o]-e[3*o+i])*r,t[i]=(e[3*i+n]+e[3*n+i])*r,t[o]=(e[3*o+n]+e[3*n+o])*r}return t}function g(t,e,r,n){let i=.5*Math.PI/180;e*=i,r*=i,n*=i;let o=Math.sin(e),a=Math.cos(e),u=Math.sin(r),s=Math.cos(r),c=Math.sin(n),f=Math.cos(n);return t[0]=o*s*f-a*u*c,t[1]=a*u*f+o*s*c,t[2]=a*s*c-o*u*f,t[3]=a*s*f+o*u*c,t}function M(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}const x=a.clone,T=a.fromValues,w=a.copy,E=a.set,O=a.add,R=l,P=a.scale,S=a.dot,A=a.lerp,N=a.length,C=N,I=a.squaredLength,k=I,L=a.normalize,F=a.exactEquals,D=a.equals,B=function(){let t=o.create(),e=o.fromValues(1,0,0),r=o.fromValues(0,1,0);return function(n,i,a){let u=o.dot(i,a);return u<-.999999?(o.cross(t,e,i),o.len(t)<1e-6&&o.cross(t,r,i),o.normalize(t,t),c(n,t,Math.PI),n):u>.999999?(n[0]=0,n[1]=0,n[2]=0,n[3]=1,n):(o.cross(t,i,a),n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=1+u,L(n,n))}}(),j=function(){let t=u(),e=u();return function(r,n,i,o,a,u){return m(t,n,a,u),m(e,i,o,u),m(r,t,e,2*u*(1-u)),r}}(),U=function(){let t=i.create();return function(e,r,n,i){return t[0]=n[0],t[3]=n[1],t[6]=n[2],t[1]=i[0],t[4]=i[1],t[7]=i[2],t[2]=-r[0],t[5]=-r[1],t[8]=-r[2],L(e,b(e,t))}}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.vec4=e.vec3=e.vec2=e.quat2=e.quat=e.mat4=e.mat3=e.mat2d=e.mat2=e.glMatrix=void 0;var n=d(r(0)),i=d(r(33)),o=d(r(32)),a=d(r(12)),u=d(r(10)),s=d(r(5)),c=d(r(31)),f=d(r(30)),l=d(r(4)),h=d(r(1));function d(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e.default=t,e}e.glMatrix=n,e.mat2=i,e.mat2d=o,e.mat3=a,e.mat4=u,e.quat=s,e.quat2=c,e.vec2=f,e.vec3=l,e.vec4=h},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Primitive=e.PrimitiveAttribute=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(6);function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}e.PrimitiveAttribute=function t(e,r,n,i,a,u){o(this,t),this.name=e,this.buffer=r,this.componentCount=n||3,this.componentType=i||5126,this.stride=a||0,this.byteOffset=u||0,this.normalized=!1},e.Primitive=function(){function t(e,r,n){o(this,t),this.attributes=e||[],this.elementCount=r||0,this.mode=n||4,this.indexBuffer=null,this.indexByteOffset=0,this.indexType=0,this._min=null,this._max=null}return n(t,[{key:"setIndexBuffer",value:function(t,e,r){this.indexBuffer=t,this.indexByteOffset=e||0,this.indexType=r||5123}},{key:"setBounds",value:function(t,e){this._min=i.vec3.clone(t),this._max=i.vec3.clone(e)}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function o(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var u=WebGLRenderingContext,s=e.TextureSampler=function t(){a(this,t),this.minFilter=null,this.magFilter=null,this.wrapS=null,this.wrapT=null},c=e.Texture=function(){function t(){a(this,t),this.sampler=new s,this.mipmap=!0}return n(t,[{key:"format",get:function(){return u.RGBA}},{key:"width",get:function(){return 0}},{key:"height",get:function(){return 0}},{key:"textureKey",get:function(){return null}}]),t}(),f=e.ImageTexture=function(t){function e(t){a(this,e);var r=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._img=t,r._imgBitmap=null,t.src&&t.complete?t.naturalWidth?r._promise=r._finishImage():r._promise=Promise.reject("Image provided had failed to load."):r._promise=new Promise(function(e,n){t.addEventListener("load",function(){return e(r._finishImage())}),t.addEventListener("error",n)}),r}return o(e,c),n(e,[{key:"_finishImage",value:function(){var t=this;return window.createImageBitmap?window.createImageBitmap(this._img).then(function(e){return t._imgBitmap=e,Promise.resolve(t)}):Promise.resolve(this)}},{key:"waitForComplete",value:function(){return this._promise}},{key:"format",get:function(){return u.RGBA}},{key:"width",get:function(){return this._img.width}},{key:"height",get:function(){return this._img.height}},{key:"textureKey",get:function(){return this._img.src}},{key:"source",get:function(){return this._imgBitmap||this._img}}]),e}(),l=(e.UrlTexture=function(t){function e(t){a(this,e);var r=new Image,n=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,r));return r.src=t,n}return o(e,f),e}(),e.BlobTexture=function(t){function e(t){a(this,e);var r=new Image,n=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,r));return r.src=window.URL.createObjectURL(t),n}return o(e,f),e}(),e.VideoTexture=function(t){function e(t){a(this,e);var r=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._video=t,t.readyState>=2?r._promise=Promise.resolve(r):t.error?r._promise=Promise.reject(t.error):r._promise=new Promise(function(e,n){t.addEventListener("loadeddata",function(){return e(r)}),t.addEventListener("error",n)}),r}return o(e,c),n(e,[{key:"waitForComplete",value:function(){return this._promise}},{key:"format",get:function(){return u.RGBA}},{key:"width",get:function(){return this._video.videoWidth}},{key:"height",get:function(){return this._video.videoHeight}},{key:"textureKey",get:function(){return this._video.src}},{key:"source",get:function(){return this._video}}]),e}(),0),h=e.DataTexture=function(t){function e(t,r,n){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:u.RGBA,s=arguments.length>4&&void 0!==arguments[4]?arguments[4]:u.UNSIGNED_BYTE;a(this,e);var c=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return c._data=t,c._width=r,c._height=n,c._format=o,c._type=s,c._key="DATA_"+l,l++,c}return o(e,c),n(e,[{key:"format",get:function(){return this._format}},{key:"width",get:function(){return this._width}},{key:"height",get:function(){return this._height}},{key:"textureKey",get:function(){return this._key}}]),e}();e.ColorTexture=function(t){function e(t,r,n,o){a(this,e);var u=new Uint8Array([255*t,255*r,255*n,255*o]),s=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,u,1,1));return s.mipmap=!1,s._key="COLOR_"+u[0]+"_"+u[1]+"_"+u[2]+"_"+u[3],s}return o(e,h),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.GeometryBuilderBase=e.PrimitiveStream=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(7),o=r(6);function a(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var u=WebGLRenderingContext,s=o.vec3.create(),c=e.PrimitiveStream=function(){function t(e){a(this,t),this._vertices=[],this._indices=[],this._geometryStarted=!1,this._vertexOffset=0,this._vertexIndex=0,this._highIndex=0,this._flipWinding=!1,this._invertNormals=!1,this._transform=null,this._normalTransform=null,this._min=null,this._max=null}return n(t,[{key:"startGeometry",value:function(){if(this._geometryStarted)throw new Error("Attempted to start a new geometry before the previous one was ended.");this._geometryStarted=!0,this._vertexIndex=0,this._highIndex=0}},{key:"endGeometry",value:function(){if(!this._geometryStarted)throw new Error("Attempted to end a geometry before one was started.");if(this._highIndex>=this._vertexIndex)throw new Error("Geometry contains indices that are out of bounds.\n (Contains an index of "+this._highIndex+" when the vertex count is "+this._vertexIndex+")");this._geometryStarted=!1,this._vertexOffset+=this._vertexIndex}},{key:"pushVertex",value:function(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0,a=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,u=arguments.length>6&&void 0!==arguments[6]?arguments[6]:0,c=arguments.length>7&&void 0!==arguments[7]?arguments[7]:1;if(!this._geometryStarted)throw new Error("Cannot push vertices before calling startGeometry().");return this._transform&&(s[0]=t,s[1]=e,s[2]=r,o.vec3.transformMat4(s,s,this._transform),t=s[0],e=s[1],r=s[2],s[0]=a,s[1]=u,s[2]=c,o.vec3.transformMat3(s,s,this._normalTransform),a=s[0],u=s[1],c=s[2]),this._invertNormals&&(a*=-1,u*=-1,c*=-1),this._vertices.push(t,e,r,n,i,a,u,c),this._min?(this._min[0]=Math.min(this._min[0],t),this._min[1]=Math.min(this._min[1],e),this._min[2]=Math.min(this._min[2],r),this._max[0]=Math.max(this._max[0],t),this._max[1]=Math.max(this._max[1],e),this._max[2]=Math.max(this._max[2],r)):(this._min=o.vec3.fromValues(t,e,r),this._max=o.vec3.fromValues(t,e,r)),this._vertexIndex++}},{key:"pushTriangle",value:function(t,e,r){if(!this._geometryStarted)throw new Error("Cannot push triangles before calling startGeometry().");this._highIndex=Math.max(this._highIndex,t,e,r),t+=this._vertexOffset,e+=this._vertexOffset,r+=this._vertexOffset,this._flipWinding?this._indices.push(r,e,t):this._indices.push(t,e,r)}},{key:"clear",value:function(){if(this._geometryStarted)throw new Error("Cannot clear before ending the current geometry.");this._vertices=[],this._indices=[],this._vertexOffset=0,this._min=null,this._max=null}},{key:"finishPrimitive",value:function(t){if(!this._vertexOffset)throw new Error("Attempted to call finishPrimitive() before creating any geometry.");var e=t.createRenderBuffer(u.ARRAY_BUFFER,new Float32Array(this._vertices)),r=t.createRenderBuffer(u.ELEMENT_ARRAY_BUFFER,new Uint16Array(this._indices)),n=[new i.PrimitiveAttribute("POSITION",e,3,u.FLOAT,32,0),new i.PrimitiveAttribute("TEXCOORD_0",e,2,u.FLOAT,32,12),new i.PrimitiveAttribute("NORMAL",e,3,u.FLOAT,32,20)],o=new i.Primitive(n,this._indices.length);return o.setIndexBuffer(r),o.setBounds(this._min,this._max),o}},{key:"flipWinding",set:function(t){if(this._geometryStarted)throw new Error("Cannot change flipWinding before ending the current geometry.");this._flipWinding=t},get:function(){this._flipWinding}},{key:"invertNormals",set:function(t){if(this._geometryStarted)throw new Error("Cannot change invertNormals before ending the current geometry.");this._invertNormals=t},get:function(){this._invertNormals}},{key:"transform",set:function(t){if(this._geometryStarted)throw new Error("Cannot change transform before ending the current geometry.");this._transform=t,this._transform&&(this._normalTransform||(this._normalTransform=o.mat3.create()),o.mat3.fromMat4(this._normalTransform,this._transform))},get:function(){this._transform}},{key:"nextVertexIndex",get:function(){return this._vertexIndex}}]),t}();e.GeometryBuilderBase=function(){function t(e){a(this,t),this._stream=e||new c}return n(t,[{key:"finishPrimitive",value:function(t){return this._stream.finishPrimitive(t)}},{key:"clear",value:function(){this._stream.clear()}},{key:"primitiveStream",set:function(t){this._stream=t},get:function(){return this._stream}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"copy",function(){return a}),r.d(e,"fromValues",function(){return u}),r.d(e,"set",function(){return s}),r.d(e,"identity",function(){return c}),r.d(e,"transpose",function(){return f}),r.d(e,"invert",function(){return l}),r.d(e,"adjoint",function(){return h}),r.d(e,"determinant",function(){return d}),r.d(e,"multiply",function(){return v}),r.d(e,"translate",function(){return _}),r.d(e,"scale",function(){return m}),r.d(e,"rotate",function(){return p}),r.d(e,"rotateX",function(){return y}),r.d(e,"rotateY",function(){return b}),r.d(e,"rotateZ",function(){return g}),r.d(e,"fromTranslation",function(){return M}),r.d(e,"fromScaling",function(){return x}),r.d(e,"fromRotation",function(){return T}),r.d(e,"fromXRotation",function(){return w}),r.d(e,"fromYRotation",function(){return E}),r.d(e,"fromZRotation",function(){return O}),r.d(e,"fromRotationTranslation",function(){return R}),r.d(e,"fromQuat2",function(){return P}),r.d(e,"getTranslation",function(){return S}),r.d(e,"getScaling",function(){return A}),r.d(e,"getRotation",function(){return N}),r.d(e,"fromRotationTranslationScale",function(){return C}),r.d(e,"fromRotationTranslationScaleOrigin",function(){return I}),r.d(e,"fromQuat",function(){return k}),r.d(e,"frustum",function(){return L}),r.d(e,"perspective",function(){return F}),r.d(e,"perspectiveFromFieldOfView",function(){return D}),r.d(e,"ortho",function(){return B}),r.d(e,"lookAt",function(){return j}),r.d(e,"targetTo",function(){return U}),r.d(e,"str",function(){return V}),r.d(e,"frob",function(){return Y}),r.d(e,"add",function(){return G}),r.d(e,"subtract",function(){return H}),r.d(e,"multiplyScalar",function(){return q}),r.d(e,"multiplyScalarAndAdd",function(){return X}),r.d(e,"exactEquals",function(){return W}),r.d(e,"equals",function(){return K}),r.d(e,"mul",function(){return z}),r.d(e,"sub",function(){return Q});var n=r(0);function i(){let t=new n.ARRAY_TYPE(16);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function o(t){let e=new n.ARRAY_TYPE(16);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e[9]=t[9],e[10]=t[10],e[11]=t[11],e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15],e}function a(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t}function u(t,e,r,i,o,a,u,s,c,f,l,h,d,v,_,m){let p=new n.ARRAY_TYPE(16);return p[0]=t,p[1]=e,p[2]=r,p[3]=i,p[4]=o,p[5]=a,p[6]=u,p[7]=s,p[8]=c,p[9]=f,p[10]=l,p[11]=h,p[12]=d,p[13]=v,p[14]=_,p[15]=m,p}function s(t,e,r,n,i,o,a,u,s,c,f,l,h,d,v,_,m){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t[6]=u,t[7]=s,t[8]=c,t[9]=f,t[10]=l,t[11]=h,t[12]=d,t[13]=v,t[14]=_,t[15]=m,t}function c(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function f(t,e){if(t===e){let r=e[1],n=e[2],i=e[3],o=e[6],a=e[7],u=e[11];t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=r,t[6]=e[9],t[7]=e[13],t[8]=n,t[9]=o,t[11]=e[14],t[12]=i,t[13]=a,t[14]=u}else t[0]=e[0],t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=e[1],t[5]=e[5],t[6]=e[9],t[7]=e[13],t[8]=e[2],t[9]=e[6],t[10]=e[10],t[11]=e[14],t[12]=e[3],t[13]=e[7],t[14]=e[11],t[15]=e[15];return t}function l(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=e[9],h=e[10],d=e[11],v=e[12],_=e[13],m=e[14],p=e[15],y=r*u-n*a,b=r*s-i*a,g=r*c-o*a,M=n*s-i*u,x=n*c-o*u,T=i*c-o*s,w=f*_-l*v,E=f*m-h*v,O=f*p-d*v,R=l*m-h*_,P=l*p-d*_,S=h*p-d*m,A=y*S-b*P+g*R+M*O-x*E+T*w;return A?(A=1/A,t[0]=(u*S-s*P+c*R)*A,t[1]=(i*P-n*S-o*R)*A,t[2]=(_*T-m*x+p*M)*A,t[3]=(h*x-l*T-d*M)*A,t[4]=(s*O-a*S-c*E)*A,t[5]=(r*S-i*O+o*E)*A,t[6]=(m*g-v*T-p*b)*A,t[7]=(f*T-h*g+d*b)*A,t[8]=(a*P-u*O+c*w)*A,t[9]=(n*O-r*P-o*w)*A,t[10]=(v*x-_*g+p*y)*A,t[11]=(l*g-f*x-d*y)*A,t[12]=(u*E-a*R-s*w)*A,t[13]=(r*R-n*E+i*w)*A,t[14]=(_*b-v*M-m*y)*A,t[15]=(f*M-l*b+h*y)*A,t):null}function h(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=e[9],h=e[10],d=e[11],v=e[12],_=e[13],m=e[14],p=e[15];return t[0]=u*(h*p-d*m)-l*(s*p-c*m)+_*(s*d-c*h),t[1]=-(n*(h*p-d*m)-l*(i*p-o*m)+_*(i*d-o*h)),t[2]=n*(s*p-c*m)-u*(i*p-o*m)+_*(i*c-o*s),t[3]=-(n*(s*d-c*h)-u*(i*d-o*h)+l*(i*c-o*s)),t[4]=-(a*(h*p-d*m)-f*(s*p-c*m)+v*(s*d-c*h)),t[5]=r*(h*p-d*m)-f*(i*p-o*m)+v*(i*d-o*h),t[6]=-(r*(s*p-c*m)-a*(i*p-o*m)+v*(i*c-o*s)),t[7]=r*(s*d-c*h)-a*(i*d-o*h)+f*(i*c-o*s),t[8]=a*(l*p-d*_)-f*(u*p-c*_)+v*(u*d-c*l),t[9]=-(r*(l*p-d*_)-f*(n*p-o*_)+v*(n*d-o*l)),t[10]=r*(u*p-c*_)-a*(n*p-o*_)+v*(n*c-o*u),t[11]=-(r*(u*d-c*l)-a*(n*d-o*l)+f*(n*c-o*u)),t[12]=-(a*(l*m-h*_)-f*(u*m-s*_)+v*(u*h-s*l)),t[13]=r*(l*m-h*_)-f*(n*m-i*_)+v*(n*h-i*l),t[14]=-(r*(u*m-s*_)-a*(n*m-i*_)+v*(n*s-i*u)),t[15]=r*(u*h-s*l)-a*(n*h-i*l)+f*(n*s-i*u),t}function d(t){let e=t[0],r=t[1],n=t[2],i=t[3],o=t[4],a=t[5],u=t[6],s=t[7],c=t[8],f=t[9],l=t[10],h=t[11],d=t[12],v=t[13],_=t[14],m=t[15];return(e*a-r*o)*(l*m-h*_)-(e*u-n*o)*(f*m-h*v)+(e*s-i*o)*(f*_-l*v)+(r*u-n*a)*(c*m-h*d)-(r*s-i*a)*(c*_-l*d)+(n*s-i*u)*(c*v-f*d)}function v(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=e[9],d=e[10],v=e[11],_=e[12],m=e[13],p=e[14],y=e[15],b=r[0],g=r[1],M=r[2],x=r[3];return t[0]=b*n+g*u+M*l+x*_,t[1]=b*i+g*s+M*h+x*m,t[2]=b*o+g*c+M*d+x*p,t[3]=b*a+g*f+M*v+x*y,b=r[4],g=r[5],M=r[6],x=r[7],t[4]=b*n+g*u+M*l+x*_,t[5]=b*i+g*s+M*h+x*m,t[6]=b*o+g*c+M*d+x*p,t[7]=b*a+g*f+M*v+x*y,b=r[8],g=r[9],M=r[10],x=r[11],t[8]=b*n+g*u+M*l+x*_,t[9]=b*i+g*s+M*h+x*m,t[10]=b*o+g*c+M*d+x*p,t[11]=b*a+g*f+M*v+x*y,b=r[12],g=r[13],M=r[14],x=r[15],t[12]=b*n+g*u+M*l+x*_,t[13]=b*i+g*s+M*h+x*m,t[14]=b*o+g*c+M*d+x*p,t[15]=b*a+g*f+M*v+x*y,t}function _(t,e,r){let n,i,o,a,u,s,c,f,l,h,d,v,_=r[0],m=r[1],p=r[2];return e===t?(t[12]=e[0]*_+e[4]*m+e[8]*p+e[12],t[13]=e[1]*_+e[5]*m+e[9]*p+e[13],t[14]=e[2]*_+e[6]*m+e[10]*p+e[14],t[15]=e[3]*_+e[7]*m+e[11]*p+e[15]):(n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=e[9],d=e[10],v=e[11],t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=u,t[5]=s,t[6]=c,t[7]=f,t[8]=l,t[9]=h,t[10]=d,t[11]=v,t[12]=n*_+u*m+l*p+e[12],t[13]=i*_+s*m+h*p+e[13],t[14]=o*_+c*m+d*p+e[14],t[15]=a*_+f*m+v*p+e[15]),t}function m(t,e,r){let n=r[0],i=r[1],o=r[2];return t[0]=e[0]*n,t[1]=e[1]*n,t[2]=e[2]*n,t[3]=e[3]*n,t[4]=e[4]*i,t[5]=e[5]*i,t[6]=e[6]*i,t[7]=e[7]*i,t[8]=e[8]*o,t[9]=e[9]*o,t[10]=e[10]*o,t[11]=e[11]*o,t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t}function p(t,e,r,i){let o,a,u,s,c,f,l,h,d,v,_,m,p,y,b,g,M,x,T,w,E,O,R,P,S=i[0],A=i[1],N=i[2],C=Math.sqrt(S*S+A*A+N*N);return Math.abs(C)<n.EPSILON?null:(S*=C=1/C,A*=C,N*=C,o=Math.sin(r),u=1-(a=Math.cos(r)),s=e[0],c=e[1],f=e[2],l=e[3],h=e[4],d=e[5],v=e[6],_=e[7],m=e[8],p=e[9],y=e[10],b=e[11],g=S*S*u+a,M=A*S*u+N*o,x=N*S*u-A*o,T=S*A*u-N*o,w=A*A*u+a,E=N*A*u+S*o,O=S*N*u+A*o,R=A*N*u-S*o,P=N*N*u+a,t[0]=s*g+h*M+m*x,t[1]=c*g+d*M+p*x,t[2]=f*g+v*M+y*x,t[3]=l*g+_*M+b*x,t[4]=s*T+h*w+m*E,t[5]=c*T+d*w+p*E,t[6]=f*T+v*w+y*E,t[7]=l*T+_*w+b*E,t[8]=s*O+h*R+m*P,t[9]=c*O+d*R+p*P,t[10]=f*O+v*R+y*P,t[11]=l*O+_*R+b*P,e!==t&&(t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t)}function y(t,e,r){let n=Math.sin(r),i=Math.cos(r),o=e[4],a=e[5],u=e[6],s=e[7],c=e[8],f=e[9],l=e[10],h=e[11];return e!==t&&(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[4]=o*i+c*n,t[5]=a*i+f*n,t[6]=u*i+l*n,t[7]=s*i+h*n,t[8]=c*i-o*n,t[9]=f*i-a*n,t[10]=l*i-u*n,t[11]=h*i-s*n,t}function b(t,e,r){let n=Math.sin(r),i=Math.cos(r),o=e[0],a=e[1],u=e[2],s=e[3],c=e[8],f=e[9],l=e[10],h=e[11];return e!==t&&(t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[0]=o*i-c*n,t[1]=a*i-f*n,t[2]=u*i-l*n,t[3]=s*i-h*n,t[8]=o*n+c*i,t[9]=a*n+f*i,t[10]=u*n+l*i,t[11]=s*n+h*i,t}function g(t,e,r){let n=Math.sin(r),i=Math.cos(r),o=e[0],a=e[1],u=e[2],s=e[3],c=e[4],f=e[5],l=e[6],h=e[7];return e!==t&&(t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[0]=o*i+c*n,t[1]=a*i+f*n,t[2]=u*i+l*n,t[3]=s*i+h*n,t[4]=c*i-o*n,t[5]=f*i-a*n,t[6]=l*i-u*n,t[7]=h*i-s*n,t}function M(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=e[0],t[13]=e[1],t[14]=e[2],t[15]=1,t}function x(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=e[1],t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=e[2],t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function T(t,e,r){let i,o,a,u=r[0],s=r[1],c=r[2],f=Math.sqrt(u*u+s*s+c*c);return Math.abs(f)<n.EPSILON?null:(u*=f=1/f,s*=f,c*=f,i=Math.sin(e),a=1-(o=Math.cos(e)),t[0]=u*u*a+o,t[1]=s*u*a+c*i,t[2]=c*u*a-s*i,t[3]=0,t[4]=u*s*a-c*i,t[5]=s*s*a+o,t[6]=c*s*a+u*i,t[7]=0,t[8]=u*c*a+s*i,t[9]=s*c*a-u*i,t[10]=c*c*a+o,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t)}function w(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=n,t[6]=r,t[7]=0,t[8]=0,t[9]=-r,t[10]=n,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function E(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=0,t[2]=-r,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=r,t[9]=0,t[10]=n,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function O(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=0,t[3]=0,t[4]=-r,t[5]=n,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function R(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=n+n,s=i+i,c=o+o,f=n*u,l=n*s,h=n*c,d=i*s,v=i*c,_=o*c,m=a*u,p=a*s,y=a*c;return t[0]=1-(d+_),t[1]=l+y,t[2]=h-p,t[3]=0,t[4]=l-y,t[5]=1-(f+_),t[6]=v+m,t[7]=0,t[8]=h+p,t[9]=v-m,t[10]=1-(f+d),t[11]=0,t[12]=r[0],t[13]=r[1],t[14]=r[2],t[15]=1,t}function P(t,e){let r=new n.ARRAY_TYPE(3),i=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=i*i+o*o+a*a+u*u;return h>0?(r[0]=2*(s*u+l*i+c*a-f*o)/h,r[1]=2*(c*u+l*o+f*i-s*a)/h,r[2]=2*(f*u+l*a+s*o-c*i)/h):(r[0]=2*(s*u+l*i+c*a-f*o),r[1]=2*(c*u+l*o+f*i-s*a),r[2]=2*(f*u+l*a+s*o-c*i)),R(t,e,r),t}function S(t,e){return t[0]=e[12],t[1]=e[13],t[2]=e[14],t}function A(t,e){let r=e[0],n=e[1],i=e[2],o=e[4],a=e[5],u=e[6],s=e[8],c=e[9],f=e[10];return t[0]=Math.sqrt(r*r+n*n+i*i),t[1]=Math.sqrt(o*o+a*a+u*u),t[2]=Math.sqrt(s*s+c*c+f*f),t}function N(t,e){let r=e[0]+e[5]+e[10],n=0;return r>0?(n=2*Math.sqrt(r+1),t[3]=.25*n,t[0]=(e[6]-e[9])/n,t[1]=(e[8]-e[2])/n,t[2]=(e[1]-e[4])/n):e[0]>e[5]&&e[0]>e[10]?(n=2*Math.sqrt(1+e[0]-e[5]-e[10]),t[3]=(e[6]-e[9])/n,t[0]=.25*n,t[1]=(e[1]+e[4])/n,t[2]=(e[8]+e[2])/n):e[5]>e[10]?(n=2*Math.sqrt(1+e[5]-e[0]-e[10]),t[3]=(e[8]-e[2])/n,t[0]=(e[1]+e[4])/n,t[1]=.25*n,t[2]=(e[6]+e[9])/n):(n=2*Math.sqrt(1+e[10]-e[0]-e[5]),t[3]=(e[1]-e[4])/n,t[0]=(e[8]+e[2])/n,t[1]=(e[6]+e[9])/n,t[2]=.25*n),t}function C(t,e,r,n){let i=e[0],o=e[1],a=e[2],u=e[3],s=i+i,c=o+o,f=a+a,l=i*s,h=i*c,d=i*f,v=o*c,_=o*f,m=a*f,p=u*s,y=u*c,b=u*f,g=n[0],M=n[1],x=n[2];return t[0]=(1-(v+m))*g,t[1]=(h+b)*g,t[2]=(d-y)*g,t[3]=0,t[4]=(h-b)*M,t[5]=(1-(l+m))*M,t[6]=(_+p)*M,t[7]=0,t[8]=(d+y)*x,t[9]=(_-p)*x,t[10]=(1-(l+v))*x,t[11]=0,t[12]=r[0],t[13]=r[1],t[14]=r[2],t[15]=1,t}function I(t,e,r,n,i){let o=e[0],a=e[1],u=e[2],s=e[3],c=o+o,f=a+a,l=u+u,h=o*c,d=o*f,v=o*l,_=a*f,m=a*l,p=u*l,y=s*c,b=s*f,g=s*l,M=n[0],x=n[1],T=n[2],w=i[0],E=i[1],O=i[2],R=(1-(_+p))*M,P=(d+g)*M,S=(v-b)*M,A=(d-g)*x,N=(1-(h+p))*x,C=(m+y)*x,I=(v+b)*T,k=(m-y)*T,L=(1-(h+_))*T;return t[0]=R,t[1]=P,t[2]=S,t[3]=0,t[4]=A,t[5]=N,t[6]=C,t[7]=0,t[8]=I,t[9]=k,t[10]=L,t[11]=0,t[12]=r[0]+w-(R*w+A*E+I*O),t[13]=r[1]+E-(P*w+N*E+k*O),t[14]=r[2]+O-(S*w+C*E+L*O),t[15]=1,t}function k(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r+r,u=n+n,s=i+i,c=r*a,f=n*a,l=n*u,h=i*a,d=i*u,v=i*s,_=o*a,m=o*u,p=o*s;return t[0]=1-l-v,t[1]=f+p,t[2]=h-m,t[3]=0,t[4]=f-p,t[5]=1-c-v,t[6]=d+_,t[7]=0,t[8]=h+m,t[9]=d-_,t[10]=1-c-l,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function L(t,e,r,n,i,o,a){let u=1/(r-e),s=1/(i-n),c=1/(o-a);return t[0]=2*o*u,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*o*s,t[6]=0,t[7]=0,t[8]=(r+e)*u,t[9]=(i+n)*s,t[10]=(a+o)*c,t[11]=-1,t[12]=0,t[13]=0,t[14]=a*o*2*c,t[15]=0,t}function F(t,e,r,n,i){let o=1/Math.tan(e/2),a=1/(n-i);return t[0]=o/r,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=o,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=(i+n)*a,t[11]=-1,t[12]=0,t[13]=0,t[14]=2*i*n*a,t[15]=0,t}function D(t,e,r,n){let i=Math.tan(e.upDegrees*Math.PI/180),o=Math.tan(e.downDegrees*Math.PI/180),a=Math.tan(e.leftDegrees*Math.PI/180),u=Math.tan(e.rightDegrees*Math.PI/180),s=2/(a+u),c=2/(i+o);return t[0]=s,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=c,t[6]=0,t[7]=0,t[8]=-(a-u)*s*.5,t[9]=(i-o)*c*.5,t[10]=n/(r-n),t[11]=-1,t[12]=0,t[13]=0,t[14]=n*r/(r-n),t[15]=0,t}function B(t,e,r,n,i,o,a){let u=1/(e-r),s=1/(n-i),c=1/(o-a);return t[0]=-2*u,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*s,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*c,t[11]=0,t[12]=(e+r)*u,t[13]=(i+n)*s,t[14]=(a+o)*c,t[15]=1,t}function j(t,e,r,i){let o,a,u,s,f,l,h,d,v,_,m=e[0],p=e[1],y=e[2],b=i[0],g=i[1],M=i[2],x=r[0],T=r[1],w=r[2];return Math.abs(m-x)<n.EPSILON&&Math.abs(p-T)<n.EPSILON&&Math.abs(y-w)<n.EPSILON?c(t):(h=m-x,d=p-T,v=y-w,o=g*(v*=_=1/Math.sqrt(h*h+d*d+v*v))-M*(d*=_),a=M*(h*=_)-b*v,u=b*d-g*h,(_=Math.sqrt(o*o+a*a+u*u))?(o*=_=1/_,a*=_,u*=_):(o=0,a=0,u=0),s=d*u-v*a,f=v*o-h*u,l=h*a-d*o,(_=Math.sqrt(s*s+f*f+l*l))?(s*=_=1/_,f*=_,l*=_):(s=0,f=0,l=0),t[0]=o,t[1]=s,t[2]=h,t[3]=0,t[4]=a,t[5]=f,t[6]=d,t[7]=0,t[8]=u,t[9]=l,t[10]=v,t[11]=0,t[12]=-(o*m+a*p+u*y),t[13]=-(s*m+f*p+l*y),t[14]=-(h*m+d*p+v*y),t[15]=1,t)}function U(t,e,r,n){let i=e[0],o=e[1],a=e[2],u=n[0],s=n[1],c=n[2],f=i-r[0],l=o-r[1],h=a-r[2],d=f*f+l*l+h*h;d>0&&(f*=d=1/Math.sqrt(d),l*=d,h*=d);let v=s*h-c*l,_=c*f-u*h,m=u*l-s*f;return(d=v*v+_*_+m*m)>0&&(v*=d=1/Math.sqrt(d),_*=d,m*=d),t[0]=v,t[1]=_,t[2]=m,t[3]=0,t[4]=l*m-h*_,t[5]=h*v-f*m,t[6]=f*_-l*v,t[7]=0,t[8]=f,t[9]=l,t[10]=h,t[11]=0,t[12]=i,t[13]=o,t[14]=a,t[15]=1,t}function V(t){return"mat4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+", "+t[9]+", "+t[10]+", "+t[11]+", "+t[12]+", "+t[13]+", "+t[14]+", "+t[15]+")"}function Y(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+Math.pow(t[6],2)+Math.pow(t[7],2)+Math.pow(t[8],2)+Math.pow(t[9],2)+Math.pow(t[10],2)+Math.pow(t[11],2)+Math.pow(t[12],2)+Math.pow(t[13],2)+Math.pow(t[14],2)+Math.pow(t[15],2))}function G(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t[6]=e[6]+r[6],t[7]=e[7]+r[7],t[8]=e[8]+r[8],t[9]=e[9]+r[9],t[10]=e[10]+r[10],t[11]=e[11]+r[11],t[12]=e[12]+r[12],t[13]=e[13]+r[13],t[14]=e[14]+r[14],t[15]=e[15]+r[15],t}function H(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t[4]=e[4]-r[4],t[5]=e[5]-r[5],t[6]=e[6]-r[6],t[7]=e[7]-r[7],t[8]=e[8]-r[8],t[9]=e[9]-r[9],t[10]=e[10]-r[10],t[11]=e[11]-r[11],t[12]=e[12]-r[12],t[13]=e[13]-r[13],t[14]=e[14]-r[14],t[15]=e[15]-r[15],t}function q(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t[6]=e[6]*r,t[7]=e[7]*r,t[8]=e[8]*r,t[9]=e[9]*r,t[10]=e[10]*r,t[11]=e[11]*r,t[12]=e[12]*r,t[13]=e[13]*r,t[14]=e[14]*r,t[15]=e[15]*r,t}function X(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t[4]=e[4]+r[4]*n,t[5]=e[5]+r[5]*n,t[6]=e[6]+r[6]*n,t[7]=e[7]+r[7]*n,t[8]=e[8]+r[8]*n,t[9]=e[9]+r[9]*n,t[10]=e[10]+r[10]*n,t[11]=e[11]+r[11]*n,t[12]=e[12]+r[12]*n,t[13]=e[13]+r[13]*n,t[14]=e[14]+r[14]*n,t[15]=e[15]+r[15]*n,t}function W(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]&&t[6]===e[6]&&t[7]===e[7]&&t[8]===e[8]&&t[9]===e[9]&&t[10]===e[10]&&t[11]===e[11]&&t[12]===e[12]&&t[13]===e[13]&&t[14]===e[14]&&t[15]===e[15]}function K(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=t[6],f=t[7],l=t[8],h=t[9],d=t[10],v=t[11],_=t[12],m=t[13],p=t[14],y=t[15],b=e[0],g=e[1],M=e[2],x=e[3],T=e[4],w=e[5],E=e[6],O=e[7],R=e[8],P=e[9],S=e[10],A=e[11],N=e[12],C=e[13],I=e[14],k=e[15];return Math.abs(r-b)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(b))&&Math.abs(i-g)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(g))&&Math.abs(o-M)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(M))&&Math.abs(a-x)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(x))&&Math.abs(u-T)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(T))&&Math.abs(s-w)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(w))&&Math.abs(c-E)<=n.EPSILON*Math.max(1,Math.abs(c),Math.abs(E))&&Math.abs(f-O)<=n.EPSILON*Math.max(1,Math.abs(f),Math.abs(O))&&Math.abs(l-R)<=n.EPSILON*Math.max(1,Math.abs(l),Math.abs(R))&&Math.abs(h-P)<=n.EPSILON*Math.max(1,Math.abs(h),Math.abs(P))&&Math.abs(d-S)<=n.EPSILON*Math.max(1,Math.abs(d),Math.abs(S))&&Math.abs(v-A)<=n.EPSILON*Math.max(1,Math.abs(v),Math.abs(A))&&Math.abs(_-N)<=n.EPSILON*Math.max(1,Math.abs(_),Math.abs(N))&&Math.abs(m-C)<=n.EPSILON*Math.max(1,Math.abs(m),Math.abs(C))&&Math.abs(p-I)<=n.EPSILON*Math.max(1,Math.abs(p),Math.abs(I))&&Math.abs(y-k)<=n.EPSILON*Math.max(1,Math.abs(y),Math.abs(k))}const z=v,Q=H},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Renderer=e.RenderTexture=e.RenderView=e.ATTRIB_MASK=e.ATTRIB=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();e.createWebGLContext=p;var i=r(3),o=r(2),a=r(29),u=r(8),s=r(6);function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var f=e.ATTRIB={POSITION:1,NORMAL:2,TANGENT:3,TEXCOORD_0:4,TEXCOORD_1:5,COLOR_0:6},l=e.ATTRIB_MASK={POSITION:1,NORMAL:2,TANGENT:4,TEXCOORD_0:8,TEXCOORD_1:16,COLOR_0:32},h=WebGLRenderingContext,d=new Float32Array([-.1,-1,-.2]),v=new Float32Array([3,3,3]),_=new RegExp("precision (lowp|mediump|highp) float;");function m(t){return 0==(t&t-1)}function p(t){t=t||{alpha:!1};var e=document.createElement("canvas"),r=t.webgl2?["webgl2"]:["webgl","experimental-webgl"],n=null,i=!0,o=!1,a=void 0;try{for(var u,s=r[Symbol.iterator]();!(i=(u=s.next()).done);i=!0){var c=u.value;if(n=e.getContext(c,t))break}}catch(t){o=!0,a=t}finally{try{!i&&s.return&&s.return()}finally{if(o)throw a}}if(!n){var f=t.webgl2?"WebGL 2":"WebGL";return console.error("This browser does not support "+f+"."),null}return n}e.RenderView=function(){function t(e,r){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"left";c(this,t),this.projectionMatrix=e,this.viewMatrix=r,this.viewport=n,this._eye=i,this._eyeIndex="left"==i?0:1}return n(t,[{key:"eye",get:function(){return this._eye},set:function(t){this._eye=t,this._eyeIndex="left"==t?0:1}},{key:"eyeIndex",get:function(){return this._eyeIndex}}]),t}();var y=function(){function t(e,r,n){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;c(this,t),this._target=e,this._usage=r,this._length=o,n instanceof Promise?(this._buffer=null,this._promise=n.then(function(t){return i._buffer=t,i})):(this._buffer=n,this._promise=Promise.resolve(this))}return n(t,[{key:"waitForComplete",value:function(){return this._promise}}]),t}(),b=function t(e){c(this,t),this._attrib_index=f[e.name],this._componentCount=e.componentCount,this._componentType=e.componentType,this._stride=e.stride,this._byteOffset=e.byteOffset,this._normalized=e.normalized},g=function t(e){c(this,t),this._buffer=e,this._attributes=[]},M=function(){function t(e){c(this,t),this._activeFrameId=0,this._instances=[],this._material=null,this.setPrimitive(e)}return n(t,[{key:"setPrimitive",value:function(t){this._mode=t.mode,this._elementCount=t.elementCount,this._promise=null,this._vao=null,this._complete=!1,this._attributeBuffers=[],this._attributeMask=0;var e=!0,r=!1,n=void 0;try{for(var i,o=t.attributes[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){var a=i.value;this._attributeMask|=l[a.name];var u=new b(a),c=!1,f=!0,h=!1,d=void 0;try{for(var v,_=this._attributeBuffers[Symbol.iterator]();!(f=(v=_.next()).done);f=!0){var m=v.value;if(m._buffer==a.buffer){m._attributes.push(u),c=!0;break}}}catch(t){h=!0,d=t}finally{try{!f&&_.return&&_.return()}finally{if(h)throw d}}if(!c){var p=new g(a.buffer);p._attributes.push(u),this._attributeBuffers.push(p)}}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}this._indexBuffer=null,this._indexByteOffset=0,this._indexType=0,t.indexBuffer&&(this._indexByteOffset=t.indexByteOffset,this._indexType=t.indexType,this._indexBuffer=t.indexBuffer),t._min?(this._min=s.vec3.clone(t._min),this._max=s.vec3.clone(t._max)):(this._min=null,this._max=null),null!=this._material&&this.waitForComplete()}},{key:"setRenderMaterial",value:function(t){this._material=t,this._promise=null,this._complete=!1,null!=this._material&&this.waitForComplete()}},{key:"markActive",value:function(t){if(this._complete&&this._activeFrameId!=t){if(this._material&&!this._material.markActive(t))return;this._activeFrameId=t}}},{key:"waitForComplete",value:function(){var t=this;if(!this._promise){if(!this._material)return Promise.reject("RenderPrimitive does not have a material");var e=[],r=!0,n=!1,i=void 0;try{for(var o,a=this._attributeBuffers[Symbol.iterator]();!(r=(o=a.next()).done);r=!0){var u=o.value;u._buffer._buffer||e.push(u._buffer._promise)}}catch(t){n=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(n)throw i}}this._indexBuffer&&!this._indexBuffer._buffer&&e.push(this._indexBuffer._promise),this._promise=Promise.all(e).then(function(){return t._complete=!0,t})}return this._promise}},{key:"samplers",get:function(){return this._material._samplerDictionary}},{key:"uniforms",get:function(){return this._material._uniform_dictionary}}]),t}(),x=e.RenderTexture=function(){function t(e){c(this,t),this._texture=e,this._complete=!1,this._activeFrameId=0,this._activeCallback=null}return n(t,[{key:"markActive",value:function(t){this._activeCallback&&this._activeFrameId!=t&&(this._activeFrameId=t,this._activeCallback(this))}}]),t}(),T=s.mat4.create();function w(t,e,r,n,i){var o=(i&r)-(n&r);o&&(o>0?t.enable(e):t.disable(e))}var E=function(){function t(e,r,n){c(this,t),this._renderer=e,this._uniformName=r._uniformName,this._renderTexture=e._getRenderTexture(r._texture),this._index=n}return n(t,[{key:"texture",set:function(t){this._renderTexture=this._renderer._getRenderTexture(t)}}]),t}(),O=function(){function t(e){c(this,t),this._uniformName=e._uniformName,this._uniform=null,this._length=e._length,e._value instanceof Array?this._value=new Float32Array(e._value):this._value=new Float32Array([e._value])}return n(t,[{key:"value",set:function(t){if(1==this._value.length)this._value[0]=t;else for(var e=0;e<this._value.length;++e)this._value[e]=t[e]}}]),t}(),R=function(){function t(e,r,n){c(this,t),this._program=n,this._state=r.state._state,this._activeFrameId=0,this._completeForActiveFrame=!1,this._samplerDictionary={},this._samplers=[];for(var o=0;o<r._samplers.length;++o){var a=new E(e,r._samplers[o],o);this._samplers.push(a),this._samplerDictionary[a._uniformName]=a}this._uniform_dictionary={},this._uniforms=[];var u=!0,s=!1,f=void 0;try{for(var l,h=r._uniforms[Symbol.iterator]();!(u=(l=h.next()).done);u=!0){var d=l.value,v=new O(d);this._uniforms.push(v),this._uniform_dictionary[v._uniformName]=v}}catch(t){s=!0,f=t}finally{try{!u&&h.return&&h.return()}finally{if(s)throw f}}this._firstBind=!0,this._renderOrder=r.renderOrder,this._renderOrder==i.RENDER_ORDER.DEFAULT&&(this._state&i.CAP.BLEND?this._renderOrder=i.RENDER_ORDER.TRANSPARENT:this._renderOrder=i.RENDER_ORDER.OPAQUE)}return n(t,[{key:"bind",value:function(t){if(this._firstBind){for(var e=0;e<this._samplers.length;){var r=this._samplers[e];this._program.uniform[r._uniformName]?++e:this._samplers.splice(e,1)}for(var n=0;n<this._uniforms.length;){var i=this._uniforms[n];i._uniform=this._program.uniform[i._uniformName],i._uniform?++n:this._uniforms.splice(n,1)}this._firstBind=!1}var o=!0,a=!1,u=void 0;try{for(var s,c=this._samplers[Symbol.iterator]();!(o=(s=c.next()).done);o=!0){var f=s.value;t.activeTexture(t.TEXTURE0+f._index),f._renderTexture&&f._renderTexture._complete?t.bindTexture(t.TEXTURE_2D,f._renderTexture._texture):t.bindTexture(t.TEXTURE_2D,null)}}catch(t){a=!0,u=t}finally{try{!o&&c.return&&c.return()}finally{if(a)throw u}}var l=!0,h=!1,d=void 0;try{for(var v,_=this._uniforms[Symbol.iterator]();!(l=(v=_.next()).done);l=!0){var m=v.value;switch(m._length){case 1:t.uniform1fv(m._uniform,m._value);break;case 2:t.uniform2fv(m._uniform,m._value);break;case 3:t.uniform3fv(m._uniform,m._value);break;case 4:t.uniform4fv(m._uniform,m._value)}}}catch(t){h=!0,d=t}finally{try{!l&&_.return&&_.return()}finally{if(h)throw d}}}},{key:"markActive",value:function(t){if(this._activeFrameId!=t){this._activeFrameId=t,this._completeForActiveFrame=!0;for(var e=0;e<this._samplers.length;++e){var r=this._samplers[e];if(r._renderTexture){if(!r._renderTexture._complete){this._completeForActiveFrame=!1;break}r._renderTexture.markActive(t)}}}return this._completeForActiveFrame}},{key:"_capsDiff",value:function(t){return t&i.MAT_STATE.CAPS_RANGE^this._state&i.MAT_STATE.CAPS_RANGE}},{key:"_blendDiff",value:function(t){return this._state&i.CAP.BLEND?t&i.MAT_STATE.BLEND_FUNC_RANGE^this._state&i.MAT_STATE.BLEND_FUNC_RANGE:0}},{key:"_depthFuncDiff",value:function(t){return this._state&i.CAP.DEPTH_TEST?t&i.MAT_STATE.DEPTH_FUNC_RANGE^this._state&i.MAT_STATE.DEPTH_FUNC_RANGE:0}},{key:"cullFace",get:function(){return!!(this._state&i.CAP.CULL_FACE)}},{key:"blend",get:function(){return!!(this._state&i.CAP.BLEND)}},{key:"depthTest",get:function(){return!!(this._state&i.CAP.DEPTH_TEST)}},{key:"stencilTest",get:function(){return!!(this._state&i.CAP.STENCIL_TEST)}},{key:"colorMask",get:function(){return!!(this._state&i.CAP.COLOR_MASK)}},{key:"depthMask",get:function(){return!!(this._state&i.CAP.DEPTH_MASK)}},{key:"stencilMask",get:function(){return!!(this._state&i.CAP.STENCIL_MASK)}},{key:"depthFunc",get:function(){return((this._state&i.MAT_STATE.DEPTH_FUNC_RANGE)>>i.MAT_STATE.DEPTH_FUNC_SHIFT)+h.NEVER}},{key:"blendFuncSrc",get:function(){return(0,i.stateToBlendFunc)(this._state,i.MAT_STATE.BLEND_SRC_RANGE,i.MAT_STATE.BLEND_SRC_SHIFT)}},{key:"blendFuncDst",get:function(){return(0,i.stateToBlendFunc)(this._state,i.MAT_STATE.BLEND_DST_RANGE,i.MAT_STATE.BLEND_DST_SHIFT)}}]),t}();e.Renderer=function(){function t(e){c(this,t),this._gl=e||p(),this._frameId=0,this._programCache={},this._textureCache={},this._renderPrimitives=Array(i.RENDER_ORDER.DEFAULT),this._cameraPositions=[],this._vaoExt=e.getExtension("OES_vertex_array_object");var r=e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT);this._defaultFragPrecision=r.precision>0?"highp":"mediump",this._depthMaskNeedsReset=!1,this._colorMaskNeedsReset=!1,this._globalLightColor=s.vec3.clone(v),this._globalLightDir=s.vec3.clone(d)}return n(t,[{key:"createRenderBuffer",value:function(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:h.STATIC_DRAW,n=this._gl,i=n.createBuffer();if(e instanceof Promise){var o=new y(t,r,e.then(function(e){return n.bindBuffer(t,i),n.bufferData(t,e,r),o._length=e.byteLength,i}));return o}return n.bindBuffer(t,i),n.bufferData(t,e,r),new y(t,r,i,e.byteLength)}},{key:"updateRenderBuffer",value:function(t,e){var r=this,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;if(t._buffer){var i=this._gl;i.bindBuffer(t._target,t._buffer),0==n&&t._length==e.byteLength?i.bufferData(t._target,e,t._usage):i.bufferSubData(t._target,n,e)}else t.waitForComplete().then(function(t){r.updateRenderBuffer(t,e,n)})}},{key:"createRenderPrimitive",value:function(t,e){var r=new M(t),n=this._getMaterialProgram(e,r),i=new R(this,e,n);return r.setRenderMaterial(i),this._renderPrimitives[i._renderOrder]||(this._renderPrimitives[i._renderOrder]=[]),this._renderPrimitives[i._renderOrder].push(r),r}},{key:"createMesh",value:function(t,e){var r=new o.Node;return r.addRenderPrimitive(this.createRenderPrimitive(t,e)),r}},{key:"drawViews",value:function(t,e){if(e){var r=this._gl;if(this._frameId++,e.markActive(this._frameId),1==t.length&&t[0].viewport){var n=t[0].viewport;this._gl.viewport(n.x,n.y,n.width,n.height)}for(var i=0;i<t.length;++i){s.mat4.invert(T,t[i].viewMatrix),this._cameraPositions.length<=i&&this._cameraPositions.push(s.vec3.create());var o=this._cameraPositions[i];s.vec3.set(o,0,0,0),s.vec3.transformMat4(o,o,T)}var a=!0,u=!1,c=void 0;try{for(var f,l=this._renderPrimitives[Symbol.iterator]();!(a=(f=l.next()).done);a=!0){var h=f.value;h&&h.length&&this._drawRenderPrimitiveSet(t,h)}}catch(t){u=!0,c=t}finally{try{!a&&l.return&&l.return()}finally{if(u)throw c}}this._vaoExt&&this._vaoExt.bindVertexArrayOES(null),this._depthMaskNeedsReset&&r.depthMask(!0),this._colorMaskNeedsReset&&r.colorMask(!0,!0,!0,!0)}}},{key:"_drawRenderPrimitiveSet",value:function(t,e){var r=this._gl,n=null,i=null,o=0,a=!0,u=!1,s=void 0;try{for(var c,f=e[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){var l=c.value;if(l._activeFrameId==this._frameId){n!=l._material._program&&((n=l._material._program).use(),n.uniform.LIGHT_DIRECTION&&r.uniform3fv(n.uniform.LIGHT_DIRECTION,this._globalLightDir),n.uniform.LIGHT_COLOR&&r.uniform3fv(n.uniform.LIGHT_COLOR,this._globalLightColor),1==t.length&&(r.uniformMatrix4fv(n.uniform.PROJECTION_MATRIX,!1,t[0].projectionMatrix),r.uniformMatrix4fv(n.uniform.VIEW_MATRIX,!1,t[0].viewMatrix),r.uniform3fv(n.uniform.CAMERA_POSITION,this._cameraPositions[0]),r.uniform1i(n.uniform.EYE_INDEX,t[0].eyeIndex))),i!=l._material&&(this._bindMaterialState(l._material,i),l._material.bind(r,n,i),i=l._material),this._vaoExt?l._vao?this._vaoExt.bindVertexArrayOES(l._vao):(l._vao=this._vaoExt.createVertexArrayOES(),this._vaoExt.bindVertexArrayOES(l._vao),this._bindPrimitive(l)):(this._bindPrimitive(l,o),o=l._attributeMask);for(var h=0;h<t.length;++h){var d=t[h];if(t.length>1){if(d.viewport){var v=d.viewport;r.viewport(v.x,v.y,v.width,v.height)}r.uniformMatrix4fv(n.uniform.PROJECTION_MATRIX,!1,d.projectionMatrix),r.uniformMatrix4fv(n.uniform.VIEW_MATRIX,!1,d.viewMatrix),r.uniform3fv(n.uniform.CAMERA_POSITION,this._cameraPositions[h]),r.uniform1i(n.uniform.EYE_INDEX,d.eyeIndex)}var _=!0,m=!1,p=void 0;try{for(var y,b=l._instances[Symbol.iterator]();!(_=(y=b.next()).done);_=!0){var g=y.value;g._activeFrameId==this._frameId&&(r.uniformMatrix4fv(n.uniform.MODEL_MATRIX,!1,g.worldMatrix),l._indexBuffer?r.drawElements(l._mode,l._elementCount,l._indexType,l._indexByteOffset):r.drawArrays(l._mode,0,l._elementCount))}}catch(t){m=!0,p=t}finally{try{!_&&b.return&&b.return()}finally{if(m)throw p}}}}}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}}},{key:"_getRenderTexture",value:function(t){var e=this;if(!t)return null;var r=t.textureKey;if(!r)throw new Error("Texure does not have a valid key");if(r in this._textureCache)return this._textureCache[r];var n=this._gl,i=n.createTexture(),o=new x(i);return this._textureCache[r]=o,t instanceof u.DataTexture?(n.bindTexture(n.TEXTURE_2D,i),n.texImage2D(n.TEXTURE_2D,0,t.format,t.width,t.height,0,t.format,t._type,t._data),this._setSamplerParameters(t),o._complete=!0):t.waitForComplete().then(function(){n.bindTexture(n.TEXTURE_2D,i),n.texImage2D(n.TEXTURE_2D,0,t.format,t.format,n.UNSIGNED_BYTE,t.source),e._setSamplerParameters(t),o._complete=!0,t instanceof u.VideoTexture&&t._video.addEventListener("playing",function(){o._activeCallback=function(){t._video.paused||t._video.waiting||(n.bindTexture(n.TEXTURE_2D,i),n.texImage2D(n.TEXTURE_2D,0,t.format,t.format,n.UNSIGNED_BYTE,t.source))}})}),o}},{key:"_setSamplerParameters",value:function(t){var e=this._gl,r=t.sampler,n=m(t.width)&&m(t.height),i=n&&t.mipmap;i&&e.generateMipmap(e.TEXTURE_2D);var o=r.minFilter||(i?e.LINEAR_MIPMAP_LINEAR:e.LINEAR),a=r.wrapS||(n?e.REPEAT:e.CLAMP_TO_EDGE),u=r.wrapT||(n?e.REPEAT:e.CLAMP_TO_EDGE);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,r.magFilter||e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,o),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,a),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,u)}},{key:"_getProgramKey",value:function(t,e){var r=t+":";for(var n in e)r+=n+"="+e[n]+",";return r}},{key:"_getMaterialProgram",value:function(t,e){var r=this,n=t.materialName,i=t.vertexSource,o=t.fragmentSource;if(null==n)throw new Error("Material does not have a name");if(null==i)throw new Error('Material "'+n+'" does not have a vertex source');if(null==o)throw new Error('Material "'+n+'" does not have a fragment source');var u=t.getProgramDefines(e),s=this._getProgramKey(n,u);if(s in this._programCache)return this._programCache[s];var c=i;c+="\nuniform mat4 PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX;\n\nvoid main() {\n gl_Position = vertex_main(PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX);\n}\n";var l=(o.match(_)?"":"precision "+this._defaultFragPrecision+" float;\n")+o;l+="\nvoid main() {\n gl_FragColor = fragment_main();\n}\n";var h=new a.Program(this._gl,c,l,f,u);return this._programCache[s]=h,h.onNextUse(function(e){for(var n=0;n<t._samplers.length;++n){var i=t._samplers[n],o=e.uniform[i._uniformName];o&&r._gl.uniform1i(o,n)}}),h}},{key:"_bindPrimitive",value:function(t,e){var r=this._gl;if(e!=t._attributeMask)for(var n in f)t._attributeMask&l[n]?r.enableVertexAttribArray(f[n]):r.disableVertexAttribArray(f[n]);var i=!0,o=!1,a=void 0;try{for(var u,s=t._attributeBuffers[Symbol.iterator]();!(i=(u=s.next()).done);i=!0){var c=u.value;r.bindBuffer(r.ARRAY_BUFFER,c._buffer._buffer);var h=!0,d=!1,v=void 0;try{for(var _,m=c._attributes[Symbol.iterator]();!(h=(_=m.next()).done);h=!0){var p=_.value;r.vertexAttribPointer(p._attrib_index,p._componentCount,p._componentType,p._normalized,p._stride,p._byteOffset)}}catch(t){d=!0,v=t}finally{try{!h&&m.return&&m.return()}finally{if(d)throw v}}}}catch(t){o=!0,a=t}finally{try{!i&&s.return&&s.return()}finally{if(o)throw a}}t._indexBuffer?r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,t._indexBuffer._buffer):r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,null)}},{key:"_bindMaterialState",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=this._gl,n=t._state,o=e?e._state:~n;if(n!=o){if(t._capsDiff(o)){w(r,r.CULL_FACE,i.CAP.CULL_FACE,o,n),w(r,r.BLEND,i.CAP.BLEND,o,n),w(r,r.DEPTH_TEST,i.CAP.DEPTH_TEST,o,n),w(r,r.STENCIL_TEST,i.CAP.STENCIL_TEST,o,n);var a=(n&i.CAP.COLOR_MASK)-(o&i.CAP.COLOR_MASK);if(a){var u=a>1;this._colorMaskNeedsReset=!u,r.colorMask(u,u,u,u)}var s=(n&i.CAP.DEPTH_MASK)-(o&i.CAP.DEPTH_MASK);s&&(this._depthMaskNeedsReset=!(s>1),r.depthMask(s>1));var c=(n&i.CAP.STENCIL_MASK)-(o&i.CAP.STENCIL_MASK);c&&r.stencilMask(c>1)}t._blendDiff(o)&&r.blendFunc(t.blendFuncSrc,t.blendFuncDst),t._depthFuncDiff(o)&&r.depthFunc(t.depthFunc)}}},{key:"gl",get:function(){return this._gl}},{key:"globalLightColor",set:function(t){s.vec3.copy(this._globalLightColor,t)},get:function(){return s.vec3.clone(this._globalLightColor)}},{key:"globalLightDir",set:function(t){s.vec3.copy(this._globalLightDir,t)},get:function(){return s.vec3.clone(this._globalLightDir)}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"fromMat4",function(){return o}),r.d(e,"clone",function(){return a}),r.d(e,"copy",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"identity",function(){return f}),r.d(e,"transpose",function(){return l}),r.d(e,"invert",function(){return h}),r.d(e,"adjoint",function(){return d}),r.d(e,"determinant",function(){return v}),r.d(e,"multiply",function(){return _}),r.d(e,"translate",function(){return m}),r.d(e,"rotate",function(){return p}),r.d(e,"scale",function(){return y}),r.d(e,"fromTranslation",function(){return b}),r.d(e,"fromRotation",function(){return g}),r.d(e,"fromScaling",function(){return M}),r.d(e,"fromMat2d",function(){return x}),r.d(e,"fromQuat",function(){return T}),r.d(e,"normalFromMat4",function(){return w}),r.d(e,"projection",function(){return E}),r.d(e,"str",function(){return O}),r.d(e,"frob",function(){return R}),r.d(e,"add",function(){return P}),r.d(e,"subtract",function(){return S}),r.d(e,"multiplyScalar",function(){return A}),r.d(e,"multiplyScalarAndAdd",function(){return N}),r.d(e,"exactEquals",function(){return C}),r.d(e,"equals",function(){return I}),r.d(e,"mul",function(){return k}),r.d(e,"sub",function(){return L});var n=r(0);function i(){let t=new n.ARRAY_TYPE(9);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function o(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[4],t[4]=e[5],t[5]=e[6],t[6]=e[8],t[7]=e[9],t[8]=e[10],t}function a(t){let e=new n.ARRAY_TYPE(9);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e}function u(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t}function s(t,e,r,i,o,a,u,s,c){let f=new n.ARRAY_TYPE(9);return f[0]=t,f[1]=e,f[2]=r,f[3]=i,f[4]=o,f[5]=a,f[6]=u,f[7]=s,f[8]=c,f}function c(t,e,r,n,i,o,a,u,s,c){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t[6]=u,t[7]=s,t[8]=c,t}function f(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function l(t,e){if(t===e){let r=e[1],n=e[2],i=e[5];t[1]=e[3],t[2]=e[6],t[3]=r,t[5]=e[7],t[6]=n,t[7]=i}else t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8];return t}function h(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=f*a-u*c,h=-f*o+u*s,d=c*o-a*s,v=r*l+n*h+i*d;return v?(v=1/v,t[0]=l*v,t[1]=(-f*n+i*c)*v,t[2]=(u*n-i*a)*v,t[3]=h*v,t[4]=(f*r-i*s)*v,t[5]=(-u*r+i*o)*v,t[6]=d*v,t[7]=(-c*r+n*s)*v,t[8]=(a*r-n*o)*v,t):null}function d(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8];return t[0]=a*f-u*c,t[1]=i*c-n*f,t[2]=n*u-i*a,t[3]=u*s-o*f,t[4]=r*f-i*s,t[5]=i*o-r*u,t[6]=o*c-a*s,t[7]=n*s-r*c,t[8]=r*a-n*o,t}function v(t){let e=t[0],r=t[1],n=t[2],i=t[3],o=t[4],a=t[5],u=t[6],s=t[7],c=t[8];return e*(c*o-a*s)+r*(-c*i+a*u)+n*(s*i-o*u)}function _(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=r[0],d=r[1],v=r[2],_=r[3],m=r[4],p=r[5],y=r[6],b=r[7],g=r[8];return t[0]=h*n+d*a+v*c,t[1]=h*i+d*u+v*f,t[2]=h*o+d*s+v*l,t[3]=_*n+m*a+p*c,t[4]=_*i+m*u+p*f,t[5]=_*o+m*s+p*l,t[6]=y*n+b*a+g*c,t[7]=y*i+b*u+g*f,t[8]=y*o+b*s+g*l,t}function m(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=r[0],d=r[1];return t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=u,t[5]=s,t[6]=h*n+d*a+c,t[7]=h*i+d*u+f,t[8]=h*o+d*s+l,t}function p(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=Math.sin(r),d=Math.cos(r);return t[0]=d*n+h*a,t[1]=d*i+h*u,t[2]=d*o+h*s,t[3]=d*a-h*n,t[4]=d*u-h*i,t[5]=d*s-h*o,t[6]=c,t[7]=f,t[8]=l,t}function y(t,e,r){let n=r[0],i=r[1];return t[0]=n*e[0],t[1]=n*e[1],t[2]=n*e[2],t[3]=i*e[3],t[4]=i*e[4],t[5]=i*e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t}function b(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=e[0],t[7]=e[1],t[8]=1,t}function g(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=0,t[3]=-r,t[4]=n,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function M(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=0,t[4]=e[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function x(t,e){return t[0]=e[0],t[1]=e[1],t[2]=0,t[3]=e[2],t[4]=e[3],t[5]=0,t[6]=e[4],t[7]=e[5],t[8]=1,t}function T(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r+r,u=n+n,s=i+i,c=r*a,f=n*a,l=n*u,h=i*a,d=i*u,v=i*s,_=o*a,m=o*u,p=o*s;return t[0]=1-l-v,t[3]=f-p,t[6]=h+m,t[1]=f+p,t[4]=1-c-v,t[7]=d-_,t[2]=h-m,t[5]=d+_,t[8]=1-c-l,t}function w(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=e[9],h=e[10],d=e[11],v=e[12],_=e[13],m=e[14],p=e[15],y=r*u-n*a,b=r*s-i*a,g=r*c-o*a,M=n*s-i*u,x=n*c-o*u,T=i*c-o*s,w=f*_-l*v,E=f*m-h*v,O=f*p-d*v,R=l*m-h*_,P=l*p-d*_,S=h*p-d*m,A=y*S-b*P+g*R+M*O-x*E+T*w;return A?(A=1/A,t[0]=(u*S-s*P+c*R)*A,t[1]=(s*O-a*S-c*E)*A,t[2]=(a*P-u*O+c*w)*A,t[3]=(i*P-n*S-o*R)*A,t[4]=(r*S-i*O+o*E)*A,t[5]=(n*O-r*P-o*w)*A,t[6]=(_*T-m*x+p*M)*A,t[7]=(m*g-v*T-p*b)*A,t[8]=(v*x-_*g+p*y)*A,t):null}function E(t,e,r){return t[0]=2/e,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/r,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t}function O(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"}function R(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+Math.pow(t[6],2)+Math.pow(t[7],2)+Math.pow(t[8],2))}function P(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t[6]=e[6]+r[6],t[7]=e[7]+r[7],t[8]=e[8]+r[8],t}function S(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t[4]=e[4]-r[4],t[5]=e[5]-r[5],t[6]=e[6]-r[6],t[7]=e[7]-r[7],t[8]=e[8]-r[8],t}function A(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t[6]=e[6]*r,t[7]=e[7]*r,t[8]=e[8]*r,t}function N(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t[4]=e[4]+r[4]*n,t[5]=e[5]+r[5]*n,t[6]=e[6]+r[6]*n,t[7]=e[7]+r[7]*n,t[8]=e[8]+r[8]*n,t}function C(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]&&t[6]===e[6]&&t[7]===e[7]&&t[8]===e[8]}function I(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=t[6],f=t[7],l=t[8],h=e[0],d=e[1],v=e[2],_=e[3],m=e[4],p=e[5],y=e[6],b=e[7],g=e[8];return Math.abs(r-h)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(h))&&Math.abs(i-d)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(d))&&Math.abs(o-v)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(v))&&Math.abs(a-_)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(_))&&Math.abs(u-m)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(m))&&Math.abs(s-p)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(p))&&Math.abs(c-y)<=n.EPSILON*Math.max(1,Math.abs(c),Math.abs(y))&&Math.abs(f-b)<=n.EPSILON*Math.max(1,Math.abs(f),Math.abs(b))&&Math.abs(l-g)<=n.EPSILON*Math.max(1,Math.abs(l),Math.abs(g))}const k=_,L=S},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.PbrMaterial=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(11);e.PbrMaterial=function(t){function e(){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e);var t=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.baseColor=t.defineSampler("baseColorTex"),t.metallicRoughness=t.defineSampler("metallicRoughnessTex"),t.normal=t.defineSampler("normalTex"),t.occlusion=t.defineSampler("occlusionTex"),t.emissive=t.defineSampler("emissiveTex"),t.baseColorFactor=t.defineUniform("baseColorFactor",[1,1,1,1]),t.metallicRoughnessFactor=t.defineUniform("metallicRoughnessFactor",[1,1]),t.occlusionStrength=t.defineUniform("occlusionStrength",1),t.emissiveFactor=t.defineUniform("emissiveFactor",[0,0,0]),t}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,i.Material),n(e,[{key:"getProgramDefines",value:function(t){var e={};return t._attributeMask&o.ATTRIB_MASK.COLOR_0&&(e.USE_VERTEX_COLOR=1),t._attributeMask&o.ATTRIB_MASK.TEXCOORD_0&&(this.baseColor.texture&&(e.USE_BASE_COLOR_MAP=1),this.normal.texture&&t._attributeMask&o.ATTRIB_MASK.TANGENT&&(e.USE_NORMAL_MAP=1),this.metallicRoughness.texture&&(e.USE_METAL_ROUGH_MAP=1),this.occlusion.texture&&(e.USE_OCCLUSION=1),this.emissive.texture&&(e.USE_EMISSIVE_TEXTURE=1)),this.metallicRoughness.texture&&t._attributeMask&o.ATTRIB_MASK.TEXCOORD_0||1!=this.metallicRoughnessFactor.value[1]||(e.FULLY_ROUGH=1),e}},{key:"materialName",get:function(){return"PBR"}},{key:"vertexSource",get:function(){return"\nattribute vec3 POSITION, NORMAL;\nattribute vec2 TEXCOORD_0, TEXCOORD_1;\n\nuniform vec3 CAMERA_POSITION;\nuniform vec3 LIGHT_DIRECTION;\n\nvarying vec3 vLight; // Vector from vertex to light.\nvarying vec3 vView; // Vector from vertex to camera.\nvarying vec2 vTex;\n\n#ifdef USE_NORMAL_MAP\nattribute vec4 TANGENT;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_VERTEX_COLOR\nattribute vec4 COLOR_0;\nvarying vec4 vCol;\n#endif\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 n = normalize(vec3(model * vec4(NORMAL, 0.0)));\n#ifdef USE_NORMAL_MAP\n vec3 t = normalize(vec3(model * vec4(TANGENT.xyz, 0.0)));\n vec3 b = cross(n, t) * TANGENT.w;\n vTBN = mat3(t, b, n);\n#else\n vNorm = n;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n vCol = COLOR_0;\n#endif\n\n vTex = TEXCOORD_0;\n vec4 mPos = model * vec4(POSITION, 1.0);\n vLight = -LIGHT_DIRECTION;\n vView = CAMERA_POSITION - mPos.xyz;\n return proj * view * mPos;\n}"}},{key:"fragmentSource",get:function(){return"\n#define M_PI 3.14159265\n\nuniform vec4 baseColorFactor;\n#ifdef USE_BASE_COLOR_MAP\nuniform sampler2D baseColorTex;\n#endif\n\nvarying vec3 vLight;\nvarying vec3 vView;\nvarying vec2 vTex;\n\n#ifdef USE_VERTEX_COLOR\nvarying vec4 vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\nuniform sampler2D normalTex;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_METAL_ROUGH_MAP\nuniform sampler2D metallicRoughnessTex;\n#endif\nuniform vec2 metallicRoughnessFactor;\n\n#ifdef USE_OCCLUSION\nuniform sampler2D occlusionTex;\nuniform float occlusionStrength;\n#endif\n\n#ifdef USE_EMISSIVE_TEXTURE\nuniform sampler2D emissiveTex;\n#endif\nuniform vec3 emissiveFactor;\n\nuniform vec3 LIGHT_COLOR;\n\nconst vec3 dielectricSpec = vec3(0.04);\nconst vec3 black = vec3(0.0);\n\n\nvec3 lambertDiffuse(vec3 cDiff) {\n return cDiff / M_PI;\n}\n\nfloat specD(float a, float nDotH) {\n float aSqr = a * a;\n float f = ((nDotH * nDotH) * (aSqr - 1.0) + 1.0);\n return aSqr / (M_PI * f * f);\n}\n\nfloat specG(float roughness, float nDotL, float nDotV) {\n float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n float gl = nDotL / (nDotL * (1.0 - k) + k);\n float gv = nDotV / (nDotV * (1.0 - k) + k);\n return gl * gv;\n}\n\nvec3 specF(float vDotH, vec3 F0) {\n float exponent = (-5.55473 * vDotH - 6.98316) * vDotH;\n float base = 2.0;\n return F0 + (1.0 - F0) * pow(base, exponent);\n}\n\nvec4 fragment_main() {\n#ifdef USE_BASE_COLOR_MAP\n vec4 baseColor = texture2D(baseColorTex, vTex) * baseColorFactor;\n#else\n vec4 baseColor = baseColorFactor;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n baseColor *= vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\n vec3 n = texture2D(normalTex, vTex).rgb;\n n = normalize(vTBN * (2.0 * n - 1.0));\n#else\n vec3 n = normalize(vNorm);\n#endif\n\n#ifdef FULLY_ROUGH\n float metallic = 0.0;\n#else\n float metallic = metallicRoughnessFactor.x;\n#endif\n\n float roughness = metallicRoughnessFactor.y;\n\n#ifdef USE_METAL_ROUGH_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessTex, vTex);\n metallic *= metallicRoughness.b;\n roughness *= metallicRoughness.g;\n#endif\n \n vec3 l = normalize(vLight);\n vec3 v = normalize(vView);\n vec3 h = normalize(l+v);\n\n float nDotL = clamp(dot(n, l), 0.001, 1.0);\n float nDotV = abs(dot(n, v)) + 0.001;\n float nDotH = max(dot(n, h), 0.0);\n float vDotH = max(dot(v, h), 0.0);\n\n // From GLTF Spec\n vec3 cDiff = mix(baseColor.rgb * (1.0 - dielectricSpec.r), black, metallic); // Diffuse color\n vec3 F0 = mix(dielectricSpec, baseColor.rgb, metallic); // Specular color\n float a = roughness * roughness;\n\n#ifdef FULLY_ROUGH\n vec3 specular = F0 * 0.45;\n#else\n vec3 F = specF(vDotH, F0);\n float D = specD(a, nDotH);\n float G = specG(roughness, nDotL, nDotV);\n vec3 specular = (D * F * G) / (4.0 * nDotL * nDotV);\n#endif\n float halfLambert = dot(n, l) * 0.5 + 0.5;\n halfLambert *= halfLambert;\n\n vec3 color = (halfLambert * LIGHT_COLOR * lambertDiffuse(cDiff)) + specular;\n\n#ifdef USE_OCCLUSION\n float occlusion = texture2D(occlusionTex, vTex).r;\n color = mix(color, color * occlusion, occlusionStrength);\n#endif\n \n vec3 emissive = emissiveFactor;\n#ifdef USE_EMISSIVE_TEXTURE\n emissive *= texture2D(emissiveTex, vTex).rgb;\n#endif\n color += emissive;\n\n // gamma correction\n //color = pow(color, vec3(1.0/2.2));\n\n return vec4(color, baseColor.a);\n}"}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.BoxBuilder=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(9);e.BoxBuilder=function(t){function e(){return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,i.GeometryBuilderBase),n(e,[{key:"pushBox",value:function(t,e){var r=this.primitiveStream,n=.5*(e[0]-t[0]),i=.5*(e[1]-t[1]),o=.5*(e[2]-t[2]),a=t[0]+n,u=t[1]+i,s=t[2]+o;r.startGeometry();var c=r.nextVertexIndex;r.pushTriangle(c,c+1,c+2),r.pushTriangle(c,c+2,c+3),r.pushVertex(-n+a,-i+u,-o+s,0,1,0,-1,0),r.pushVertex(+n+a,-i+u,-o+s,1,1,0,-1,0),r.pushVertex(+n+a,-i+u,+o+s,1,0,0,-1,0),r.pushVertex(-n+a,-i+u,+o+s,0,0,0,-1,0),c=r.nextVertexIndex,r.pushTriangle(c,c+2,c+1),r.pushTriangle(c,c+3,c+2),r.pushVertex(-n+a,+i+u,-o+s,0,0,0,1,0),r.pushVertex(+n+a,+i+u,-o+s,1,0,0,1,0),r.pushVertex(+n+a,+i+u,+o+s,1,1,0,1,0),r.pushVertex(-n+a,+i+u,+o+s,0,1,0,1,0),c=r.nextVertexIndex,r.pushTriangle(c,c+2,c+1),r.pushTriangle(c,c+3,c+2),r.pushVertex(-n+a,-i+u,-o+s,0,1,-1,0,0),r.pushVertex(-n+a,+i+u,-o+s,0,0,-1,0,0),r.pushVertex(-n+a,+i+u,+o+s,1,0,-1,0,0),r.pushVertex(-n+a,-i+u,+o+s,1,1,-1,0,0),c=r.nextVertexIndex,r.pushTriangle(c,c+1,c+2),r.pushTriangle(c,c+2,c+3),r.pushVertex(+n+a,-i+u,-o+s,1,1,1,0,0),r.pushVertex(+n+a,+i+u,-o+s,1,0,1,0,0),r.pushVertex(+n+a,+i+u,+o+s,0,0,1,0,0),r.pushVertex(+n+a,-i+u,+o+s,0,1,1,0,0),c=r.nextVertexIndex,r.pushTriangle(c,c+2,c+1),r.pushTriangle(c,c+3,c+2),r.pushVertex(-n+a,-i+u,-o+s,1,1,0,0,-1),r.pushVertex(+n+a,-i+u,-o+s,0,1,0,0,-1),r.pushVertex(+n+a,+i+u,-o+s,0,0,0,0,-1),r.pushVertex(-n+a,+i+u,-o+s,1,0,0,0,-1),c=r.nextVertexIndex,r.pushTriangle(c,c+1,c+2),r.pushTriangle(c,c+2,c+3),r.pushVertex(-n+a,-i+u,+o+s,0,1,0,0,1),r.pushVertex(+n+a,-i+u,+o+s,1,1,0,0,1),r.pushVertex(+n+a,+i+u,+o+s,1,0,0,0,1),r.pushVertex(-n+a,+i+u,+o+s,0,0,0,0,1),r.endGeometry()}},{key:"pushCube",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[0,0,0],e=.5*(arguments.length>1&&void 0!==arguments[1]?arguments[1]:1);this.pushBox([t[0]-e,t[1]-e,t[2]-e],[t[0]+e,t[1]+e,t[2]+e])}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();var i=null;function o(){if(!i){i={};for(var t=(window.location.search.substring(1)||window.location.hash.substring(1)).split("&"),e=0;e<t.length;e++){var r=t[e].split("=");i[r[0].toLowerCase()]=decodeURIComponent(r[1])}}}window.onhashchange=function(){i=null};e.QueryArgs=function(){function t(){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t)}return n(t,null,[{key:"getString",value:function(t,e){o();var r=t.toLowerCase();return r in i?i[r]:e}},{key:"getInt",value:function(t,e){o();var r=t.toLowerCase();return r in i?parseInt(i[r],10):e}},{key:"getFloat",value:function(t,e){o();var r=t.toLowerCase();return r in i?parseFloat(i[r]):e}},{key:"getBool",value:function(t,e){o();var r=t.toLowerCase();return r in i?0!=parseInt(i[r],10):e}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.FallbackHelper=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(6);e.FallbackHelper=function(){function t(e,r){var n=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.scene=e,this.gl=r,this._emulateStage=!1,this.lookYaw=0,this.lookPitch=0,this.viewMatrix=i.mat4.create();var o=i.mat4.create();function a(){r.canvas.width=r.canvas.offsetWidth*window.devicePixelRatio,r.canvas.height=r.canvas.offsetHeight*window.devicePixelRatio,i.mat4.perspective(o,.4*Math.PI,r.canvas.width/r.canvas.height,.1,1e3),r.viewport(0,0,r.drawingBufferWidth,r.drawingBufferHeight)}this.projectionMatrix=o,i.mat4.identity(this.viewMatrix),window.addEventListener("resize",a),a();var u=r.canvas,s=0,c=0;u.addEventListener("touchstart",function(t){2==t.touches.length&&(s=t.touches[1].pageX,c=t.touches[1].pageY)}),u.addEventListener("touchmove",function(t){2==t.touches.length&&(n.onLook(t.touches[1].pageX-s,t.touches[1].pageY-c),s=t.touches[1].pageX,c=t.touches[1].pageY)}),u.addEventListener("mousemove",function(t){2&t.buttons&&n.onLook(t.movementX,t.movementY)}),u.addEventListener("contextmenu",function(t){t.preventDefault()}),this.boundOnFrame=this.onFrame.bind(this),window.requestAnimationFrame(this.boundOnFrame)}return n(t,[{key:"onLook",value:function(t,e){this.lookYaw+=.0025*t,this.lookPitch+=.0025*e,this.lookPitch<.5*-Math.PI&&(this.lookPitch=.5*-Math.PI),this.lookPitch>.5*Math.PI&&(this.lookPitch=.5*Math.PI),this.updateView()}},{key:"onFrame",value:function(t){var e=this.gl;window.requestAnimationFrame(this.boundOnFrame),this.scene.startFrame(),e.clear(e.COLOR_BUFFER_BIT|e.DEPTH_BUFFER_BIT),this.scene.draw(this.projectionMatrix,this.viewMatrix),this.scene.endFrame()}},{key:"updateView",value:function(){i.mat4.identity(this.viewMatrix),i.mat4.rotateX(this.viewMatrix,this.viewMatrix,-this.lookPitch),i.mat4.rotateY(this.viewMatrix,this.viewMatrix,-this.lookYaw),this._emulateStage&&i.mat4.translate(this.viewMatrix,this.viewMatrix,[0,-1.6,0])}},{key:"emulateStage",get:function(){return this._emulateStage},set:function(t){this._emulateStage=t,this.updateView()}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.SevenSegmentText=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7);function u(t){if(Array.isArray(t)){for(var e=0,r=Array(t.length);e<t.length;e++)r[e]=t[e];return r}return Array.from(t)}function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=function(t){function e(){return s(this,e),c(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"SEVEN_SEGMENT_TEXT"}},{key:"vertexSource",get:function(){return"\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 0.0, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n const vec4 color = vec4(0.0, 1.0, 0.0, 1.0);\n\n vec4 fragment_main() {\n return color;\n }"}}]),e}();e.SevenSegmentText=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._text="",t._charNodes=[],t}return f(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this.clearNodes(),this._charNodes=[];var e=[],r={},n=[];function i(t,n,i,o,a){var u=e.length/2;e.push(n,i,o,i,o,a,n,a),r[t]=[u,u+2,u+1,u,u+3,u+2]}var o={};function s(t,e){for(var i={character:t,offset:2*n.length,count:0},a=0;a<e.length;++a){var s=e[a],c=r[s];i.count+=c.length,n.push.apply(n,u(c))}o[t]=i}i(0,-1,1,.5,.75),i(1,-1,.125,.5,-.125),i(2,-1,-.75,.5,-1),i(3,-1,1,-.75,-.125),i(4,.25,1,.5,-.125),i(5,-1,.125,-.75,-1),i(6,.25,.125,.5,-1),s("0",[0,2,3,4,5,6]),s("1",[4,6]),s("2",[0,1,2,4,5]),s("3",[0,1,2,4,6]),s("4",[1,3,4,6]),s("5",[0,1,2,3,6]),s("6",[0,1,2,3,5,6]),s("7",[0,4,6]),s("8",[0,1,2,3,4,5,6]),s("9",[0,1,2,3,4,6]),s("A",[0,1,3,4,5,6]),s("B",[1,2,3,5,6]),s("C",[0,2,3,5]),s("D",[1,2,4,5,6]),s("E",[0,1,2,4,6]),s("F",[0,1,3,5]),s("P",[0,1,3,4,5]),s("-",[1]),s(" ",[]),s("_",[2]);var c=t.gl,f=t.createRenderBuffer(c.ARRAY_BUFFER,new Float32Array(e)),h=t.createRenderBuffer(c.ELEMENT_ARRAY_BUFFER,new Uint16Array(n)),d=[new a.PrimitiveAttribute("POSITION",f,2,c.FLOAT,8,0)],v=new a.Primitive(d,n.length);v.setIndexBuffer(h);var _=new l;for(var m in this._charPrimitives={},o){var p=o[m];v.elementCount=p.count,v.indexByteOffset=p.offset,this._charPrimitives[m]=t.createRenderPrimitive(v,_)}this.text=this._text}},{key:"text",get:function(){return this._text},set:function(t){this._text=t;for(var e=0,r=null;e<t.length;++e)if(r=t[e]in this._charPrimitives?this._charPrimitives[t[e]]:this._charPrimitives._,this._charNodes.length<=e){var n=new o.Node;n.addRenderPrimitive(r);var i=2*e;n.translation=[i,0,0],this._charNodes.push(n),this.addNode(n)}else this._charNodes[e].clearRenderPrimitives(),this._charNodes[e].addRenderPrimitive(r),this._charNodes[e].visible=!0;for(;e<this._charNodes.length;++e)this._charNodes[e].visible=!1}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.StatsViewer=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7),u=r(17);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=30,h=90,d=function(t){function e(){return s(this,e),c(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"STATS_VIEWER"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec3 COLOR_0;\n varying vec4 vColor;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vColor = vec4(COLOR_0, 1.0);\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n varying vec4 vColor;\n\n vec4 fragment_main() {\n return vColor;\n }"}}]),e}();function v(t){return.9/l*t-.45}function _(t){return Math.min(t,h)*(.7/h)-.45}var m=window.performance&&performance.now?performance.now.bind(performance):Date.now;e.StatsViewer=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._performanceMonitoring=!1,t._startTime=m(),t._prevFrameTime=t._startTime,t._prevGraphUpdateTime=t._startTime,t._frames=0,t._fpsAverage=0,t._fpsMin=0,t._fpsStep=t._performanceMonitoring?1e3:250,t._lastSegment=0,t._fpsVertexBuffer=null,t._fpsRenderPrimitive=null,t._fpsNode=null,t._sevenSegmentNode=new u.SevenSegmentText,t._sevenSegmentNode.matrix=new Float32Array([.075,0,0,0,0,.075,0,0,0,0,1,0,-.3625,.3625,.02,1]),t}return f(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this.clearNodes();for(var e=t.gl,r=[],n=[],i=0;i<l;++i){r.push(v(i),_(0),.02,0,1,1),r.push(v(i+1),_(0),.02,0,1,1),r.push(v(i),_(0),.02,0,1,1),r.push(v(i+1),_(0),.02,0,1,1);var u=4*i;n.push(u,u+3,u+1,u+3,u,u+2)}function s(t,e,i,o,a,u,s,c){var f=r.length/6;r.push(t,e,a,u,s,c),r.push(i,o,a,u,s,c),r.push(t,o,a,u,s,c),r.push(i,e,a,u,s,c),n.push(f,f+1,f+2,f,f+3,f+1)}s(-.5,-.5,.5,.5,0,0,0,.125),s(-.45,-.45,.45,.25,.01,0,0,.4),s(-.45,_(30),.45,_(32),.015,.5,0,.5),s(-.45,_(60),.45,_(62),.015,.2,0,.75),this._fpsVertexBuffer=t.createRenderBuffer(e.ARRAY_BUFFER,new Float32Array(r),e.DYNAMIC_DRAW);var c=t.createRenderBuffer(e.ELEMENT_ARRAY_BUFFER,new Uint16Array(n)),f=[new a.PrimitiveAttribute("POSITION",this._fpsVertexBuffer,3,e.FLOAT,24,0),new a.PrimitiveAttribute("COLOR_0",this._fpsVertexBuffer,3,e.FLOAT,24,12)],h=new a.Primitive(f,n.length);h.setIndexBuffer(c),h.setBounds([-.5,-.5,0],[.5,.5,.015]),this._fpsRenderPrimitive=t.createRenderPrimitive(h,new d),this._fpsNode=new o.Node,this._fpsNode.addRenderPrimitive(this._fpsRenderPrimitive),this.addNode(this._fpsNode),this.addNode(this._sevenSegmentNode)}},{key:"begin",value:function(){this._startTime=m()}},{key:"end",value:function(){var t=m(),e=1e3/(t-this._prevFrameTime);if(this._prevFrameTime=t,this._fpsMin=this._frames?Math.min(this._fpsMin,e):e,this._frames++,t>this._prevGraphUpdateTime+this._fpsStep){var r=t-this._prevGraphUpdateTime;this._fpsAverage=Math.round(1e3/(r/this._frames)),this._updateGraph(this._fpsMin,this._fpsAverage),this._performanceMonitoring&&console.log("Average FPS: "+this._fpsAverage+" Min FPS: "+this._fpsMin),this._prevGraphUpdateTime=t,this._frames=0,this._fpsMin=0}}},{key:"_updateGraph",value:function(t,e){var r,n=(r=t,{r:Math.max(0,Math.min(1,1-r/60)),g:Math.max(0,Math.min(1,(r-15)/(h-15))),b:Math.max(0,Math.min(1,(r-15)/(h-15)))}),i=_(t-1),o=_(e+1),a=[v(this._lastSegment),o,.02,n.r,n.g,n.b,v(this._lastSegment+1),o,.02,n.r,n.g,n.b,v(this._lastSegment),i,.02,n.r,n.g,n.b,v(this._lastSegment+1),i,.02,n.r,n.g,n.b];n.r=.2,n.g=1,n.b=.2,this._lastSegment==l-1?(this._renderer.updateRenderBuffer(this._fpsVertexBuffer,new Float32Array(a),24*this._lastSegment*4),a=[v(0),_(h),.02,n.r,n.g,n.b,v(.25),_(h),.02,n.r,n.g,n.b,v(0),_(0),.02,n.r,n.g,n.b,v(.25),_(0),.02,n.r,n.g,n.b],this._renderer.updateRenderBuffer(this._fpsVertexBuffer,new Float32Array(a),0)):(a.push(v(this._lastSegment+1),_(h),.02,n.r,n.g,n.b,v(this._lastSegment+1.25),_(h),.02,n.r,n.g,n.b,v(this._lastSegment+1),_(0),.02,n.r,n.g,n.b,v(this._lastSegment+1.25),_(0),.02,n.r,n.g,n.b),this._renderer.updateRenderBuffer(this._fpsVertexBuffer,new Float32Array(a),24*this._lastSegment*4)),this._lastSegment=(this._lastSegment+1)%l,this._sevenSegmentNode.text=this._fpsAverage+" FP5"}},{key:"performanceMonitoring",get:function(){return this._performanceMonitoring},set:function(t){this._performanceMonitoring=t,this._fpsStep=t?1e3:250}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.InputRenderer=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=WebGLRenderingContext,h=new Uint8Array([255,255,255,1,255,255,255,2,191,191,191,4,204,204,204,5,219,219,219,7,204,204,204,10,216,216,216,13,210,210,210,17,206,206,206,21,206,206,206,26,206,206,206,31,205,205,205,36,200,200,200,42,201,201,201,47,201,201,201,52,201,201,201,57,201,201,201,61,200,200,200,65,203,203,203,68,238,238,238,135,250,250,250,200,249,249,249,201,249,249,249,201,250,250,250,201,250,250,250,201,249,249,249,201,249,249,249,201,250,250,250,200,238,238,238,135,203,203,203,68,200,200,200,65,201,201,201,61,201,201,201,57,201,201,201,52,201,201,201,47,200,200,200,42,205,205,205,36,206,206,206,31,206,206,206,26,206,206,206,21,210,210,210,17,216,216,216,13,204,204,204,10,219,219,219,7,204,204,204,5,191,191,191,4,255,255,255,2,255,255,255,1]),d=[1,1,1,.25],v=[1,1,1,1],_=[.5,.5,.5,.25],m={controllers:!0,lasers:!0,cursors:!0},p=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.ADDITIVE,t.state.cullFace=!1,t.state.blend=!0,t.state.blendFuncSrc=l.ONE,t.state.blendFuncDst=l.ONE,t.state.depthMask=!1,t.laser=t.defineSampler("diffuse"),t.laser.texture=new u.DataTexture(h,48,1),t.laserColor=t.defineUniform("laserColor",d),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"INPUT_LASER"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n\n uniform vec4 laserColor;\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n const float fadePoint = 0.5335;\n const float fadeEnd = 0.535;\n\n vec4 fragment_main() {\n vec2 uv = vTexCoord;\n float front_fade_factor = 1.0 - clamp(1.0 - (uv.y - fadePoint) / (1.0 - fadePoint), 0.0, 1.0);\n float back_fade_factor = clamp((uv.y - fadePoint) / (fadeEnd - fadePoint), 0.0, 1.0);\n vec4 color = laserColor * texture2D(diffuse, vTexCoord);\n float opacity = color.a * front_fade_factor * back_fade_factor;\n return vec4(color.rgb * opacity, opacity);\n }"}}]),e}(),y="\nattribute vec4 POSITION;\n\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vLuminance = POSITION.z;\n vOpacity = POSITION.w;\n\n // Billboarded, constant size vertex transform.\n vec4 screenPos = proj * view * model * vec4(0.0, 0.0, 0.0, 1.0);\n screenPos /= screenPos.w;\n screenPos.xy += POSITION.xy;\n return screenPos;\n}",b="\nprecision mediump float;\n\nuniform vec4 cursorColor;\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 fragment_main() {\n vec3 color = cursorColor.rgb * vLuminance;\n float opacity = cursorColor.a * vOpacity;\n return vec4(color * opacity, opacity);\n}",g=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.ADDITIVE,t.state.cullFace=!1,t.state.blend=!0,t.state.blendFuncSrc=l.ONE,t.state.depthMask=!1,t.cursorColor=t.defineUniform("cursorColor",v),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"INPUT_CURSOR"}},{key:"vertexSource",get:function(){return y}},{key:"fragmentSource",get:function(){return b}}]),e}(),M=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.ADDITIVE,t.state.cullFace=!1,t.state.blend=!0,t.state.blendFuncSrc=l.ONE,t.state.depthFunc=l.GEQUAL,t.state.depthMask=!1,t.cursorColor=t.defineUniform("cursorColor",_),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"INPUT_CURSOR_2"}},{key:"vertexSource",get:function(){return y}},{key:"fragmentSource",get:function(){return b}}]),e}();e.InputRenderer=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._maxInputElements=32,t._controllers=[],t._controllerNode=null,t._controllerNodeHandedness=null,t._lasers=null,t._cursors=null,t._activeControllers=0,t._activeLasers=0,t._activeCursors=0,t}return f(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this._controllers=[],this._controllerNode=null,this._controllerNodeHandedness=null,this._lasers=null,this._cursors=null,this._activeControllers=0,this._activeLasers=0,this._activeCursors=0}},{key:"setControllerMesh",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"right";this._controllerNode=t,this._controllerNode.visible=!1,this.addNode(this._controllerNode),this._controllerNodeHandedness=e}},{key:"addController",value:function(t){if(this._controllerNode){var e=null;this._activeControllers<this._controllers.length?e=this._controllers[this._activeControllers]:(e=this._controllerNode.clone(),this.addNode(e),this._controllers.push(e)),this._activeControllers=(this._activeControllers+1)%this._maxInputElements,e.matrix=t,e.visible=!0}}},{key:"addLaserPointer",value:function(t){!this._lasers&&this._renderer&&(this._lasers=[this._createLaserMesh()],this.addNode(this._lasers[0]));var e=null;this._activeLasers<this._lasers.length?e=this._lasers[this._activeLasers]:(e=this._lasers[0].clone(),this.addNode(e),this._lasers.push(e)),this._activeLasers=(this._activeLasers+1)%this._maxInputElements,e.matrix=t.transformMatrix,e.visible=!0}},{key:"addCursor",value:function(t){!this._cursors&&this._renderer&&(this._cursors=[this._createCursorMesh()],this.addNode(this._cursors[0]));var e=null;this._activeCursors<this._cursors.length?e=this._cursors[this._activeCursors]:(e=this._cursors[0].clone(),this.addNode(e),this._cursors.push(e)),this._activeCursors=(this._activeCursors+1)%this._maxInputElements,e.translation=t,e.visible=!0}},{key:"reset",value:function(t){if(t||(t=m),this._controllers&&t.controllers){var e=!0,r=!1,n=void 0;try{for(var i,o=this._controllers[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){i.value.visible=!1}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}this._activeControllers=0}if(this._lasers&&t.lasers){var a=!0,u=!1,s=void 0;try{for(var c,f=this._lasers[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){c.value.visible=!1}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}this._activeLasers=0}if(this._cursors&&t.cursors){var l=!0,h=!1,d=void 0;try{for(var v,_=this._cursors[Symbol.iterator]();!(l=(v=_.next()).done);l=!0){v.value.visible=!1}}catch(t){h=!0,d=t}finally{try{!l&&_.return&&_.return()}finally{if(h)throw d}}this._activeCursors=0}}},{key:"_createLaserMesh",value:function(){var t=this._renderer._gl,e=.005,r=[0,e,0,0,1,0,e,-1,0,0,0,-e,0,1,1,0,-e,-1,1,0,e,0,0,0,1,e,0,-1,0,0,-e,0,0,1,1,-e,0,-1,1,0,0,-e,0,0,1,0,-e,-1,0,0,0,e,0,1,1,0,e,-1,1,0,-e,0,0,0,1,-e,0,-1,0,0,e,0,0,1,1,e,0,-1,1,0],n=[0,1,2,1,3,2,4,5,6,5,7,6,8,9,10,9,11,10,12,13,14,13,15,14],i=this._renderer.createRenderBuffer(t.ARRAY_BUFFER,new Float32Array(r)),u=this._renderer.createRenderBuffer(t.ELEMENT_ARRAY_BUFFER,new Uint16Array(n)),s=n.length,c=[new a.PrimitiveAttribute("POSITION",i,3,t.FLOAT,20,0),new a.PrimitiveAttribute("TEXCOORD_0",i,2,t.FLOAT,20,12)],f=new a.Primitive(c,s);f.setIndexBuffer(u);var l=new p,h=this._renderer.createRenderPrimitive(f,l),d=new o.Node;return d.addRenderPrimitive(h),d}},{key:"_createCursorMesh",value:function(){for(var t=this._renderer._gl,e=[],r=[],n=2*Math.PI/16,i=0;i<16;++i){var u=i*n,s=Math.cos(u),c=Math.sin(u);e.push(.004*s,.004*c,1,.9),i>1&&r.push(0,i-1,i)}for(var f=0;f<16;++f){var l=f*n,h=Math.cos(l),d=Math.sin(l);if(e.push(.004*h,.004*d,.5,.75),e.push(.007*h,.007*d,0,0),f>0){var v=16+2*f;r.push(v-2,v-1,v),r.push(v-1,v+1,v)}}r.push(46,47,16),r.push(47,17,16);var _=this._renderer.createRenderBuffer(t.ARRAY_BUFFER,new Float32Array(e)),m=this._renderer.createRenderBuffer(t.ELEMENT_ARRAY_BUFFER,new Uint16Array(r)),p=r.length,y=[new a.PrimitiveAttribute("POSITION",_,4,t.FLOAT,16,0)],b=new a.Primitive(y,p);b.setIndexBuffer(m);var x=new g,T=new M,w=this._renderer.createRenderPrimitive(b,x),E=this._renderer.createRenderPrimitive(b,T),O=new o.Node;return O.addRenderPrimitive(w),O.addRenderPrimitive(E),O}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Scene=e.WebXRView=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(11),o=r(19),a=r(18),u=r(2),s=r(6);function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function f(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var h=e.WebXRView=function(t){function e(t,r,n){return c(this,e),f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t?t.projectionMatrix:null,r&&t?r.getViewMatrix(t):null,n&&t?n.getViewport(t):null,t?t.eye:"left"))}return l(e,i.RenderView),e}();e.Scene=function(t){function e(){c(this,e);var t=f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._timestamp=-1,t._frameDelta=0,t._statsStanding=!1,t._stats=null,t._statsEnabled=!1,t.enableStats(!0),t._inputRenderer=null,t._resetInputEndFrame=!0,t._lastTimestamp=0,t._hoverFrame=0,t._hoveredNodes=[],t.clear=!0,t}return l(e,u.Node),n(e,[{key:"setRenderer",value:function(t){this._setRenderer(t)}},{key:"loseRenderer",value:function(){this._renderer&&(this._stats=null,this._renderer=null,this._inputRenderer=null)}},{key:"updateInputSources",value:function(t,e){if(t.session.getInputSources){var r=t.session.getInputSources(),n=[],i=this._hoverFrame;this._hoverFrame++;var o=!0,a=!1,u=void 0;try{for(var c,f=r[Symbol.iterator]();!(o=(c=f.next()).done);o=!0){var l=c.value,h=t.getInputPose(l,e);if(h&&(h.gripMatrix&&this.inputRenderer.addController(h.gripMatrix),h.targetRay)){"tracked-pointer"==l.targetRayMode&&this.inputRenderer.addLaserPointer(h.targetRay);var d=this.hitTest(h.targetRay);if(d)this.inputRenderer.addCursor(d.intersection),d.node._hoverFrameId!=i&&d.node.onHoverStart(),d.node._hoverFrameId=this._hoverFrame,n.push(d.node);else{var v=s.vec3.fromValues(h.targetRay.origin.x,h.targetRay.origin.y,h.targetRay.origin.z);s.vec3.add(v,v,[1*h.targetRay.direction.x,1*h.targetRay.direction.y,1*h.targetRay.direction.z]),this.inputRenderer.addCursor(v)}}}}catch(t){a=!0,u=t}finally{try{!o&&f.return&&f.return()}finally{if(a)throw u}}var _=!0,m=!1,p=void 0;try{for(var y,b=this._hoveredNodes[Symbol.iterator]();!(_=(y=b.next()).done);_=!0){var g=y.value;g._hoverFrameId!=this._hoverFrame&&g.onHoverEnd()}}catch(t){m=!0,p=t}finally{try{!_&&b.return&&b.return()}finally{if(m)throw p}}this._hoveredNodes=n}}},{key:"handleSelect",value:function(t,e,r){var n=e.getInputPose(t,r);n&&this.handleSelectPointer(n.targetRay)}},{key:"handleSelectPointer",value:function(t){if(t){var e=this.hitTest(t);e&&e.node.handleSelect()}}},{key:"enableStats",value:function(t){t!=this._statsEnabled&&(this._statsEnabled=t,t?(this._stats=new a.StatsViewer,this._stats.selectable=!0,this.addNode(this._stats),this._statsStanding?this._stats.translation=[0,1.4,-.75]:this._stats.translation=[0,-.3,-.5],this._stats.scale=[.3,.3,.3],s.quat.fromEuler(this._stats.rotation,-45,0,0)):t||this._stats&&(this.removeNode(this._stats),this._stats=null))}},{key:"standingStats",value:function(t){this._statsStanding=t,this._stats&&(this._statsStanding?this._stats.translation=[0,1.4,-.75]:this._stats.translation=[0,-.3,-.5],this._stats.scale=[.3,.3,.3],s.quat.fromEuler(this._stats.rotation,-45,0,0))}},{key:"draw",value:function(t,e,r){var n=new i.RenderView;n.projectionMatrix=t,n.viewMatrix=e,r&&(n.eye=r),this.drawViewArray([n])}},{key:"drawXRFrame",value:function(t,e){if(this._renderer&&e){var r=this._renderer.gl,n=t.session.baseLayer;if(r){r.bindFramebuffer(r.FRAMEBUFFER,n.framebuffer),this.clear&&r.clear(r.COLOR_BUFFER_BIT|r.DEPTH_BUFFER_BIT);var i=[],o=!0,a=!1,u=void 0;try{for(var s,c=t.views[Symbol.iterator]();!(o=(s=c.next()).done);o=!0){var f=s.value;i.push(new h(f,e,n))}}catch(t){a=!0,u=t}finally{try{!o&&c.return&&c.return()}finally{if(a)throw u}}this.drawViewArray(i)}}}},{key:"drawViewArray",value:function(t){this._renderer&&this._renderer.drawViews(t,this)}},{key:"startFrame",value:function(){var t=this._timestamp;return this._timestamp=performance.now(),this._stats&&this._stats.begin(),this._frameDelta=t>=0?this._timestamp-t:0,this._update(this._timestamp,this._frameDelta),this._frameDelta}},{key:"endFrame",value:function(){this._inputRenderer&&this._resetInputEndFrame&&this._inputRenderer.reset(),this._stats&&this._stats.end()}},{key:"onLoadScene",value:function(t){return Promise.resolve()}},{key:"inputRenderer",get:function(){return this._inputRenderer||(this._inputRenderer=new o.InputRenderer,this.addNode(this._inputRenderer)),this._inputRenderer}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.VideoNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(7),a=r(2),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=WebGLRenderingContext,h=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.image=t.defineSampler("diffuse"),t.texCoordScaleOffset=t.defineUniform("texCoordScaleOffset",[1,1,0,0,1,1,0,0],4),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"VIDEO_PLAYER"}},{key:"vertexSource",get:function(){return"\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n return out_vec;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }"}}]),e}();e.VideoNode=function(t){function e(t){s(this,e);var r=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._video=t.video,r._displayMode=t.displayMode||"mono",r._video_texture=new u.VideoTexture(r._video),r}return f(e,a.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=[0,2,1,0,3,2],r=t.createRenderBuffer(l.ARRAY_BUFFER,new Float32Array([-1,1,0,0,0,1,1,0,1,0,1,-1,0,1,1,-1,-1,0,0,1])),n=t.createRenderBuffer(l.ELEMENT_ARRAY_BUFFER,new Uint16Array(e)),i=[new o.PrimitiveAttribute("POSITION",r,3,l.FLOAT,20,0),new o.PrimitiveAttribute("TEXCOORD_0",r,2,l.FLOAT,20,12)],a=new o.Primitive(i,e.length);a.setIndexBuffer(n),a.setBounds([-1,-1,0],[1,1,.015]);var u=new h;switch(u.image.texture=this._video_texture,this._displayMode){case"mono":u.texCoordScaleOffset.value=[1,1,0,0,1,1,0,0];break;case"stereoTopBottom":u.texCoordScaleOffset.value=[1,.5,0,0,1,.5,0,.5];break;case"stereoLeftRight":u.texCoordScaleOffset.value=[.5,1,0,0,.5,1,.5,0]}var s=t.createRenderPrimitive(a,u);this.addRenderPrimitive(s)}},{key:"aspectRatio",get:function(){var t=this._video.videoWidth,e=this._video.videoHeight;switch(this._displayMode){case"stereoTopBottom":e*=.5;break;case"stereoLeftRight":t*=.5}return e&&t?t/e:1}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.SkyboxNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(7),a=r(2),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=WebGLRenderingContext,h=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.SKY,t.state.depthFunc=l.LEQUAL,t.state.depthMask=!1,t.image=t.defineSampler("diffuse"),t.texCoordScaleOffset=t.defineUniform("texCoordScaleOffset",[1,1,0,0,1,1,0,0],4),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"SKYBOX"}},{key:"vertexSource",get:function(){return"\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n // Drop the translation portion of the view matrix\n view[3].xyz = vec3(0.0, 0.0, 0.0);\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n\n // Returning the W component for both Z and W forces the geometry depth to\n // the far plane. When combined with a depth func of LEQUAL this makes the\n // sky write to any depth fragment that has not been written to yet.\n return out_vec.xyww;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }"}}]),e}();e.SkyboxNode=function(t){function e(t){s(this,e);var r=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._url=t.url,r._displayMode=t.displayMode||"mono",r._rotationY=t.rotationY||0,r}return f(e,a.Node),n(e,[{key:"onRendererChanged",value:function(t){for(var e=[],r=[],n=0;n<=40;++n)for(var i=n*Math.PI/40,a=Math.sin(i),s=Math.cos(i),c=41*n,f=41*(n+1),d=0;d<=40;++d){var v=2*d*Math.PI/40+this._rotationY,_=Math.sin(v)*a,m=s,p=-Math.cos(v)*a,y=d/40,b=n/40;if(e.push(_,m,p,y,b),n<40&&d<40){var g=c+d,M=f+d;r.push(g,M,g+1,M,M+1,g+1)}}var x=t.createRenderBuffer(l.ARRAY_BUFFER,new Float32Array(e)),T=t.createRenderBuffer(l.ELEMENT_ARRAY_BUFFER,new Uint16Array(r)),w=[new o.PrimitiveAttribute("POSITION",x,3,l.FLOAT,20,0),new o.PrimitiveAttribute("TEXCOORD_0",x,2,l.FLOAT,20,12)],E=new o.Primitive(w,r.length);E.setIndexBuffer(T);var O=new h;switch(O.image.texture=new u.UrlTexture(this._url),this._displayMode){case"mono":O.texCoordScaleOffset.value=[1,1,0,0,1,1,0,0];break;case"stereoTopBottom":O.texCoordScaleOffset.value=[1,.5,0,0,1,.5,0,.5];break;case"stereoLeftRight":O.texCoordScaleOffset.value=[.5,1,0,0,.5,1,.5,0]}var R=t.createRenderPrimitive(E,O);this.addRenderPrimitive(R)}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Gltf2Loader=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(13),o=r(2),a=r(7),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var c=WebGLRenderingContext,f=1313821514,l=5130562;function h(t){return!!t.match(/^data:/)}function d(t,e){return function(t){var e=new RegExp("^"+window.location.protocol,"i");return!!t.match(e)}(t)||h(t)?t:e+t}function v(t){switch(t){case"SCALAR":return 1;case"VEC2":return 2;case"VEC3":return 3;case"VEC4":return 4;default:return 0}}e.Gltf2Loader=function(){function t(e){s(this,t),this.renderer=e,this._gl=e._gl}return n(t,[{key:"loadFromUrl",value:function(t){var e=this;return fetch(t).then(function(r){var n=t.lastIndexOf("/"),i=0!==n?t.substring(0,n+1):"";if(t.endsWith(".gltf"))return r.json().then(function(t){return e.loadFromJson(t,i)});if(t.endsWith(".glb"))return r.arrayBuffer().then(function(t){return e.loadFromBinary(t,i)});throw new Error("Unrecognized file extension")})}},{key:"loadFromBinary",value:function(t,e){var r=new DataView(t,0,12),n=r.getUint32(0,!0),i=r.getUint32(4,!0),o=r.getUint32(8,!0);if(1179937895!=n)throw new Error("Invalid magic string in binary header.");if(2!=i)throw new Error("Incompatible version in binary header.");for(var a={},u=12;u<o;){var s=new DataView(t,u,8),c=s.getUint32(0,!0);a[s.getUint32(4,!0)]=t.slice(u+8,u+8+c),u+=c+8}if(!a[f])throw new Error("File contained no json chunk.");var h=new TextDecoder("utf-8").decode(a[f]),d=JSON.parse(h);return this.loadFromJson(d,e,a[l])}},{key:"loadFromJson",value:function(t,e,r){if(!t.asset)throw new Error("Missing asset description.");if("2.0"!=t.asset.minVersion&&"2.0"!=t.asset.version)throw new Error("Incompatible asset version.");var n=[];if(r)n[0]=new p({},e,r);else{var s=!0,f=!1,l=void 0;try{for(var h,d=t.buffers[Symbol.iterator]();!(s=(h=d.next()).done);s=!0){var y=h.value;n.push(new p(y,e))}}catch(t){f=!0,l=t}finally{try{!s&&d.return&&d.return()}finally{if(f)throw l}}}var b=[],g=!0,M=!1,x=void 0;try{for(var T,w=t.bufferViews[Symbol.iterator]();!(g=(T=w.next()).done);g=!0){var E=T.value;b.push(new m(E,n))}}catch(t){M=!0,x=t}finally{try{!g&&w.return&&w.return()}finally{if(M)throw x}}var O=[];if(t.images){var R=!0,P=!1,S=void 0;try{for(var A,N=t.images[Symbol.iterator]();!(R=(A=N.next()).done);R=!0){var C=A.value;O.push(new p(C,e))}}catch(t){P=!0,S=t}finally{try{!R&&N.return&&N.return()}finally{if(P)throw S}}}var I=[];if(t.textures){var k=!0,L=!1,F=void 0;try{for(var D,B=t.textures[Symbol.iterator]();!(k=(D=B.next()).done);k=!0){var j=D.value,U=O[j.source].texture(b);if(j.sampler){var V=V[j.sampler];U.sampler.minFilter=V.minFilter,U.sampler.magFilter=V.magFilter,U.sampler.wrapS=V.wrapS,U.sampler.wrapT=V.wrapT}I.push(U)}}catch(t){L=!0,F=t}finally{try{!k&&B.return&&B.return()}finally{if(L)throw F}}}function Y(t){return t?I[t.index]:null}var G=[];if(t.materials){var H=!0,q=!1,X=void 0;try{for(var W,K=t.materials[Symbol.iterator]();!(H=(W=K.next()).done);H=!0){var z=W.value,Q=new i.PbrMaterial,J=z.pbrMetallicRoughness||{};switch(Q.baseColorFactor.value=J.baseColorFactor||[1,1,1,1],Q.baseColor.texture=Y(J.baseColorTexture),Q.metallicRoughnessFactor.value=[J.metallicFactor||1,J.roughnessFactor||1],Q.metallicRoughness.texture=Y(J.metallicRoughnessTexture),Q.normal.texture=Y(t.normalTexture),Q.occlusion.texture=Y(t.occlusionTexture),Q.occlusionStrength.value=t.occlusionTexture&&t.occlusionTexture.strength?t.occlusionTexture.strength:1,Q.emissiveFactor.value=z.emissiveFactor||[0,0,0],Q.emissive.texture=Y(t.emissiveTexture),!Q.emissive.texture&&t.emissiveFactor&&(Q.emissive.texture=new u.ColorTexture(1,1,1,1)),z.alphaMode){case"BLEND":case"MASK":Q.state.blend=!0;break;default:Q.state.blend=!1}Q.state.cullFace=!z.doubleSided,G.push(Q)}}catch(t){q=!0,X=t}finally{try{!H&&K.return&&K.return()}finally{if(q)throw X}}}var Z=t.accessors,$=[],tt=!0,et=!1,rt=void 0;try{for(var nt,it=t.meshes[Symbol.iterator]();!(tt=(nt=it.next()).done);tt=!0){var ot=nt.value,at=new _;$.push(at);var ut=!0,st=!1,ct=void 0;try{for(var ft,lt=ot.primitives[Symbol.iterator]();!(ut=(ft=lt.next()).done);ut=!0){var ht=ft.value,dt=null;dt="material"in ht?G[ht.material]:new i.PbrMaterial;var vt=[],_t=0,mt=null,pt=null;for(var yt in ht.attributes){var bt=Z[ht.attributes[yt]],gt=b[bt.bufferView];_t=bt.count;var Mt=new a.PrimitiveAttribute(yt,gt.renderBuffer(this.renderer,c.ARRAY_BUFFER),v(bt.type),bt.componentType,gt.byteStride||0,bt.byteOffset||0);Mt.normalized=bt.normalized||!1,"POSITION"==yt&&(mt=bt.min,pt=bt.max),vt.push(Mt)}var xt=new a.Primitive(vt,_t,ht.mode);if("indices"in ht){var Tt=Z[ht.indices],wt=b[Tt.bufferView];xt.setIndexBuffer(wt.renderBuffer(this.renderer,c.ELEMENT_ARRAY_BUFFER),Tt.byteOffset||0,Tt.componentType),xt.indexType=Tt.componentType,xt.indexByteOffset=Tt.byteOffset||0,xt.elementCount=Tt.count}mt&&pt&&xt.setBounds(mt,pt),at.primitives.push(this.renderer.createRenderPrimitive(xt,dt))}}catch(t){st=!0,ct=t}finally{try{!ut&<.return&<.return()}finally{if(st)throw ct}}}}catch(t){et=!0,rt=t}finally{try{!tt&&it.return&&it.return()}finally{if(et)throw rt}}var Et=new o.Node,Ot=t.scenes[t.scene],Rt=!0,Pt=!1,St=void 0;try{for(var At,Nt=Ot.nodes[Symbol.iterator]();!(Rt=(At=Nt.next()).done);Rt=!0){var Ct=At.value,It=t.nodes[Ct];Et.addNode(this.processNodes(It,t.nodes,$))}}catch(t){Pt=!0,St=t}finally{try{!Rt&&Nt.return&&Nt.return()}finally{if(Pt)throw St}}return Et}},{key:"processNodes",value:function(t,e,r){var n=new o.Node;if(n.name=t.name,"mesh"in t){var i=r[t.mesh],a=!0,u=!1,s=void 0;try{for(var c,f=i.primitives[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){var l=c.value;n.addRenderPrimitive(l)}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}}if(t.matrix?n.matrix=new Float32Array(t.matrix):(t.translation||t.rotation||t.scale)&&(t.translation&&(n.translation=new Float32Array(t.translation)),t.rotation&&(n.rotation=new Float32Array(t.rotation)),t.scale&&(n.scale=new Float32Array(t.scale))),t.children){var h=!0,d=!1,v=void 0;try{for(var _,m=t.children[Symbol.iterator]();!(h=(_=m.next()).done);h=!0){var p=e[_.value];n.addNode(this.processNodes(p,e,r))}}catch(t){d=!0,v=t}finally{try{!h&&m.return&&m.return()}finally{if(d)throw v}}}return n}}]),t}();var _=function t(){s(this,t),this.primitives=[]},m=function(){function t(e,r){s(this,t),this.buffer=r[e.buffer],this.byteOffset=e.byteOffset||0,this.byteLength=e.byteLength||null,this.byteStride=e.byteStride,this._viewPromise=null,this._renderBuffer=null}return n(t,[{key:"dataView",value:function(){var t=this;return this._viewPromise||(this._viewPromise=this.buffer.arrayBuffer().then(function(e){return new DataView(e,t.byteOffset,t.byteLength)})),this._viewPromise}},{key:"renderBuffer",value:function(t,e){return this._renderBuffer||(this._renderBuffer=t.createRenderBuffer(e,this.dataView())),this._renderBuffer}}]),t}(),p=function(){function t(e,r,n){s(this,t),this.json=e,this.baseUrl=r,this._dataPromise=null,this._texture=null,n&&(this._dataPromise=Promise.resolve(n))}return n(t,[{key:"arrayBuffer",value:function(){if(!this._dataPromise){if(h(this.json.uri)){var t=this.json.uri.replace("data:application/octet-stream;base64,",""),e=Uint8Array.from(atob(t),function(t){return t.charCodeAt(0)});return this._dataPromise=Promise.resolve(e.buffer),this._dataPromise}this._dataPromise=fetch(d(this.json.uri,this.baseUrl)).then(function(t){return t.arrayBuffer()})}return this._dataPromise}},{key:"texture",value:function(t){var e=this;if(!this._texture){var r=new Image;if(this._texture=new u.ImageTexture(r),this.json.uri)h(this.json.uri)?r.src=this.json.uri:r.src=""+this.baseUrl+this.json.uri;else t[this.json.bufferView].dataView().then(function(t){var n=new Blob([t],{type:e.json.mimeType});r.src=window.URL.createObjectURL(n)})}return this._texture}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Gltf2Node=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(2),o=r(23);var a=new WeakMap;e.Gltf2Node=function(t){function e(t){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e);var r=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._url=t.url,r._promise=null,r._resolver=null,r._rejecter=null,r}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,i.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=this,r=a.get(t);r||(r=new o.Gltf2Loader(t),a.set(t,r)),!this._resolver&&this._promise&&(this._promise=null),this._ensurePromise(),r.loadFromUrl(this._url).then(function(t){e.addNode(t),e._resolver(t.waitForComplete()),e._resolver=null,e._rejecter=null}).catch(function(t){e._rejecter(t),e._resolver=null,e._rejecter=null})}},{key:"_ensurePromise",value:function(){var t=this;return this._promise||(this._promise=new Promise(function(e,r){t._resolver=e,t._rejecter=r})),this._promise}},{key:"waitForComplete",value:function(){return this._ensurePromise()}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.CubeSeaNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(8),u=r(14),s=r(6);function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function f(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var h=function(t){function e(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];c(this,e);var r=f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r.heavy=t,r.baseColor=r.defineSampler("baseColor"),r}return l(e,i.Material),n(e,[{key:"materialName",get:function(){return"CUBE_SEA"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n attribute vec3 NORMAL;\n\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n const vec3 lightDir = vec3(0.75, 0.5, 1.0);\n const vec3 ambientColor = vec3(0.5, 0.5, 0.5);\n const vec3 lightColor = vec3(0.75, 0.75, 0.75);\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 normalRotated = vec3(model * vec4(NORMAL, 0.0));\n float lightFactor = max(dot(normalize(lightDir), normalRotated), 0.0);\n vLight = ambientColor + (lightColor * lightFactor);\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return this.heavy?"\n precision mediump float;\n\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec2 dimensions = vec2(64, 64);\n float seed = 0.42;\n\n vec2 hash( vec2 p ) {\n p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3)));\n return fract(sin(p)*18.5453);\n }\n\n vec3 hash3( vec2 p ) {\n vec3 q = vec3( dot(p,vec2(127.1,311.7)),\n dot(p,vec2(269.5,183.3)),\n dot(p,vec2(419.2,371.9)) );\n return fract(sin(q)*43758.5453);\n }\n\n float iqnoise( in vec2 x, float u, float v ) {\n vec2 p = floor(x);\n vec2 f = fract(x);\n float k = 1.0+63.0*pow(1.0-v,4.0);\n float va = 0.0;\n float wt = 0.0;\n for( int j=-2; j<=2; j++ )\n for( int i=-2; i<=2; i++ ) {\n vec2 g = vec2( float(i),float(j) );\n vec3 o = hash3( p + g )*vec3(u,u,1.0);\n vec2 r = g - f + o.xy;\n float d = dot(r,r);\n float ww = pow( 1.0-smoothstep(0.0,1.414,sqrt(d)), k );\n va += o.z*ww;\n wt += ww;\n }\n return va/wt;\n }\n\n // return distance, and cell id\n vec2 voronoi( in vec2 x ) {\n vec2 n = floor( x );\n vec2 f = fract( x );\n vec3 m = vec3( 8.0 );\n for( int j=-1; j<=1; j++ )\n for( int i=-1; i<=1; i++ ) {\n vec2 g = vec2( float(i), float(j) );\n vec2 o = hash( n + g );\n vec2 r = g - f + (0.5+0.5*sin(seed+6.2831*o));\n float d = dot( r, r );\n if( d<m.x )\n m = vec3( d, o );\n }\n return vec2( sqrt(m.x), m.y+m.z );\n }\n\n vec4 fragment_main() {\n vec2 uv = ( vTexCoord );\n uv *= vec2( 10., 10. );\n uv += seed;\n vec2 p = 0.5 - 0.5*sin( 0.*vec2(1.01,1.71) );\n\n vec2 c = voronoi( uv );\n vec3 col = vec3( c.y / 2. );\n\n float f = iqnoise( 1. * uv + c.y, p.x, p.y );\n col *= 1.0 + .25 * vec3( f );\n\n return vec4(vLight, 1.0) * texture2D(diffuse, vTexCoord) * vec4( col, 1. );\n }":"\n precision mediump float;\n uniform sampler2D baseColor;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec4 fragment_main() {\n return vec4(vLight, 1.0) * texture2D(baseColor, vTexCoord);\n }"}}]),e}();e.CubeSeaNode=function(t){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};c(this,e);var r=f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r.heavyGpu=!!t.heavyGpu,r.cubeCount=t.cubeCount||(r.heavyGpu?12:10),r.cubeScale=t.cubeScale||1,r.halfOnly=!!t.halfOnly,r.autoRotate=!!t.autoRotate,r._texture=new a.UrlTexture(t.imageUrl||"media/textures/cube-sea.png"),r._material=new h(r.heavyGpu),r._material.baseColor.texture=r._texture,r._renderPrimitive=null,r}return l(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this._renderPrimitive=null;var e=new u.BoxBuilder;e.pushCube([0,.25,-.8],.1),e.pushCube([.8,.25,0],.1),e.pushCube([0,.25,.8],.1),e.pushCube([-.8,.25,0],.1);var r=e.finishPrimitive(t);return this.heroNode=t.createMesh(r,this._material),this.rebuildCubes(e),this.cubeSeaNode=new o.Node,this.cubeSeaNode.addRenderPrimitive(this._renderPrimitive),this.addNode(this.cubeSeaNode),this.addNode(this.heroNode),this.waitForComplete()}},{key:"rebuildCubes",value:function(t){if(this._renderer){t?t.clear():t=new u.BoxBuilder;for(var e=.4*this.cubeScale,r=.5*this.cubeCount,n=0;n<this.cubeCount;++n)for(var i=0;i<this.cubeCount;++i)for(var o=0;o<this.cubeCount;++o){var a=[n-r,i-r,o-r];this.halfOnly&&a[0]<0||(0==a[0]&&0==a[1]&&0==a[2]||t.pushCube(a,e))}this.cubeCount>12&&(t.indexType=5125);var s=t.finishPrimitive(this._renderer);this._renderPrimitive?this._renderPrimitive.setPrimitive(s):this._renderPrimitive=this._renderer.createRenderPrimitive(s,this._material)}}},{key:"onUpdate",value:function(t,e){this.autoRotate&&s.mat4.fromRotation(this.cubeSeaNode.matrix,t/500,[0,-1,0]),s.mat4.fromRotation(this.heroNode.matrix,t/2e3,[0,1,0])}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.DropShadowNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(9);function u(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function c(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var f=WebGLRenderingContext,l=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.state.blendFuncSrc=f.ONE,t.state.blendFuncDst=f.ONE_MINUS_SRC_ALPHA,t.state.depthFunc=f.LEQUAL,t.state.depthMask=!1,t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"DROP_SHADOW_MATERIAL"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying float vShadow;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vShadow = TEXCOORD_0.x;\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n varying float vShadow;\n\n vec4 fragment_main() {\n return vec4(0.0, 0.0, 0.0, vShadow);\n }"}}]),e}();e.DropShadowNode=function(t){function e(t,r){return u(this,e),s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this))}return c(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=new a.PrimitiveStream;e.startGeometry(),e.pushVertex(0,.01,0,.7);for(var r=2*Math.PI/32,n=void 0,i=0;i<32;++i){n=e.nextVertexIndex;var o=i*r,u=Math.cos(o),s=Math.sin(o);e.pushVertex(.6*u,.01,.6*s,.3),e.pushVertex(1*u,.01,1*s,0),i>0&&(e.pushTriangle(0,n,n-2),e.pushTriangle(n,n+1,n-1),e.pushTriangle(n,n-1,n-2))}e.pushTriangle(0,1,n),e.pushTriangle(1,2,n+1),e.pushTriangle(1,n+1,n),e.endGeometry();var c=e.finishPrimitive(t);this._shadowRenderPrimitive=t.createRenderPrimitive(c,new l),this.addRenderPrimitive(this._shadowRenderPrimitive)}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.ButtonNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(9);function u(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function c(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var f=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.defineUniform("hoverAmount",0),t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"BUTTON_MATERIAL"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n\n uniform float hoverAmount;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n float scale = mix(1.0, 1.1, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform float hoverAmount;\n\n const vec4 default_color = vec4(0.75, 0.75, 0.75, 0.85);\n const vec4 hover_color = vec4(0.9, 0.9,\n 0.9, 1);\n\n vec4 fragment_main() {\n return mix(default_color, hover_color, hoverAmount);\n }"}}]),e}(),l=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.defineUniform("hoverAmount",0),t.icon=t.defineSampler("icon"),t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"BUTTON_ICON_MATERIAL"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n uniform float hoverAmount;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n float scale = mix(1.0, 1.1, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform sampler2D icon;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(icon, vTexCoord);\n }"}}]),e}();e.ButtonNode=function(t){function e(t,r){u(this,e);var n=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return n.selectable=!0,n._selectHandler=r,n._iconTexture=t,n._hovered=!1,n._hoverT=0,n}return c(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=new a.PrimitiveStream,r=.0025,n=.05,i=n-.025;e.startGeometry();for(var o=0;o<32;++o){var u=o*(2*Math.PI/32),s=.025*Math.cos(u),c=.025*Math.sin(u);switch(Math.floor(o/8)){case 0:s+=i,c+=i;break;case 1:s-=i,c+=i;break;case 2:s-=i,c-=i;break;case 3:s+=i,c-=i}e.pushVertex(s,c,-r,0,0,0,0,1),o>1&&e.pushTriangle(0,o-1,o)}e.endGeometry();var h=e.finishPrimitive(t);this._buttonRenderPrimitive=t.createRenderPrimitive(h,new f),this.addRenderPrimitive(this._buttonRenderPrimitive),n=.035,e.clear(),e.startGeometry(),e.pushVertex(-n,n,r,0,0,0,0,1),e.pushVertex(-n,-n,r,0,1,0,0,1),e.pushVertex(n,-n,r,1,1,0,0,1),e.pushVertex(n,n,r,1,0,0,0,1),e.pushTriangle(0,1,2),e.pushTriangle(0,2,3),e.endGeometry();var d=e.finishPrimitive(t),v=new l;v.icon.texture=this._iconTexture,this._iconRenderPrimitive=t.createRenderPrimitive(d,v),this.addRenderPrimitive(this._iconRenderPrimitive)}},{key:"onHoverStart",value:function(){this._hovered=!0}},{key:"onHoverEnd",value:function(){this._hovered=!1}},{key:"_updateHoverState",value:function(){var t=this._hoverT/200,e=t<.5?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1;this._buttonRenderPrimitive.uniforms.hoverAmount.value=e,this._iconRenderPrimitive.uniforms.hoverAmount.value=e}},{key:"onUpdate",value:function(t,e){this._hovered&&this._hoverT<200?(this._hoverT=Math.min(200,this._hoverT+e),this._updateHoverState()):!this._hovered&&this._hoverT>0&&(this._hoverT=Math.max(0,this._hoverT-e),this._updateHoverState())}},{key:"iconTexture",get:function(){return this._iconTexture},set:function(t){this._iconTexture!=t&&(this._iconTexture=t,this._iconRenderPrimitive.samplers.icon.texture=t)}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.BoundsRenderer=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7);function u(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function c(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var f=WebGLRenderingContext,l=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.state.blendFuncSrc=f.SRC_ALPHA,t.state.blendFuncDst=f.ONE,t.state.depthTest=!1,t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"BOUNDS_RENDERER"}},{key:"vertexSource",get:function(){return"\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n\n vec4 fragment_main() {\n return vec4(0.0, 1.0, 0.0, 0.3);\n }"}}]),e}();e.BoundsRenderer=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._stageBounds=null,t}return c(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this.stageBounds=this._stageBounds}},{key:"stageBounds",get:function(){return this._stageBounds},set:function(t){if(this._stageBounds&&this.clearRenderPrimitives(),this._stageBounds=t,t&&0!==t.length&&this._renderer){for(var e=[],r=[],n=t.geometry.length,i=0;i<n;i++){var o=t.geometry[i];e.push(o.x,0,o.z),r.push(i,0===i?n-1:i-1,n)}e.push(0,0,0);var u=this._renderer.createRenderBuffer(f.ARRAY_BUFFER,new Float32Array(e)),s=this._renderer.createRenderBuffer(f.ELEMENT_ARRAY_BUFFER,new Uint16Array(r)),c=[new a.PrimitiveAttribute("POSITION",u,3,f.FLOAT,12,0)],h=new a.Primitive(c,r.length);h.setIndexBuffer(s);var d=this._renderer.createRenderPrimitive(h,new l);this.addRenderPrimitive(d)}}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();e.Program=function(){function t(e,r,n,i,o){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this._gl=e,this.program=e.createProgram(),this.attrib=null,this.uniform=null,this.defines={},this._firstUse=!0,this._nextUseCallbacks=[];var a="";if(o)for(var u in o)this.defines[u]=o[u],a+="#define "+u+" "+o[u]+"\n";if(this._vertShader=e.createShader(e.VERTEX_SHADER),e.attachShader(this.program,this._vertShader),e.shaderSource(this._vertShader,a+r),e.compileShader(this._vertShader),this._fragShader=e.createShader(e.FRAGMENT_SHADER),e.attachShader(this.program,this._fragShader),e.shaderSource(this._fragShader,a+n),e.compileShader(this._fragShader),i)for(var s in this.attrib={},i)e.bindAttribLocation(this.program,i[s],s),this.attrib[s]=i[s];e.linkProgram(this.program)}return n(t,[{key:"onNextUse",value:function(t){this._nextUseCallbacks.push(t)}},{key:"use",value:function(){var t=this._gl;if(this._firstUse){if(this._firstUse=!1,t.getProgramParameter(this.program,t.LINK_STATUS)){if(!this.attrib){this.attrib={};for(var e=t.getProgramParameter(this.program,t.ACTIVE_ATTRIBUTES),r=0;r<e;r++){var n=t.getActiveAttrib(this.program,r);this.attrib[n.name]=t.getAttribLocation(this.program,n.name)}}this.uniform={};for(var i=t.getProgramParameter(this.program,t.ACTIVE_UNIFORMS),o="",a=0;a<i;a++){o=t.getActiveUniform(this.program,a).name.replace("[0]",""),this.uniform[o]=t.getUniformLocation(this.program,o)}}else t.getShaderParameter(this._vertShader,t.COMPILE_STATUS)?t.getShaderParameter(this._fragShader,t.COMPILE_STATUS)?console.error("Program link error: "+t.getProgramInfoLog(this.program)):console.error("Fragment shader compile error: "+t.getShaderInfoLog(this._fragShader)):console.error("Vertex shader compile error: "+t.getShaderInfoLog(this._vertShader)),t.deleteProgram(this.program),this.program=null;t.deleteShader(this._vertShader),t.deleteShader(this._fragShader)}if(t.useProgram(this.program),this._nextUseCallbacks.length){var u=!0,s=!1,c=void 0;try{for(var f,l=this._nextUseCallbacks[Symbol.iterator]();!(u=(f=l.next()).done);u=!0){(0,f.value)(this)}}catch(t){s=!0,c=t}finally{try{!u&&l.return&&l.return()}finally{if(s)throw c}}this._nextUseCallbacks=[]}}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"fromValues",function(){return a}),r.d(e,"copy",function(){return u}),r.d(e,"set",function(){return s}),r.d(e,"add",function(){return c}),r.d(e,"subtract",function(){return f}),r.d(e,"multiply",function(){return l}),r.d(e,"divide",function(){return h}),r.d(e,"ceil",function(){return d}),r.d(e,"floor",function(){return v}),r.d(e,"min",function(){return _}),r.d(e,"max",function(){return m}),r.d(e,"round",function(){return p}),r.d(e,"scale",function(){return y}),r.d(e,"scaleAndAdd",function(){return b}),r.d(e,"distance",function(){return g}),r.d(e,"squaredDistance",function(){return M}),r.d(e,"length",function(){return x}),r.d(e,"squaredLength",function(){return T}),r.d(e,"negate",function(){return w}),r.d(e,"inverse",function(){return E}),r.d(e,"normalize",function(){return O}),r.d(e,"dot",function(){return R}),r.d(e,"cross",function(){return P}),r.d(e,"lerp",function(){return S}),r.d(e,"random",function(){return A}),r.d(e,"transformMat2",function(){return N}),r.d(e,"transformMat2d",function(){return C}),r.d(e,"transformMat3",function(){return I}),r.d(e,"transformMat4",function(){return k}),r.d(e,"str",function(){return L}),r.d(e,"exactEquals",function(){return F}),r.d(e,"equals",function(){return D}),r.d(e,"len",function(){return B}),r.d(e,"sub",function(){return j}),r.d(e,"mul",function(){return U}),r.d(e,"div",function(){return V}),r.d(e,"dist",function(){return Y}),r.d(e,"sqrDist",function(){return G}),r.d(e,"sqrLen",function(){return H}),r.d(e,"forEach",function(){return q});var n=r(0);function i(){let t=new n.ARRAY_TYPE(2);return t[0]=0,t[1]=0,t}function o(t){let e=new n.ARRAY_TYPE(2);return e[0]=t[0],e[1]=t[1],e}function a(t,e){let r=new n.ARRAY_TYPE(2);return r[0]=t,r[1]=e,r}function u(t,e){return t[0]=e[0],t[1]=e[1],t}function s(t,e,r){return t[0]=e,t[1]=r,t}function c(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t}function f(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t}function l(t,e,r){return t[0]=e[0]*r[0],t[1]=e[1]*r[1],t}function h(t,e,r){return t[0]=e[0]/r[0],t[1]=e[1]/r[1],t}function d(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t}function v(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t}function _(t,e,r){return t[0]=Math.min(e[0],r[0]),t[1]=Math.min(e[1],r[1]),t}function m(t,e,r){return t[0]=Math.max(e[0],r[0]),t[1]=Math.max(e[1],r[1]),t}function p(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t}function y(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t}function b(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t}function g(t,e){var r=e[0]-t[0],n=e[1]-t[1];return Math.sqrt(r*r+n*n)}function M(t,e){var r=e[0]-t[0],n=e[1]-t[1];return r*r+n*n}function x(t){var e=t[0],r=t[1];return Math.sqrt(e*e+r*r)}function T(t){var e=t[0],r=t[1];return e*e+r*r}function w(t,e){return t[0]=-e[0],t[1]=-e[1],t}function E(t,e){return t[0]=1/e[0],t[1]=1/e[1],t}function O(t,e){var r=e[0],n=e[1],i=r*r+n*n;return i>0&&(i=1/Math.sqrt(i),t[0]=e[0]*i,t[1]=e[1]*i),t}function R(t,e){return t[0]*e[0]+t[1]*e[1]}function P(t,e,r){var n=e[0]*r[1]-e[1]*r[0];return t[0]=t[1]=0,t[2]=n,t}function S(t,e,r,n){var i=e[0],o=e[1];return t[0]=i+n*(r[0]-i),t[1]=o+n*(r[1]-o),t}function A(t,e){e=e||1;var r=2*n.RANDOM()*Math.PI;return t[0]=Math.cos(r)*e,t[1]=Math.sin(r)*e,t}function N(t,e,r){var n=e[0],i=e[1];return t[0]=r[0]*n+r[2]*i,t[1]=r[1]*n+r[3]*i,t}function C(t,e,r){var n=e[0],i=e[1];return t[0]=r[0]*n+r[2]*i+r[4],t[1]=r[1]*n+r[3]*i+r[5],t}function I(t,e,r){var n=e[0],i=e[1];return t[0]=r[0]*n+r[3]*i+r[6],t[1]=r[1]*n+r[4]*i+r[7],t}function k(t,e,r){let n=e[0],i=e[1];return t[0]=r[0]*n+r[4]*i+r[12],t[1]=r[1]*n+r[5]*i+r[13],t}function L(t){return"vec2("+t[0]+", "+t[1]+")"}function F(t,e){return t[0]===e[0]&&t[1]===e[1]}function D(t,e){let r=t[0],i=t[1],o=e[0],a=e[1];return Math.abs(r-o)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(i-a)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(a))}const B=x,j=f,U=l,V=h,Y=g,G=M,H=T,q=function(){let t=i();return function(e,r,n,i,o,a){let u,s;for(r||(r=2),n||(n=0),s=i?Math.min(i*r+n,e.length):e.length,u=n;u<s;u+=r)t[0]=e[u],t[1]=e[u+1],o(t,t,a),e[u]=t[0],e[u+1]=t[1];return e}}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return a}),r.d(e,"clone",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"fromRotationTranslationValues",function(){return c}),r.d(e,"fromRotationTranslation",function(){return f}),r.d(e,"fromTranslation",function(){return l}),r.d(e,"fromRotation",function(){return h}),r.d(e,"fromMat4",function(){return d}),r.d(e,"copy",function(){return v}),r.d(e,"identity",function(){return _}),r.d(e,"set",function(){return m}),r.d(e,"getReal",function(){return p}),r.d(e,"getDual",function(){return y}),r.d(e,"setReal",function(){return b}),r.d(e,"setDual",function(){return g}),r.d(e,"getTranslation",function(){return M}),r.d(e,"translate",function(){return x}),r.d(e,"rotateX",function(){return T}),r.d(e,"rotateY",function(){return w}),r.d(e,"rotateZ",function(){return E}),r.d(e,"rotateByQuatAppend",function(){return O}),r.d(e,"rotateByQuatPrepend",function(){return R}),r.d(e,"rotateAroundAxis",function(){return P}),r.d(e,"add",function(){return S}),r.d(e,"multiply",function(){return A}),r.d(e,"mul",function(){return N}),r.d(e,"scale",function(){return C}),r.d(e,"dot",function(){return I}),r.d(e,"lerp",function(){return k}),r.d(e,"invert",function(){return L}),r.d(e,"conjugate",function(){return F}),r.d(e,"length",function(){return D}),r.d(e,"len",function(){return B}),r.d(e,"squaredLength",function(){return j}),r.d(e,"sqrLen",function(){return U}),r.d(e,"normalize",function(){return V}),r.d(e,"str",function(){return Y}),r.d(e,"exactEquals",function(){return G}),r.d(e,"equals",function(){return H});var n=r(0),i=r(5),o=r(10);function a(){let t=new n.ARRAY_TYPE(8);return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t}function u(t){let e=new n.ARRAY_TYPE(8);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e}function s(t,e,r,i,o,a,u,s){let c=new n.ARRAY_TYPE(8);return c[0]=t,c[1]=e,c[2]=r,c[3]=i,c[4]=o,c[5]=a,c[6]=u,c[7]=s,c}function c(t,e,r,i,o,a,u){let s=new n.ARRAY_TYPE(8);s[0]=t,s[1]=e,s[2]=r,s[3]=i;let c=.5*o,f=.5*a,l=.5*u;return s[4]=c*i+f*r-l*e,s[5]=f*i+l*t-c*r,s[6]=l*i+c*e-f*t,s[7]=-c*t-f*e-l*r,s}function f(t,e,r){let n=.5*r[0],i=.5*r[1],o=.5*r[2],a=e[0],u=e[1],s=e[2],c=e[3];return t[0]=a,t[1]=u,t[2]=s,t[3]=c,t[4]=n*c+i*s-o*u,t[5]=i*c+o*a-n*s,t[6]=o*c+n*u-i*a,t[7]=-n*a-i*u-o*s,t}function l(t,e){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=.5*e[0],t[5]=.5*e[1],t[6]=.5*e[2],t[7]=0,t}function h(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=0,t[5]=0,t[6]=0,t[7]=0,t}function d(t,e){let r=i.create();o.getRotation(r,e);let a=new n.ARRAY_TYPE(3);return o.getTranslation(a,e),f(t,r,a),t}function v(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t}function _(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t}function m(t,e,r,n,i,o,a,u,s){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t[6]=u,t[7]=s,t}const p=i.copy;function y(t,e){return t[0]=e[4],t[1]=e[5],t[2]=e[6],t[3]=e[7],t}const b=i.copy;function g(t,e){return t[4]=e[0],t[5]=e[1],t[6]=e[2],t[7]=e[3],t}function M(t,e){let r=e[4],n=e[5],i=e[6],o=e[7],a=-e[0],u=-e[1],s=-e[2],c=e[3];return t[0]=2*(r*c+o*a+n*s-i*u),t[1]=2*(n*c+o*u+i*a-r*s),t[2]=2*(i*c+o*s+r*u-n*a),t}function x(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=.5*r[0],s=.5*r[1],c=.5*r[2],f=e[4],l=e[5],h=e[6],d=e[7];return t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=a*u+i*c-o*s+f,t[5]=a*s+o*u-n*c+l,t[6]=a*c+n*s-i*u+h,t[7]=-n*u-i*s-o*c+d,t}function T(t,e,r){let n=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=s*u+l*n+c*a-f*o,d=c*u+l*o+f*n-s*a,v=f*u+l*a+s*o-c*n,_=l*u-s*n-c*o-f*a;return i.rotateX(t,e,r),n=t[0],o=t[1],a=t[2],u=t[3],t[4]=h*u+_*n+d*a-v*o,t[5]=d*u+_*o+v*n-h*a,t[6]=v*u+_*a+h*o-d*n,t[7]=_*u-h*n-d*o-v*a,t}function w(t,e,r){let n=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=s*u+l*n+c*a-f*o,d=c*u+l*o+f*n-s*a,v=f*u+l*a+s*o-c*n,_=l*u-s*n-c*o-f*a;return i.rotateY(t,e,r),n=t[0],o=t[1],a=t[2],u=t[3],t[4]=h*u+_*n+d*a-v*o,t[5]=d*u+_*o+v*n-h*a,t[6]=v*u+_*a+h*o-d*n,t[7]=_*u-h*n-d*o-v*a,t}function E(t,e,r){let n=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=s*u+l*n+c*a-f*o,d=c*u+l*o+f*n-s*a,v=f*u+l*a+s*o-c*n,_=l*u-s*n-c*o-f*a;return i.rotateZ(t,e,r),n=t[0],o=t[1],a=t[2],u=t[3],t[4]=h*u+_*n+d*a-v*o,t[5]=d*u+_*o+v*n-h*a,t[6]=v*u+_*a+h*o-d*n,t[7]=_*u-h*n-d*o-v*a,t}function O(t,e,r){let n=r[0],i=r[1],o=r[2],a=r[3],u=e[0],s=e[1],c=e[2],f=e[3];return t[0]=u*a+f*n+s*o-c*i,t[1]=s*a+f*i+c*n-u*o,t[2]=c*a+f*o+u*i-s*n,t[3]=f*a-u*n-s*i-c*o,u=e[4],s=e[5],c=e[6],f=e[7],t[4]=u*a+f*n+s*o-c*i,t[5]=s*a+f*i+c*n-u*o,t[6]=c*a+f*o+u*i-s*n,t[7]=f*a-u*n-s*i-c*o,t}function R(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1],c=r[2],f=r[3];return t[0]=n*f+a*u+i*c-o*s,t[1]=i*f+a*s+o*u-n*c,t[2]=o*f+a*c+n*s-i*u,t[3]=a*f-n*u-i*s-o*c,u=r[4],s=r[5],c=r[6],f=r[7],t[4]=n*f+a*u+i*c-o*s,t[5]=i*f+a*s+o*u-n*c,t[6]=o*f+a*c+n*s-i*u,t[7]=a*f-n*u-i*s-o*c,t}function P(t,e,r,i){if(Math.abs(i)<n.EPSILON)return v(t,e);let o=Math.sqrt(r[0]*r[0]+r[1]*r[1]+r[2]*r[2]);i*=.5;let a=Math.sin(i),u=a*r[0]/o,s=a*r[1]/o,c=a*r[2]/o,f=Math.cos(i),l=e[0],h=e[1],d=e[2],_=e[3];t[0]=l*f+_*u+h*c-d*s,t[1]=h*f+_*s+d*u-l*c,t[2]=d*f+_*c+l*s-h*u,t[3]=_*f-l*u-h*s-d*c;let m=e[4],p=e[5],y=e[6],b=e[7];return t[4]=m*f+b*u+p*c-y*s,t[5]=p*f+b*s+y*u-m*c,t[6]=y*f+b*c+m*s-p*u,t[7]=b*f-m*u-p*s-y*c,t}function S(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t[6]=e[6]+r[6],t[7]=e[7]+r[7],t}function A(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[4],s=r[5],c=r[6],f=r[7],l=e[4],h=e[5],d=e[6],v=e[7],_=r[0],m=r[1],p=r[2],y=r[3];return t[0]=n*y+a*_+i*p-o*m,t[1]=i*y+a*m+o*_-n*p,t[2]=o*y+a*p+n*m-i*_,t[3]=a*y-n*_-i*m-o*p,t[4]=n*f+a*u+i*c-o*s+l*y+v*_+h*p-d*m,t[5]=i*f+a*s+o*u-n*c+h*y+v*m+d*_-l*p,t[6]=o*f+a*c+n*s-i*u+d*y+v*p+l*m-h*_,t[7]=a*f-n*u-i*s-o*c+v*y-l*_-h*m-d*p,t}const N=A;function C(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t[6]=e[6]*r,t[7]=e[7]*r,t}const I=i.dot;function k(t,e,r,n){let i=1-n;return I(e,r)<0&&(n=-n),t[0]=e[0]*i+r[0]*n,t[1]=e[1]*i+r[1]*n,t[2]=e[2]*i+r[2]*n,t[3]=e[3]*i+r[3]*n,t[4]=e[4]*i+r[4]*n,t[5]=e[5]*i+r[5]*n,t[6]=e[6]*i+r[6]*n,t[7]=e[7]*i+r[7]*n,t}function L(t,e){let r=j(e);return t[0]=-e[0]/r,t[1]=-e[1]/r,t[2]=-e[2]/r,t[3]=e[3]/r,t[4]=-e[4]/r,t[5]=-e[5]/r,t[6]=-e[6]/r,t[7]=e[7]/r,t}function F(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=e[3],t[4]=-e[4],t[5]=-e[5],t[6]=-e[6],t[7]=e[7],t}const D=i.length,B=D,j=i.squaredLength,U=j;function V(t,e){let r=j(e);return r>0&&(r=Math.sqrt(r),t[0]=e[0]/r,t[1]=e[1]/r,t[2]=e[2]/r,t[3]=e[3]/r,t[4]=e[4]/r,t[5]=e[5]/r,t[6]=e[6]/r,t[7]=e[7]/r),t}function Y(t){return"quat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+")"}function G(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]&&t[6]===e[6]&&t[7]===e[7]}function H(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=t[6],f=t[7],l=e[0],h=e[1],d=e[2],v=e[3],_=e[4],m=e[5],p=e[6],y=e[7];return Math.abs(r-l)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(l))&&Math.abs(i-h)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(h))&&Math.abs(o-d)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(d))&&Math.abs(a-v)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(v))&&Math.abs(u-_)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(_))&&Math.abs(s-m)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(m))&&Math.abs(c-p)<=n.EPSILON*Math.max(1,Math.abs(c),Math.abs(p))&&Math.abs(f-y)<=n.EPSILON*Math.max(1,Math.abs(f),Math.abs(y))}},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"copy",function(){return a}),r.d(e,"identity",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"invert",function(){return f}),r.d(e,"determinant",function(){return l}),r.d(e,"multiply",function(){return h}),r.d(e,"rotate",function(){return d}),r.d(e,"scale",function(){return v}),r.d(e,"translate",function(){return _}),r.d(e,"fromRotation",function(){return m}),r.d(e,"fromScaling",function(){return p}),r.d(e,"fromTranslation",function(){return y}),r.d(e,"str",function(){return b}),r.d(e,"frob",function(){return g}),r.d(e,"add",function(){return M}),r.d(e,"subtract",function(){return x}),r.d(e,"multiplyScalar",function(){return T}),r.d(e,"multiplyScalarAndAdd",function(){return w}),r.d(e,"exactEquals",function(){return E}),r.d(e,"equals",function(){return O}),r.d(e,"mul",function(){return R}),r.d(e,"sub",function(){return P});var n=r(0);function i(){let t=new n.ARRAY_TYPE(6);return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t}function o(t){let e=new n.ARRAY_TYPE(6);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e}function a(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t}function u(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t}function s(t,e,r,i,o,a){let u=new n.ARRAY_TYPE(6);return u[0]=t,u[1]=e,u[2]=r,u[3]=i,u[4]=o,u[5]=a,u}function c(t,e,r,n,i,o,a){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t}function f(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=r*o-n*i;return s?(s=1/s,t[0]=o*s,t[1]=-n*s,t[2]=-i*s,t[3]=r*s,t[4]=(i*u-o*a)*s,t[5]=(n*a-r*u)*s,t):null}function l(t){return t[0]*t[3]-t[1]*t[2]}function h(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=r[0],f=r[1],l=r[2],h=r[3],d=r[4],v=r[5];return t[0]=n*c+o*f,t[1]=i*c+a*f,t[2]=n*l+o*h,t[3]=i*l+a*h,t[4]=n*d+o*v+u,t[5]=i*d+a*v+s,t}function d(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=Math.sin(r),f=Math.cos(r);return t[0]=n*f+o*c,t[1]=i*f+a*c,t[2]=n*-c+o*f,t[3]=i*-c+a*f,t[4]=u,t[5]=s,t}function v(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=r[0],f=r[1];return t[0]=n*c,t[1]=i*c,t[2]=o*f,t[3]=a*f,t[4]=u,t[5]=s,t}function _(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=r[0],f=r[1];return t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=n*c+o*f+u,t[5]=i*c+a*f+s,t}function m(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=-r,t[3]=n,t[4]=0,t[5]=0,t}function p(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=e[1],t[4]=0,t[5]=0,t}function y(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=e[0],t[5]=e[1],t}function b(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"}function g(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+1)}function M(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t}function x(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t[4]=e[4]-r[4],t[5]=e[5]-r[5],t}function T(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t}function w(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t[4]=e[4]+r[4]*n,t[5]=e[5]+r[5]*n,t}function E(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]}function O(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=e[0],f=e[1],l=e[2],h=e[3],d=e[4],v=e[5];return Math.abs(r-c)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(c))&&Math.abs(i-f)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(f))&&Math.abs(o-l)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(l))&&Math.abs(a-h)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(h))&&Math.abs(u-d)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(d))&&Math.abs(s-v)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(v))}const R=h,P=x},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"copy",function(){return a}),r.d(e,"identity",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"transpose",function(){return f}),r.d(e,"invert",function(){return l}),r.d(e,"adjoint",function(){return h}),r.d(e,"determinant",function(){return d}),r.d(e,"multiply",function(){return v}),r.d(e,"rotate",function(){return _}),r.d(e,"scale",function(){return m}),r.d(e,"fromRotation",function(){return p}),r.d(e,"fromScaling",function(){return y}),r.d(e,"str",function(){return b}),r.d(e,"frob",function(){return g}),r.d(e,"LDU",function(){return M}),r.d(e,"add",function(){return x}),r.d(e,"subtract",function(){return T}),r.d(e,"exactEquals",function(){return w}),r.d(e,"equals",function(){return E}),r.d(e,"multiplyScalar",function(){return O}),r.d(e,"multiplyScalarAndAdd",function(){return R}),r.d(e,"mul",function(){return P}),r.d(e,"sub",function(){return S});var n=r(0);function i(){let t=new n.ARRAY_TYPE(4);return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t}function o(t){let e=new n.ARRAY_TYPE(4);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function a(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t}function u(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t}function s(t,e,r,i){let o=new n.ARRAY_TYPE(4);return o[0]=t,o[1]=e,o[2]=r,o[3]=i,o}function c(t,e,r,n,i){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t}function f(t,e){if(t===e){let r=e[1];t[1]=e[2],t[2]=r}else t[0]=e[0],t[1]=e[2],t[2]=e[1],t[3]=e[3];return t}function l(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r*o-i*n;return a?(a=1/a,t[0]=o*a,t[1]=-n*a,t[2]=-i*a,t[3]=r*a,t):null}function h(t,e){let r=e[0];return t[0]=e[3],t[1]=-e[1],t[2]=-e[2],t[3]=r,t}function d(t){return t[0]*t[3]-t[2]*t[1]}function v(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1],c=r[2],f=r[3];return t[0]=n*u+o*s,t[1]=i*u+a*s,t[2]=n*c+o*f,t[3]=i*c+a*f,t}function _(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s+o*u,t[1]=i*s+a*u,t[2]=n*-u+o*s,t[3]=i*-u+a*s,t}function m(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1];return t[0]=n*u,t[1]=i*u,t[2]=o*s,t[3]=a*s,t}function p(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=-r,t[3]=n,t}function y(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=e[1],t}function b(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}function g(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2))}function M(t,e,r,n){return t[2]=n[2]/n[0],r[0]=n[0],r[1]=n[1],r[3]=n[3]-t[2]*r[1],[t,e,r]}function x(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t}function T(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t}function w(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]}function E(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=e[0],s=e[1],c=e[2],f=e[3];return Math.abs(r-u)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(u))&&Math.abs(i-s)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(s))&&Math.abs(o-c)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(c))&&Math.abs(a-f)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(f))}function O(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t}function R(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t}const P=v,S=T},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Ray=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(6);var o=i.mat3.create();e.Ray=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.origin=i.vec3.create(),this._dir=i.vec3.create(),this._dir[2]=-1,e&&(i.vec3.transformMat4(this.origin,this.origin,e),i.mat3.fromMat4(o,e),i.vec3.transformMat3(this._dir,this._dir,o)),this.dir=this._dir}return n(t,[{key:"intersectsAABB",value:function(t,e){var r=this,n=[t,e],o=(n[r.sign[0]][0]-r.origin[0])*r.inv_dir[0],a=(n[1-r.sign[0]][0]-r.origin[0])*r.inv_dir[0],u=(n[r.sign[1]][1]-r.origin[1])*r.inv_dir[1],s=(n[1-r.sign[1]][1]-r.origin[1])*r.inv_dir[1];if(o>s||u>a)return null;u>o&&(o=u),s<a&&(a=s);var c=(n[r.sign[2]][2]-r.origin[2])*r.inv_dir[2],f=(n[1-r.sign[2]][2]-r.origin[2])*r.inv_dir[2];if(o>f||c>a)return null;c>o&&(o=c),f<a&&(a=f);var l=-1;if(o>0&&a>0)l=Math.min(o,a);else if(o>0)l=o;else{if(!(a>0))return null;l=a}l-=.02;var h=i.vec3.clone(this._dir);return i.vec3.scale(h,h,l),i.vec3.add(h,h,this.origin),h}},{key:"dir",get:function(){return this._dir},set:function(t){this._dir=i.vec3.copy(this._dir,t),i.vec3.normalize(this._dir,this._dir),this.inv_dir=i.vec3.fromValues(1/this._dir[0],1/this._dir[1],1/this._dir[2]),this.sign=[this.inv_dir[0]<0?1:0,this.inv_dir[1]<0?1:0,this.inv_dir[2]<0?1:0]}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=r(2);Object.defineProperty(e,"Node",{enumerable:!0,get:function(){return n.Node}});var i=r(11);Object.defineProperty(e,"Renderer",{enumerable:!0,get:function(){return i.Renderer}}),Object.defineProperty(e,"createWebGLContext",{enumerable:!0,get:function(){return i.createWebGLContext}});var o=r(8);Object.defineProperty(e,"UrlTexture",{enumerable:!0,get:function(){return o.UrlTexture}});var a=r(9);Object.defineProperty(e,"PrimitiveStream",{enumerable:!0,get:function(){return a.PrimitiveStream}});var u=r(14);Object.defineProperty(e,"BoxBuilder",{enumerable:!0,get:function(){return u.BoxBuilder}});var s=r(13);Object.defineProperty(e,"PbrMaterial",{enumerable:!0,get:function(){return s.PbrMaterial}});var c=r(6);Object.defineProperty(e,"mat4",{enumerable:!0,get:function(){return c.mat4}}),Object.defineProperty(e,"mat3",{enumerable:!0,get:function(){return c.mat3}}),Object.defineProperty(e,"vec3",{enumerable:!0,get:function(){return c.vec3}}),Object.defineProperty(e,"vec4",{enumerable:!0,get:function(){return c.vec4}}),Object.defineProperty(e,"quat",{enumerable:!0,get:function(){return c.quat}});var f=r(28);Object.defineProperty(e,"BoundsRenderer",{enumerable:!0,get:function(){return f.BoundsRenderer}});var l=r(27);Object.defineProperty(e,"ButtonNode",{enumerable:!0,get:function(){return l.ButtonNode}});var h=r(26);Object.defineProperty(e,"DropShadowNode",{enumerable:!0,get:function(){return h.DropShadowNode}});var d=r(25);Object.defineProperty(e,"CubeSeaNode",{enumerable:!0,get:function(){return d.CubeSeaNode}});var v=r(24);Object.defineProperty(e,"Gltf2Node",{enumerable:!0,get:function(){return v.Gltf2Node}});var _=r(22);Object.defineProperty(e,"SkyboxNode",{enumerable:!0,get:function(){return _.SkyboxNode}});var m=r(21);Object.defineProperty(e,"VideoNode",{enumerable:!0,get:function(){return m.VideoNode}});var p=r(20);Object.defineProperty(e,"WebXRView",{enumerable:!0,get:function(){return p.WebXRView}}),Object.defineProperty(e,"Scene",{enumerable:!0,get:function(){return p.Scene}});var y=r(16);Object.defineProperty(e,"FallbackHelper",{enumerable:!0,get:function(){return y.FallbackHelper}});var b=r(15);Object.defineProperty(e,"QueryArgs",{enumerable:!0,get:function(){return b.QueryArgs}})}])}); \ No newline at end of file +!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var r=e();for(var n in r)("object"==typeof exports?exports:t)[n]=r[n]}}(window,function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)r.d(n,i,function(e){return t[e]}.bind(null,i));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=15)}([function(t,e,r){"use strict";r.r(e),r.d(e,"EPSILON",function(){return n}),r.d(e,"ARRAY_TYPE",function(){return i}),r.d(e,"RANDOM",function(){return o}),r.d(e,"setMatrixArrayType",function(){return a}),r.d(e,"toRadian",function(){return s}),r.d(e,"equals",function(){return c});const n=1e-6;let i="undefined"!=typeof Float32Array?Float32Array:Array;const o=Math.random;function a(t){i=t}const u=Math.PI/180;function s(t){return t*u}function c(t,e){return Math.abs(t-e)<=n*Math.max(1,Math.abs(t),Math.abs(e))}},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"fromValues",function(){return a}),r.d(e,"copy",function(){return u}),r.d(e,"set",function(){return s}),r.d(e,"add",function(){return c}),r.d(e,"subtract",function(){return f}),r.d(e,"multiply",function(){return l}),r.d(e,"divide",function(){return h}),r.d(e,"ceil",function(){return d}),r.d(e,"floor",function(){return v}),r.d(e,"min",function(){return _}),r.d(e,"max",function(){return m}),r.d(e,"round",function(){return p}),r.d(e,"scale",function(){return y}),r.d(e,"scaleAndAdd",function(){return b}),r.d(e,"distance",function(){return g}),r.d(e,"squaredDistance",function(){return M}),r.d(e,"length",function(){return x}),r.d(e,"squaredLength",function(){return T}),r.d(e,"negate",function(){return E}),r.d(e,"inverse",function(){return w}),r.d(e,"normalize",function(){return O}),r.d(e,"dot",function(){return R}),r.d(e,"lerp",function(){return P}),r.d(e,"random",function(){return S}),r.d(e,"transformMat4",function(){return A}),r.d(e,"transformQuat",function(){return N}),r.d(e,"str",function(){return C}),r.d(e,"exactEquals",function(){return I}),r.d(e,"equals",function(){return L}),r.d(e,"sub",function(){return k}),r.d(e,"mul",function(){return F}),r.d(e,"div",function(){return D}),r.d(e,"dist",function(){return j}),r.d(e,"sqrDist",function(){return B}),r.d(e,"len",function(){return U}),r.d(e,"sqrLen",function(){return V}),r.d(e,"forEach",function(){return Y});var n=r(0);function i(){let t=new n.ARRAY_TYPE(4);return n.ARRAY_TYPE!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[3]=0),t}function o(t){let e=new n.ARRAY_TYPE(4);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function a(t,e,r,i){let o=new n.ARRAY_TYPE(4);return o[0]=t,o[1]=e,o[2]=r,o[3]=i,o}function u(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t}function s(t,e,r,n,i){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t}function c(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t}function f(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t}function l(t,e,r){return t[0]=e[0]*r[0],t[1]=e[1]*r[1],t[2]=e[2]*r[2],t[3]=e[3]*r[3],t}function h(t,e,r){return t[0]=e[0]/r[0],t[1]=e[1]/r[1],t[2]=e[2]/r[2],t[3]=e[3]/r[3],t}function d(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2]),t[3]=Math.ceil(e[3]),t}function v(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2]),t[3]=Math.floor(e[3]),t}function _(t,e,r){return t[0]=Math.min(e[0],r[0]),t[1]=Math.min(e[1],r[1]),t[2]=Math.min(e[2],r[2]),t[3]=Math.min(e[3],r[3]),t}function m(t,e,r){return t[0]=Math.max(e[0],r[0]),t[1]=Math.max(e[1],r[1]),t[2]=Math.max(e[2],r[2]),t[3]=Math.max(e[3],r[3]),t}function p(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t[2]=Math.round(e[2]),t[3]=Math.round(e[3]),t}function y(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t}function b(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t}function g(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2],o=e[3]-t[3];return Math.sqrt(r*r+n*n+i*i+o*o)}function M(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2],o=e[3]-t[3];return r*r+n*n+i*i+o*o}function x(t){let e=t[0],r=t[1],n=t[2],i=t[3];return Math.sqrt(e*e+r*r+n*n+i*i)}function T(t){let e=t[0],r=t[1],n=t[2],i=t[3];return e*e+r*r+n*n+i*i}function E(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=-e[3],t}function w(t,e){return t[0]=1/e[0],t[1]=1/e[1],t[2]=1/e[2],t[3]=1/e[3],t}function O(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r*r+n*n+i*i+o*o;return a>0&&(a=1/Math.sqrt(a),t[0]=r*a,t[1]=n*a,t[2]=i*a,t[3]=o*a),t}function R(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]+t[3]*e[3]}function P(t,e,r,n){let i=e[0],o=e[1],a=e[2],u=e[3];return t[0]=i+n*(r[0]-i),t[1]=o+n*(r[1]-o),t[2]=a+n*(r[2]-a),t[3]=u+n*(r[3]-u),t}function S(t,e){var r,i,o,a,u,s;e=e||1;do{u=(r=2*n.RANDOM()-1)*r+(i=2*n.RANDOM()-1)*i}while(u>=1);do{s=(o=2*n.RANDOM()-1)*o+(a=2*n.RANDOM()-1)*a}while(s>=1);var c=Math.sqrt((1-u)/s);return t[0]=e*r,t[1]=e*i,t[2]=e*o*c,t[3]=e*a*c,t}function A(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3];return t[0]=r[0]*n+r[4]*i+r[8]*o+r[12]*a,t[1]=r[1]*n+r[5]*i+r[9]*o+r[13]*a,t[2]=r[2]*n+r[6]*i+r[10]*o+r[14]*a,t[3]=r[3]*n+r[7]*i+r[11]*o+r[15]*a,t}function N(t,e,r){let n=e[0],i=e[1],o=e[2],a=r[0],u=r[1],s=r[2],c=r[3],f=c*n+u*o-s*i,l=c*i+s*n-a*o,h=c*o+a*i-u*n,d=-a*n-u*i-s*o;return t[0]=f*c+d*-a+l*-s-h*-u,t[1]=l*c+d*-u+h*-a-f*-s,t[2]=h*c+d*-s+f*-u-l*-a,t[3]=e[3],t}function C(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}function I(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]}function L(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=e[0],s=e[1],c=e[2],f=e[3];return Math.abs(r-u)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(u))&&Math.abs(i-s)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(s))&&Math.abs(o-c)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(c))&&Math.abs(a-f)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(f))}const k=f,F=l,D=h,j=g,B=M,U=x,V=T,Y=function(){let t=i();return function(e,r,n,i,o,a){let u,s;for(r||(r=4),n||(n=0),s=i?Math.min(i*r+n,e.length):e.length,u=n;u<s;u+=r)t[0]=e[u],t[1]=e[u+1],t[2]=e[u+2],t[3]=e[u+3],o(t,t,a),e[u]=t[0],e[u+1]=t[1],e[u+2]=t[2],e[u+3]=t[3];return e}}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Node=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(16),o=r(6);var a=new Float32Array([0,0,0]),u=new Float32Array([0,0,0,1]),s=new Float32Array([1,1,1]),c=o.mat4.create();e.Node=function(){function t(){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.name=null,this.children=[],this.parent=null,this.visible=!0,this.selectable=!1,this._matrix=null,this._dirtyTRS=!1,this._translation=null,this._rotation=null,this._scale=null,this._dirtyWorldMatrix=!1,this._worldMatrix=null,this._activeFrameId=-1,this._hoverFrameId=-1,this._renderPrimitives=null,this._renderer=null,this._selectHandler=null}return n(t,[{key:"_setRenderer",value:function(t){if(this._renderer!=t&&(this._renderer&&this.clearRenderPrimitives(),this._renderer=t,t)){this.onRendererChanged(t);var e=!0,r=!1,n=void 0;try{for(var i,o=this.children[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){i.value._setRenderer(t)}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}}}},{key:"onRendererChanged",value:function(t){}},{key:"clone",value:function(){var e=this,r=new t;return r.name=this.name,r.visible=this.visible,r._renderer=this._renderer,r._dirtyTRS=this._dirtyTRS,this._translation&&(r._translation=o.vec3.create(),o.vec3.copy(r._translation,this._translation)),this._rotation&&(r._rotation=o.quat.create(),o.quat.copy(r._rotation,this._rotation)),this._scale&&(r._scale=o.vec3.create(),o.vec3.copy(r._scale,this._scale)),!r._dirtyTRS&&this._matrix&&(r._matrix=o.mat4.create(),o.mat4.copy(r._matrix,this._matrix)),r._dirtyWorldMatrix=this._dirtyWorldMatrix,!r._dirtyWorldMatrix&&this._worldMatrix&&(r._worldMatrix=o.mat4.create(),o.mat4.copy(r._worldMatrix,this._worldMatrix)),this.waitForComplete().then(function(){if(e._renderPrimitives){var t=!0,n=!1,i=void 0;try{for(var o,a=e._renderPrimitives[Symbol.iterator]();!(t=(o=a.next()).done);t=!0){var u=o.value;r.addRenderPrimitive(u)}}catch(t){n=!0,i=t}finally{try{!t&&a.return&&a.return()}finally{if(n)throw i}}}var s=!0,c=!1,f=void 0;try{for(var l,h=e.children[Symbol.iterator]();!(s=(l=h.next()).done);s=!0){var d=l.value;r.addNode(d.clone())}}catch(t){c=!0,f=t}finally{try{!s&&h.return&&h.return()}finally{if(c)throw f}}}),r}},{key:"markActive",value:function(t){if(this.visible&&this._renderPrimitives){this._activeFrameId=t;var e=!0,r=!1,n=void 0;try{for(var i,o=this._renderPrimitives[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){i.value.markActive(t)}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}}var a=!0,u=!1,s=void 0;try{for(var c,f=this.children[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){var l=c.value;l.visible&&l.markActive(t)}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}}},{key:"addNode",value:function(t){t&&t.parent!=this&&(t.parent&&t.parent.removeNode(t),t.parent=this,this.children.push(t),this._renderer&&t._setRenderer(this._renderer))}},{key:"removeNode",value:function(t){var e=this.children.indexOf(t);e>-1&&(this.children.splice(e,1),t.parent=null)}},{key:"clearNodes",value:function(){var t=!0,e=!1,r=void 0;try{for(var n,i=this.children[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){n.value.parent=null}}catch(t){e=!0,r=t}finally{try{!t&&i.return&&i.return()}finally{if(e)throw r}}this.children=[]}},{key:"setMatrixDirty",value:function(){if(!this._dirtyWorldMatrix){this._dirtyWorldMatrix=!0;var t=!0,e=!1,r=void 0;try{for(var n,i=this.children[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){n.value.setMatrixDirty()}}catch(t){e=!0,r=t}finally{try{!t&&i.return&&i.return()}finally{if(e)throw r}}}}},{key:"_updateLocalMatrix",value:function(){return this._matrix||(this._matrix=o.mat4.create()),this._dirtyTRS&&(this._dirtyTRS=!1,o.mat4.fromRotationTranslationScale(this._matrix,this._rotation||u,this._translation||a,this._scale||s)),this._matrix}},{key:"waitForComplete",value:function(){var t=this,e=[],r=!0,n=!1,i=void 0;try{for(var o,a=this.children[Symbol.iterator]();!(r=(o=a.next()).done);r=!0){var u=o.value;e.push(u.waitForComplete())}}catch(t){n=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(n)throw i}}if(this._renderPrimitives){var s=!0,c=!1,f=void 0;try{for(var l,h=this._renderPrimitives[Symbol.iterator]();!(s=(l=h.next()).done);s=!0){var d=l.value;e.push(d.waitForComplete())}}catch(t){c=!0,f=t}finally{try{!s&&h.return&&h.return()}finally{if(c)throw f}}}return Promise.all(e).then(function(){return t})}},{key:"addRenderPrimitive",value:function(t){this._renderPrimitives?this._renderPrimitives.push(t):this._renderPrimitives=[t],t._instances.push(this)}},{key:"removeRenderPrimitive",value:function(t){if(this._renderPrimitives){var e=this._renderPrimitives._instances.indexOf(t);e>-1&&(this._renderPrimitives._instances.splice(e,1),(e=t._instances.indexOf(this))>-1&&t._instances.splice(e,1),this._renderPrimitives.length||(this._renderPrimitives=null))}}},{key:"clearRenderPrimitives",value:function(){if(this._renderPrimitives){var t=!0,e=!1,r=void 0;try{for(var n,i=this._renderPrimitives[Symbol.iterator]();!(t=(n=i.next()).done);t=!0){var o=n.value,a=o._instances.indexOf(this);a>-1&&o._instances.splice(a,1)}}catch(t){e=!0,r=t}finally{try{!t&&i.return&&i.return()}finally{if(e)throw r}}this._renderPrimitives=null}}},{key:"_hitTestSelectableNode",value:function(t){if(this._renderPrimitives){var e=null,r=!0,n=!1,a=void 0;try{for(var u,s=this._renderPrimitives[Symbol.iterator]();!(r=(u=s.next()).done);r=!0){var f=u.value;if(f._min){e||(o.mat4.invert(c,this.worldMatrix),o.mat4.multiply(c,c,t.transformMatrix),e=new i.Ray(c));var l=e.intersectsAABB(f._min,f._max);if(l)return o.vec3.transformMat4(l,l,this.worldMatrix),l}}}catch(t){n=!0,a=t}finally{try{!r&&s.return&&s.return()}finally{if(n)throw a}}}var h=!0,d=!1,v=void 0;try{for(var _,m=this.children[Symbol.iterator]();!(h=(_=m.next()).done);h=!0){var p=_.value._hitTestSelectableNode(t);if(p)return p}}catch(t){d=!0,v=t}finally{try{!h&&m.return&&m.return()}finally{if(d)throw v}}return null}},{key:"hitTest",value:function(t){if(this.selectable&&this.visible){var e=this._hitTestSelectableNode(t);if(e){var r=o.vec3.fromValues(t.origin.x,t.origin.y,t.origin.z);return{node:this,intersection:e,distance:o.vec3.distance(r,e)}}return null}var n=null,i=!0,a=!1,u=void 0;try{for(var s,c=this.children[Symbol.iterator]();!(i=(s=c.next()).done);i=!0){var f=s.value.hitTest(t);f&&(!n||n.distance>f.distance)&&(n=f)}}catch(t){a=!0,u=t}finally{try{!i&&c.return&&c.return()}finally{if(a)throw u}}return n}},{key:"onSelect",value:function(t){this._selectHandler=t}},{key:"handleSelect",value:function(){this._selectHandler&&this._selectHandler()}},{key:"onHoverStart",value:function(){}},{key:"onHoverEnd",value:function(){}},{key:"_update",value:function(t,e){this.onUpdate(t,e);var r=!0,n=!1,i=void 0;try{for(var o,a=this.children[Symbol.iterator]();!(r=(o=a.next()).done);r=!0){o.value._update(t,e)}}catch(t){n=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(n)throw i}}}},{key:"onUpdate",value:function(t,e){}},{key:"matrix",set:function(t){t?(this._matrix||(this._matrix=o.mat4.create()),o.mat4.copy(this._matrix,t)):this._matrix=null,this.setMatrixDirty(),this._dirtyTRS=!1,this._translation=null,this._rotation=null,this._scale=null},get:function(){return this.setMatrixDirty(),this._updateLocalMatrix()}},{key:"worldMatrix",get:function(){return this._worldMatrix||(this._dirtyWorldMatrix=!0,this._worldMatrix=o.mat4.create()),(this._dirtyWorldMatrix||this._dirtyTRS)&&(this.parent?o.mat4.mul(this._worldMatrix,this.parent.worldMatrix,this._updateLocalMatrix()):o.mat4.copy(this._worldMatrix,this._updateLocalMatrix()),this._dirtyWorldMatrix=!1),this._worldMatrix}},{key:"translation",set:function(t){null!=t&&(this._dirtyTRS=!0,this.setMatrixDirty()),this._translation=t},get:function(){return this._dirtyTRS=!0,this.setMatrixDirty(),this._translation||(this._translation=o.vec3.clone(a)),this._translation}},{key:"rotation",set:function(t){null!=t&&(this._dirtyTRS=!0,this.setMatrixDirty()),this._rotation=t},get:function(){return this._dirtyTRS=!0,this.setMatrixDirty(),this._rotation||(this._rotation=o.quat.clone(u)),this._rotation}},{key:"scale",set:function(t){null!=t&&(this._dirtyTRS=!0,this.setMatrixDirty()),this._scale=t},get:function(){return this._dirtyTRS=!0,this.setMatrixDirty(),this._scale||(this._scale=o.vec3.clone(s)),this._scale}},{key:"renderPrimitives",get:function(){return this._renderPrimitives}},{key:"selectHandler",get:function(){return this._selectHandler}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}e.stateToBlendFunc=c;var o=WebGLRenderingContext,a=e.CAP={CULL_FACE:1,BLEND:2,DEPTH_TEST:4,STENCIL_TEST:8,COLOR_MASK:16,DEPTH_MASK:32,STENCIL_MASK:64},u=e.MAT_STATE={CAPS_RANGE:255,BLEND_SRC_SHIFT:8,BLEND_SRC_RANGE:3840,BLEND_DST_SHIFT:12,BLEND_DST_RANGE:61440,BLEND_FUNC_RANGE:65280,DEPTH_FUNC_SHIFT:16,DEPTH_FUNC_RANGE:983040},s=e.RENDER_ORDER={OPAQUE:0,SKY:1,TRANSPARENT:2,ADDITIVE:3,DEFAULT:4};function c(t,e,r){var n=(t&e)>>r;switch(n){case 0:case 1:return n;default:return n-2+o.SRC_COLOR}}var f=e.MaterialState=function(){function t(){i(this,t),this._state=a.CULL_FACE|a.DEPTH_TEST|a.COLOR_MASK|a.DEPTH_MASK,this.blendFuncSrc=o.SRC_ALPHA,this.blendFuncDst=o.ONE_MINUS_SRC_ALPHA,this.depthFunc=o.LESS}return n(t,[{key:"cullFace",get:function(){return!!(this._state&a.CULL_FACE)},set:function(t){t?this._state|=a.CULL_FACE:this._state&=~a.CULL_FACE}},{key:"blend",get:function(){return!!(this._state&a.BLEND)},set:function(t){t?this._state|=a.BLEND:this._state&=~a.BLEND}},{key:"depthTest",get:function(){return!!(this._state&a.DEPTH_TEST)},set:function(t){t?this._state|=a.DEPTH_TEST:this._state&=~a.DEPTH_TEST}},{key:"stencilTest",get:function(){return!!(this._state&a.STENCIL_TEST)},set:function(t){t?this._state|=a.STENCIL_TEST:this._state&=~a.STENCIL_TEST}},{key:"colorMask",get:function(){return!!(this._state&a.COLOR_MASK)},set:function(t){t?this._state|=a.COLOR_MASK:this._state&=~a.COLOR_MASK}},{key:"depthMask",get:function(){return!!(this._state&a.DEPTH_MASK)},set:function(t){t?this._state|=a.DEPTH_MASK:this._state&=~a.DEPTH_MASK}},{key:"depthFunc",get:function(){return((this._state&u.DEPTH_FUNC_RANGE)>>u.DEPTH_FUNC_SHIFT)+o.NEVER},set:function(t){t-=o.NEVER,this._state&=~u.DEPTH_FUNC_RANGE,this._state|=t<<u.DEPTH_FUNC_SHIFT}},{key:"stencilMask",get:function(){return!!(this._state&a.STENCIL_MASK)},set:function(t){t?this._state|=a.STENCIL_MASK:this._state&=~a.STENCIL_MASK}},{key:"blendFuncSrc",get:function(){return c(this._state,u.BLEND_SRC_RANGE,u.BLEND_SRC_SHIFT)},set:function(t){switch(t){case 0:case 1:break;default:t=t-o.SRC_COLOR+2}this._state&=~u.BLEND_SRC_RANGE,this._state|=t<<u.BLEND_SRC_SHIFT}},{key:"blendFuncDst",get:function(){return c(this._state,u.BLEND_DST_RANGE,u.BLEND_DST_SHIFT)},set:function(t){switch(t){case 0:case 1:break;default:t=t-o.SRC_COLOR+2}this._state&=~u.BLEND_DST_RANGE,this._state|=t<<u.BLEND_DST_SHIFT}}]),t}(),l=function(){function t(e){i(this,t),this._uniformName=e,this._texture=null}return n(t,[{key:"texture",get:function(){return this._texture},set:function(t){this._texture=t}}]),t}(),h=function(){function t(e,r,n){i(this,t),this._uniformName=e,this._value=r,this._length=n,this._length||(r instanceof Array?this._length=r.length:this._length=1)}return n(t,[{key:"value",get:function(){return this._value},set:function(t){this._value=t}}]),t}();e.Material=function(){function t(){i(this,t),this.state=new f,this.renderOrder=s.DEFAULT,this._samplers=[],this._uniforms=[]}return n(t,[{key:"defineSampler",value:function(t){var e=new l(t);return this._samplers.push(e),e}},{key:"defineUniform",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,n=new h(t,e,r);return this._uniforms.push(n),n}},{key:"getProgramDefines",value:function(t){return{}}},{key:"materialName",get:function(){return null}},{key:"vertexSource",get:function(){return null}},{key:"fragmentSource",get:function(){return null}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return u}),r.d(e,"identity",function(){return s}),r.d(e,"setAxisAngle",function(){return c}),r.d(e,"getAxisAngle",function(){return f}),r.d(e,"multiply",function(){return l}),r.d(e,"rotateX",function(){return h}),r.d(e,"rotateY",function(){return d}),r.d(e,"rotateZ",function(){return v}),r.d(e,"calculateW",function(){return _}),r.d(e,"slerp",function(){return m}),r.d(e,"random",function(){return p}),r.d(e,"invert",function(){return y}),r.d(e,"conjugate",function(){return b}),r.d(e,"fromMat3",function(){return g}),r.d(e,"fromEuler",function(){return M}),r.d(e,"str",function(){return x}),r.d(e,"clone",function(){return T}),r.d(e,"fromValues",function(){return E}),r.d(e,"copy",function(){return w}),r.d(e,"set",function(){return O}),r.d(e,"add",function(){return R}),r.d(e,"mul",function(){return P}),r.d(e,"scale",function(){return S}),r.d(e,"dot",function(){return A}),r.d(e,"lerp",function(){return N}),r.d(e,"length",function(){return C}),r.d(e,"len",function(){return I}),r.d(e,"squaredLength",function(){return L}),r.d(e,"sqrLen",function(){return k}),r.d(e,"normalize",function(){return F}),r.d(e,"exactEquals",function(){return D}),r.d(e,"equals",function(){return j}),r.d(e,"rotationTo",function(){return B}),r.d(e,"sqlerp",function(){return U}),r.d(e,"setAxes",function(){return V});var n=r(0),i=r(12),o=r(5),a=r(1);function u(){let t=new n.ARRAY_TYPE(4);return n.ARRAY_TYPE!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t[3]=1,t}function s(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t}function c(t,e,r){r*=.5;let n=Math.sin(r);return t[0]=n*e[0],t[1]=n*e[1],t[2]=n*e[2],t[3]=Math.cos(r),t}function f(t,e){let r=2*Math.acos(e[3]),i=Math.sin(r/2);return i>n.EPSILON?(t[0]=e[0]/i,t[1]=e[1]/i,t[2]=e[2]/i):(t[0]=1,t[1]=0,t[2]=0),r}function l(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1],c=r[2],f=r[3];return t[0]=n*f+a*u+i*c-o*s,t[1]=i*f+a*s+o*u-n*c,t[2]=o*f+a*c+n*s-i*u,t[3]=a*f-n*u-i*s-o*c,t}function h(t,e,r){r*=.5;let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s+a*u,t[1]=i*s+o*u,t[2]=o*s-i*u,t[3]=a*s-n*u,t}function d(t,e,r){r*=.5;let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s-o*u,t[1]=i*s+a*u,t[2]=o*s+n*u,t[3]=a*s-i*u,t}function v(t,e,r){r*=.5;let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s+i*u,t[1]=i*s-n*u,t[2]=o*s+a*u,t[3]=a*s-o*u,t}function _(t,e){let r=e[0],n=e[1],i=e[2];return t[0]=r,t[1]=n,t[2]=i,t[3]=Math.sqrt(Math.abs(1-r*r-n*n-i*i)),t}function m(t,e,r,i){let o,a,u,s,c,f=e[0],l=e[1],h=e[2],d=e[3],v=r[0],_=r[1],m=r[2],p=r[3];return(a=f*v+l*_+h*m+d*p)<0&&(a=-a,v=-v,_=-_,m=-m,p=-p),1-a>n.EPSILON?(o=Math.acos(a),u=Math.sin(o),s=Math.sin((1-i)*o)/u,c=Math.sin(i*o)/u):(s=1-i,c=i),t[0]=s*f+c*v,t[1]=s*l+c*_,t[2]=s*h+c*m,t[3]=s*d+c*p,t}function p(t){let e=n.RANDOM(),r=n.RANDOM(),i=n.RANDOM(),o=Math.sqrt(1-e),a=Math.sqrt(e);return t[0]=o*Math.sin(2*Math.PI*r),t[1]=o*Math.cos(2*Math.PI*r),t[2]=a*Math.sin(2*Math.PI*i),t[3]=a*Math.cos(2*Math.PI*i),t}function y(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r*r+n*n+i*i+o*o,u=a?1/a:0;return t[0]=-r*u,t[1]=-n*u,t[2]=-i*u,t[3]=o*u,t}function b(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=e[3],t}function g(t,e){let r,n=e[0]+e[4]+e[8];if(n>0)r=Math.sqrt(n+1),t[3]=.5*r,r=.5/r,t[0]=(e[5]-e[7])*r,t[1]=(e[6]-e[2])*r,t[2]=(e[1]-e[3])*r;else{let n=0;e[4]>e[0]&&(n=1),e[8]>e[3*n+n]&&(n=2);let i=(n+1)%3,o=(n+2)%3;r=Math.sqrt(e[3*n+n]-e[3*i+i]-e[3*o+o]+1),t[n]=.5*r,r=.5/r,t[3]=(e[3*i+o]-e[3*o+i])*r,t[i]=(e[3*i+n]+e[3*n+i])*r,t[o]=(e[3*o+n]+e[3*n+o])*r}return t}function M(t,e,r,n){let i=.5*Math.PI/180;e*=i,r*=i,n*=i;let o=Math.sin(e),a=Math.cos(e),u=Math.sin(r),s=Math.cos(r),c=Math.sin(n),f=Math.cos(n);return t[0]=o*s*f-a*u*c,t[1]=a*u*f+o*s*c,t[2]=a*s*c-o*u*f,t[3]=a*s*f+o*u*c,t}function x(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}const T=a.clone,E=a.fromValues,w=a.copy,O=a.set,R=a.add,P=l,S=a.scale,A=a.dot,N=a.lerp,C=a.length,I=C,L=a.squaredLength,k=L,F=a.normalize,D=a.exactEquals,j=a.equals,B=function(){let t=o.create(),e=o.fromValues(1,0,0),r=o.fromValues(0,1,0);return function(n,i,a){let u=o.dot(i,a);return u<-.999999?(o.cross(t,e,i),o.len(t)<1e-6&&o.cross(t,r,i),o.normalize(t,t),c(n,t,Math.PI),n):u>.999999?(n[0]=0,n[1]=0,n[2]=0,n[3]=1,n):(o.cross(t,i,a),n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=1+u,F(n,n))}}(),U=function(){let t=u(),e=u();return function(r,n,i,o,a,u){return m(t,n,a,u),m(e,i,o,u),m(r,t,e,2*u*(1-u)),r}}(),V=function(){let t=i.create();return function(e,r,n,i){return t[0]=n[0],t[3]=n[1],t[6]=n[2],t[1]=i[0],t[4]=i[1],t[7]=i[2],t[2]=-r[0],t[5]=-r[1],t[8]=-r[2],F(e,g(e,t))}}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"length",function(){return a}),r.d(e,"fromValues",function(){return u}),r.d(e,"copy",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"add",function(){return f}),r.d(e,"subtract",function(){return l}),r.d(e,"multiply",function(){return h}),r.d(e,"divide",function(){return d}),r.d(e,"ceil",function(){return v}),r.d(e,"floor",function(){return _}),r.d(e,"min",function(){return m}),r.d(e,"max",function(){return p}),r.d(e,"round",function(){return y}),r.d(e,"scale",function(){return b}),r.d(e,"scaleAndAdd",function(){return g}),r.d(e,"distance",function(){return M}),r.d(e,"squaredDistance",function(){return x}),r.d(e,"squaredLength",function(){return T}),r.d(e,"negate",function(){return E}),r.d(e,"inverse",function(){return w}),r.d(e,"normalize",function(){return O}),r.d(e,"dot",function(){return R}),r.d(e,"cross",function(){return P}),r.d(e,"lerp",function(){return S}),r.d(e,"hermite",function(){return A}),r.d(e,"bezier",function(){return N}),r.d(e,"random",function(){return C}),r.d(e,"transformMat4",function(){return I}),r.d(e,"transformMat3",function(){return L}),r.d(e,"transformQuat",function(){return k}),r.d(e,"rotateX",function(){return F}),r.d(e,"rotateY",function(){return D}),r.d(e,"rotateZ",function(){return j}),r.d(e,"angle",function(){return B}),r.d(e,"str",function(){return U}),r.d(e,"exactEquals",function(){return V}),r.d(e,"equals",function(){return Y}),r.d(e,"sub",function(){return G}),r.d(e,"mul",function(){return q}),r.d(e,"div",function(){return H}),r.d(e,"dist",function(){return X}),r.d(e,"sqrDist",function(){return W}),r.d(e,"len",function(){return K}),r.d(e,"sqrLen",function(){return z}),r.d(e,"forEach",function(){return Q});var n=r(0);function i(){let t=new n.ARRAY_TYPE(3);return n.ARRAY_TYPE!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function o(t){var e=new n.ARRAY_TYPE(3);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e}function a(t){let e=t[0],r=t[1],n=t[2];return Math.sqrt(e*e+r*r+n*n)}function u(t,e,r){let i=new n.ARRAY_TYPE(3);return i[0]=t,i[1]=e,i[2]=r,i}function s(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t}function c(t,e,r,n){return t[0]=e,t[1]=r,t[2]=n,t}function f(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t}function l(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t}function h(t,e,r){return t[0]=e[0]*r[0],t[1]=e[1]*r[1],t[2]=e[2]*r[2],t}function d(t,e,r){return t[0]=e[0]/r[0],t[1]=e[1]/r[1],t[2]=e[2]/r[2],t}function v(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2]),t}function _(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2]),t}function m(t,e,r){return t[0]=Math.min(e[0],r[0]),t[1]=Math.min(e[1],r[1]),t[2]=Math.min(e[2],r[2]),t}function p(t,e,r){return t[0]=Math.max(e[0],r[0]),t[1]=Math.max(e[1],r[1]),t[2]=Math.max(e[2],r[2]),t}function y(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t[2]=Math.round(e[2]),t}function b(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t}function g(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t}function M(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2];return Math.sqrt(r*r+n*n+i*i)}function x(t,e){let r=e[0]-t[0],n=e[1]-t[1],i=e[2]-t[2];return r*r+n*n+i*i}function T(t){let e=t[0],r=t[1],n=t[2];return e*e+r*r+n*n}function E(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t}function w(t,e){return t[0]=1/e[0],t[1]=1/e[1],t[2]=1/e[2],t}function O(t,e){let r=e[0],n=e[1],i=e[2],o=r*r+n*n+i*i;return o>0&&(o=1/Math.sqrt(o),t[0]=e[0]*o,t[1]=e[1]*o,t[2]=e[2]*o),t}function R(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function P(t,e,r){let n=e[0],i=e[1],o=e[2],a=r[0],u=r[1],s=r[2];return t[0]=i*s-o*u,t[1]=o*a-n*s,t[2]=n*u-i*a,t}function S(t,e,r,n){let i=e[0],o=e[1],a=e[2];return t[0]=i+n*(r[0]-i),t[1]=o+n*(r[1]-o),t[2]=a+n*(r[2]-a),t}function A(t,e,r,n,i,o){let a=o*o,u=a*(2*o-3)+1,s=a*(o-2)+o,c=a*(o-1),f=a*(3-2*o);return t[0]=e[0]*u+r[0]*s+n[0]*c+i[0]*f,t[1]=e[1]*u+r[1]*s+n[1]*c+i[1]*f,t[2]=e[2]*u+r[2]*s+n[2]*c+i[2]*f,t}function N(t,e,r,n,i,o){let a=1-o,u=a*a,s=o*o,c=u*a,f=3*o*u,l=3*s*a,h=s*o;return t[0]=e[0]*c+r[0]*f+n[0]*l+i[0]*h,t[1]=e[1]*c+r[1]*f+n[1]*l+i[1]*h,t[2]=e[2]*c+r[2]*f+n[2]*l+i[2]*h,t}function C(t,e){e=e||1;let r=2*n.RANDOM()*Math.PI,i=2*n.RANDOM()-1,o=Math.sqrt(1-i*i)*e;return t[0]=Math.cos(r)*o,t[1]=Math.sin(r)*o,t[2]=i*e,t}function I(t,e,r){let n=e[0],i=e[1],o=e[2],a=r[3]*n+r[7]*i+r[11]*o+r[15];return a=a||1,t[0]=(r[0]*n+r[4]*i+r[8]*o+r[12])/a,t[1]=(r[1]*n+r[5]*i+r[9]*o+r[13])/a,t[2]=(r[2]*n+r[6]*i+r[10]*o+r[14])/a,t}function L(t,e,r){let n=e[0],i=e[1],o=e[2];return t[0]=n*r[0]+i*r[3]+o*r[6],t[1]=n*r[1]+i*r[4]+o*r[7],t[2]=n*r[2]+i*r[5]+o*r[8],t}function k(t,e,r){let n=r[0],i=r[1],o=r[2],a=r[3],u=e[0],s=e[1],c=e[2],f=i*c-o*s,l=o*u-n*c,h=n*s-i*u,d=i*h-o*l,v=o*f-n*h,_=n*l-i*f,m=2*a;return f*=m,l*=m,h*=m,d*=2,v*=2,_*=2,t[0]=u+f+d,t[1]=s+l+v,t[2]=c+h+_,t}function F(t,e,r,n){let i=[],o=[];return i[0]=e[0]-r[0],i[1]=e[1]-r[1],i[2]=e[2]-r[2],o[0]=i[0],o[1]=i[1]*Math.cos(n)-i[2]*Math.sin(n),o[2]=i[1]*Math.sin(n)+i[2]*Math.cos(n),t[0]=o[0]+r[0],t[1]=o[1]+r[1],t[2]=o[2]+r[2],t}function D(t,e,r,n){let i=[],o=[];return i[0]=e[0]-r[0],i[1]=e[1]-r[1],i[2]=e[2]-r[2],o[0]=i[2]*Math.sin(n)+i[0]*Math.cos(n),o[1]=i[1],o[2]=i[2]*Math.cos(n)-i[0]*Math.sin(n),t[0]=o[0]+r[0],t[1]=o[1]+r[1],t[2]=o[2]+r[2],t}function j(t,e,r,n){let i=[],o=[];return i[0]=e[0]-r[0],i[1]=e[1]-r[1],i[2]=e[2]-r[2],o[0]=i[0]*Math.cos(n)-i[1]*Math.sin(n),o[1]=i[0]*Math.sin(n)+i[1]*Math.cos(n),o[2]=i[2],t[0]=o[0]+r[0],t[1]=o[1]+r[1],t[2]=o[2]+r[2],t}function B(t,e){let r=u(t[0],t[1],t[2]),n=u(e[0],e[1],e[2]);O(r,r),O(n,n);let i=R(r,n);return i>1?0:i<-1?Math.PI:Math.acos(i)}function U(t){return"vec3("+t[0]+", "+t[1]+", "+t[2]+")"}function V(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]}function Y(t,e){let r=t[0],i=t[1],o=t[2],a=e[0],u=e[1],s=e[2];return Math.abs(r-a)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(a))&&Math.abs(i-u)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(u))&&Math.abs(o-s)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(s))}const G=l,q=h,H=d,X=M,W=x,K=a,z=T,Q=function(){let t=i();return function(e,r,n,i,o,a){let u,s;for(r||(r=3),n||(n=0),s=i?Math.min(i*r+n,e.length):e.length,u=n;u<s;u+=r)t[0]=e[u],t[1]=e[u+1],t[2]=e[u+2],o(t,t,a),e[u]=t[0],e[u+1]=t[1],e[u+2]=t[2];return e}}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.vec4=e.vec3=e.vec2=e.quat2=e.quat=e.mat4=e.mat3=e.mat2d=e.mat2=e.glMatrix=void 0;var n=d(r(0)),i=d(r(17)),o=d(r(18)),a=d(r(12)),u=d(r(10)),s=d(r(4)),c=d(r(19)),f=d(r(20)),l=d(r(5)),h=d(r(1));function d(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e.default=t,e}e.glMatrix=n,e.mat2=i,e.mat2d=o,e.mat3=a,e.mat4=u,e.quat=s,e.quat2=c,e.vec2=f,e.vec3=l,e.vec4=h},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Primitive=e.PrimitiveAttribute=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(6);function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}e.PrimitiveAttribute=function t(e,r,n,i,a,u){o(this,t),this.name=e,this.buffer=r,this.componentCount=n||3,this.componentType=i||5126,this.stride=a||0,this.byteOffset=u||0,this.normalized=!1},e.Primitive=function(){function t(e,r,n){o(this,t),this.attributes=e||[],this.elementCount=r||0,this.mode=n||4,this.indexBuffer=null,this.indexByteOffset=0,this.indexType=0,this._min=null,this._max=null}return n(t,[{key:"setIndexBuffer",value:function(t,e,r){this.indexBuffer=t,this.indexByteOffset=e||0,this.indexType=r||5123}},{key:"setBounds",value:function(t,e){this._min=i.vec3.clone(t),this._max=i.vec3.clone(e)}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function o(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var u=WebGLRenderingContext,s=e.TextureSampler=function t(){a(this,t),this.minFilter=null,this.magFilter=null,this.wrapS=null,this.wrapT=null},c=e.Texture=function(){function t(){a(this,t),this.sampler=new s,this.mipmap=!0}return n(t,[{key:"format",get:function(){return u.RGBA}},{key:"width",get:function(){return 0}},{key:"height",get:function(){return 0}},{key:"textureKey",get:function(){return null}}]),t}(),f=e.ImageTexture=function(t){function e(t){a(this,e);var r=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._img=t,r._imgBitmap=null,t.src&&t.complete?t.naturalWidth?r._promise=r._finishImage():r._promise=Promise.reject("Image provided had failed to load."):r._promise=new Promise(function(e,n){t.addEventListener("load",function(){return e(r._finishImage())}),t.addEventListener("error",n)}),r}return o(e,c),n(e,[{key:"_finishImage",value:function(){var t=this;return window.createImageBitmap?window.createImageBitmap(this._img).then(function(e){return t._imgBitmap=e,Promise.resolve(t)}):Promise.resolve(this)}},{key:"waitForComplete",value:function(){return this._promise}},{key:"format",get:function(){return u.RGBA}},{key:"width",get:function(){return this._img.width}},{key:"height",get:function(){return this._img.height}},{key:"textureKey",get:function(){return this._img.src}},{key:"source",get:function(){return this._imgBitmap||this._img}}]),e}(),l=(e.UrlTexture=function(t){function e(t){a(this,e);var r=new Image,n=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,r));return r.src=t,n}return o(e,f),e}(),e.BlobTexture=function(t){function e(t){a(this,e);var r=new Image,n=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,r));return r.src=window.URL.createObjectURL(t),n}return o(e,f),e}(),e.VideoTexture=function(t){function e(t){a(this,e);var r=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._video=t,t.readyState>=2?r._promise=Promise.resolve(r):t.error?r._promise=Promise.reject(t.error):r._promise=new Promise(function(e,n){t.addEventListener("loadeddata",function(){return e(r)}),t.addEventListener("error",n)}),r}return o(e,c),n(e,[{key:"waitForComplete",value:function(){return this._promise}},{key:"format",get:function(){return u.RGBA}},{key:"width",get:function(){return this._video.videoWidth}},{key:"height",get:function(){return this._video.videoHeight}},{key:"textureKey",get:function(){return this._video.src}},{key:"source",get:function(){return this._video}}]),e}(),0),h=e.DataTexture=function(t){function e(t,r,n){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:u.RGBA,s=arguments.length>4&&void 0!==arguments[4]?arguments[4]:u.UNSIGNED_BYTE;a(this,e);var c=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return c._data=t,c._width=r,c._height=n,c._format=o,c._type=s,c._key="DATA_"+l,l++,c}return o(e,c),n(e,[{key:"format",get:function(){return this._format}},{key:"width",get:function(){return this._width}},{key:"height",get:function(){return this._height}},{key:"textureKey",get:function(){return this._key}}]),e}();e.ColorTexture=function(t){function e(t,r,n,o){a(this,e);var u=new Uint8Array([255*t,255*r,255*n,255*o]),s=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,u,1,1));return s.mipmap=!1,s._key="COLOR_"+u[0]+"_"+u[1]+"_"+u[2]+"_"+u[3],s}return o(e,h),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.GeometryBuilderBase=e.PrimitiveStream=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(7),o=r(6);function a(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var u=WebGLRenderingContext,s=o.vec3.create(),c=e.PrimitiveStream=function(){function t(e){a(this,t),this._vertices=[],this._indices=[],this._geometryStarted=!1,this._vertexOffset=0,this._vertexIndex=0,this._highIndex=0,this._flipWinding=!1,this._invertNormals=!1,this._transform=null,this._normalTransform=null,this._min=null,this._max=null}return n(t,[{key:"startGeometry",value:function(){if(this._geometryStarted)throw new Error("Attempted to start a new geometry before the previous one was ended.");this._geometryStarted=!0,this._vertexIndex=0,this._highIndex=0}},{key:"endGeometry",value:function(){if(!this._geometryStarted)throw new Error("Attempted to end a geometry before one was started.");if(this._highIndex>=this._vertexIndex)throw new Error("Geometry contains indices that are out of bounds.\n (Contains an index of "+this._highIndex+" when the vertex count is "+this._vertexIndex+")");this._geometryStarted=!1,this._vertexOffset+=this._vertexIndex}},{key:"pushVertex",value:function(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0,a=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,u=arguments.length>6&&void 0!==arguments[6]?arguments[6]:0,c=arguments.length>7&&void 0!==arguments[7]?arguments[7]:1;if(!this._geometryStarted)throw new Error("Cannot push vertices before calling startGeometry().");return this._transform&&(s[0]=t,s[1]=e,s[2]=r,o.vec3.transformMat4(s,s,this._transform),t=s[0],e=s[1],r=s[2],s[0]=a,s[1]=u,s[2]=c,o.vec3.transformMat3(s,s,this._normalTransform),a=s[0],u=s[1],c=s[2]),this._invertNormals&&(a*=-1,u*=-1,c*=-1),this._vertices.push(t,e,r,n,i,a,u,c),this._min?(this._min[0]=Math.min(this._min[0],t),this._min[1]=Math.min(this._min[1],e),this._min[2]=Math.min(this._min[2],r),this._max[0]=Math.max(this._max[0],t),this._max[1]=Math.max(this._max[1],e),this._max[2]=Math.max(this._max[2],r)):(this._min=o.vec3.fromValues(t,e,r),this._max=o.vec3.fromValues(t,e,r)),this._vertexIndex++}},{key:"pushTriangle",value:function(t,e,r){if(!this._geometryStarted)throw new Error("Cannot push triangles before calling startGeometry().");this._highIndex=Math.max(this._highIndex,t,e,r),t+=this._vertexOffset,e+=this._vertexOffset,r+=this._vertexOffset,this._flipWinding?this._indices.push(r,e,t):this._indices.push(t,e,r)}},{key:"clear",value:function(){if(this._geometryStarted)throw new Error("Cannot clear before ending the current geometry.");this._vertices=[],this._indices=[],this._vertexOffset=0,this._min=null,this._max=null}},{key:"finishPrimitive",value:function(t){if(!this._vertexOffset)throw new Error("Attempted to call finishPrimitive() before creating any geometry.");var e=t.createRenderBuffer(u.ARRAY_BUFFER,new Float32Array(this._vertices)),r=t.createRenderBuffer(u.ELEMENT_ARRAY_BUFFER,new Uint16Array(this._indices)),n=[new i.PrimitiveAttribute("POSITION",e,3,u.FLOAT,32,0),new i.PrimitiveAttribute("TEXCOORD_0",e,2,u.FLOAT,32,12),new i.PrimitiveAttribute("NORMAL",e,3,u.FLOAT,32,20)],o=new i.Primitive(n,this._indices.length);return o.setIndexBuffer(r),o.setBounds(this._min,this._max),o}},{key:"flipWinding",set:function(t){if(this._geometryStarted)throw new Error("Cannot change flipWinding before ending the current geometry.");this._flipWinding=t},get:function(){this._flipWinding}},{key:"invertNormals",set:function(t){if(this._geometryStarted)throw new Error("Cannot change invertNormals before ending the current geometry.");this._invertNormals=t},get:function(){this._invertNormals}},{key:"transform",set:function(t){if(this._geometryStarted)throw new Error("Cannot change transform before ending the current geometry.");this._transform=t,this._transform&&(this._normalTransform||(this._normalTransform=o.mat3.create()),o.mat3.fromMat4(this._normalTransform,this._transform))},get:function(){this._transform}},{key:"nextVertexIndex",get:function(){return this._vertexIndex}}]),t}();e.GeometryBuilderBase=function(){function t(e){a(this,t),this._stream=e||new c}return n(t,[{key:"finishPrimitive",value:function(t){return this._stream.finishPrimitive(t)}},{key:"clear",value:function(){this._stream.clear()}},{key:"primitiveStream",set:function(t){this._stream=t},get:function(){return this._stream}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"copy",function(){return a}),r.d(e,"fromValues",function(){return u}),r.d(e,"set",function(){return s}),r.d(e,"identity",function(){return c}),r.d(e,"transpose",function(){return f}),r.d(e,"invert",function(){return l}),r.d(e,"adjoint",function(){return h}),r.d(e,"determinant",function(){return d}),r.d(e,"multiply",function(){return v}),r.d(e,"translate",function(){return _}),r.d(e,"scale",function(){return m}),r.d(e,"rotate",function(){return p}),r.d(e,"rotateX",function(){return y}),r.d(e,"rotateY",function(){return b}),r.d(e,"rotateZ",function(){return g}),r.d(e,"fromTranslation",function(){return M}),r.d(e,"fromScaling",function(){return x}),r.d(e,"fromRotation",function(){return T}),r.d(e,"fromXRotation",function(){return E}),r.d(e,"fromYRotation",function(){return w}),r.d(e,"fromZRotation",function(){return O}),r.d(e,"fromRotationTranslation",function(){return R}),r.d(e,"fromQuat2",function(){return P}),r.d(e,"getTranslation",function(){return S}),r.d(e,"getScaling",function(){return A}),r.d(e,"getRotation",function(){return N}),r.d(e,"fromRotationTranslationScale",function(){return C}),r.d(e,"fromRotationTranslationScaleOrigin",function(){return I}),r.d(e,"fromQuat",function(){return L}),r.d(e,"frustum",function(){return k}),r.d(e,"perspective",function(){return F}),r.d(e,"perspectiveFromFieldOfView",function(){return D}),r.d(e,"ortho",function(){return j}),r.d(e,"lookAt",function(){return B}),r.d(e,"targetTo",function(){return U}),r.d(e,"str",function(){return V}),r.d(e,"frob",function(){return Y}),r.d(e,"add",function(){return G}),r.d(e,"subtract",function(){return q}),r.d(e,"multiplyScalar",function(){return H}),r.d(e,"multiplyScalarAndAdd",function(){return X}),r.d(e,"exactEquals",function(){return W}),r.d(e,"equals",function(){return K}),r.d(e,"mul",function(){return z}),r.d(e,"sub",function(){return Q});var n=r(0);function i(){let t=new n.ARRAY_TYPE(16);return n.ARRAY_TYPE!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0),t[0]=1,t[5]=1,t[10]=1,t[15]=1,t}function o(t){let e=new n.ARRAY_TYPE(16);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e[9]=t[9],e[10]=t[10],e[11]=t[11],e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15],e}function a(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t}function u(t,e,r,i,o,a,u,s,c,f,l,h,d,v,_,m){let p=new n.ARRAY_TYPE(16);return p[0]=t,p[1]=e,p[2]=r,p[3]=i,p[4]=o,p[5]=a,p[6]=u,p[7]=s,p[8]=c,p[9]=f,p[10]=l,p[11]=h,p[12]=d,p[13]=v,p[14]=_,p[15]=m,p}function s(t,e,r,n,i,o,a,u,s,c,f,l,h,d,v,_,m){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t[6]=u,t[7]=s,t[8]=c,t[9]=f,t[10]=l,t[11]=h,t[12]=d,t[13]=v,t[14]=_,t[15]=m,t}function c(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function f(t,e){if(t===e){let r=e[1],n=e[2],i=e[3],o=e[6],a=e[7],u=e[11];t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=r,t[6]=e[9],t[7]=e[13],t[8]=n,t[9]=o,t[11]=e[14],t[12]=i,t[13]=a,t[14]=u}else t[0]=e[0],t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=e[1],t[5]=e[5],t[6]=e[9],t[7]=e[13],t[8]=e[2],t[9]=e[6],t[10]=e[10],t[11]=e[14],t[12]=e[3],t[13]=e[7],t[14]=e[11],t[15]=e[15];return t}function l(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=e[9],h=e[10],d=e[11],v=e[12],_=e[13],m=e[14],p=e[15],y=r*u-n*a,b=r*s-i*a,g=r*c-o*a,M=n*s-i*u,x=n*c-o*u,T=i*c-o*s,E=f*_-l*v,w=f*m-h*v,O=f*p-d*v,R=l*m-h*_,P=l*p-d*_,S=h*p-d*m,A=y*S-b*P+g*R+M*O-x*w+T*E;return A?(A=1/A,t[0]=(u*S-s*P+c*R)*A,t[1]=(i*P-n*S-o*R)*A,t[2]=(_*T-m*x+p*M)*A,t[3]=(h*x-l*T-d*M)*A,t[4]=(s*O-a*S-c*w)*A,t[5]=(r*S-i*O+o*w)*A,t[6]=(m*g-v*T-p*b)*A,t[7]=(f*T-h*g+d*b)*A,t[8]=(a*P-u*O+c*E)*A,t[9]=(n*O-r*P-o*E)*A,t[10]=(v*x-_*g+p*y)*A,t[11]=(l*g-f*x-d*y)*A,t[12]=(u*w-a*R-s*E)*A,t[13]=(r*R-n*w+i*E)*A,t[14]=(_*b-v*M-m*y)*A,t[15]=(f*M-l*b+h*y)*A,t):null}function h(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=e[9],h=e[10],d=e[11],v=e[12],_=e[13],m=e[14],p=e[15];return t[0]=u*(h*p-d*m)-l*(s*p-c*m)+_*(s*d-c*h),t[1]=-(n*(h*p-d*m)-l*(i*p-o*m)+_*(i*d-o*h)),t[2]=n*(s*p-c*m)-u*(i*p-o*m)+_*(i*c-o*s),t[3]=-(n*(s*d-c*h)-u*(i*d-o*h)+l*(i*c-o*s)),t[4]=-(a*(h*p-d*m)-f*(s*p-c*m)+v*(s*d-c*h)),t[5]=r*(h*p-d*m)-f*(i*p-o*m)+v*(i*d-o*h),t[6]=-(r*(s*p-c*m)-a*(i*p-o*m)+v*(i*c-o*s)),t[7]=r*(s*d-c*h)-a*(i*d-o*h)+f*(i*c-o*s),t[8]=a*(l*p-d*_)-f*(u*p-c*_)+v*(u*d-c*l),t[9]=-(r*(l*p-d*_)-f*(n*p-o*_)+v*(n*d-o*l)),t[10]=r*(u*p-c*_)-a*(n*p-o*_)+v*(n*c-o*u),t[11]=-(r*(u*d-c*l)-a*(n*d-o*l)+f*(n*c-o*u)),t[12]=-(a*(l*m-h*_)-f*(u*m-s*_)+v*(u*h-s*l)),t[13]=r*(l*m-h*_)-f*(n*m-i*_)+v*(n*h-i*l),t[14]=-(r*(u*m-s*_)-a*(n*m-i*_)+v*(n*s-i*u)),t[15]=r*(u*h-s*l)-a*(n*h-i*l)+f*(n*s-i*u),t}function d(t){let e=t[0],r=t[1],n=t[2],i=t[3],o=t[4],a=t[5],u=t[6],s=t[7],c=t[8],f=t[9],l=t[10],h=t[11],d=t[12],v=t[13],_=t[14],m=t[15];return(e*a-r*o)*(l*m-h*_)-(e*u-n*o)*(f*m-h*v)+(e*s-i*o)*(f*_-l*v)+(r*u-n*a)*(c*m-h*d)-(r*s-i*a)*(c*_-l*d)+(n*s-i*u)*(c*v-f*d)}function v(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=e[9],d=e[10],v=e[11],_=e[12],m=e[13],p=e[14],y=e[15],b=r[0],g=r[1],M=r[2],x=r[3];return t[0]=b*n+g*u+M*l+x*_,t[1]=b*i+g*s+M*h+x*m,t[2]=b*o+g*c+M*d+x*p,t[3]=b*a+g*f+M*v+x*y,b=r[4],g=r[5],M=r[6],x=r[7],t[4]=b*n+g*u+M*l+x*_,t[5]=b*i+g*s+M*h+x*m,t[6]=b*o+g*c+M*d+x*p,t[7]=b*a+g*f+M*v+x*y,b=r[8],g=r[9],M=r[10],x=r[11],t[8]=b*n+g*u+M*l+x*_,t[9]=b*i+g*s+M*h+x*m,t[10]=b*o+g*c+M*d+x*p,t[11]=b*a+g*f+M*v+x*y,b=r[12],g=r[13],M=r[14],x=r[15],t[12]=b*n+g*u+M*l+x*_,t[13]=b*i+g*s+M*h+x*m,t[14]=b*o+g*c+M*d+x*p,t[15]=b*a+g*f+M*v+x*y,t}function _(t,e,r){let n,i,o,a,u,s,c,f,l,h,d,v,_=r[0],m=r[1],p=r[2];return e===t?(t[12]=e[0]*_+e[4]*m+e[8]*p+e[12],t[13]=e[1]*_+e[5]*m+e[9]*p+e[13],t[14]=e[2]*_+e[6]*m+e[10]*p+e[14],t[15]=e[3]*_+e[7]*m+e[11]*p+e[15]):(n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=e[9],d=e[10],v=e[11],t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=u,t[5]=s,t[6]=c,t[7]=f,t[8]=l,t[9]=h,t[10]=d,t[11]=v,t[12]=n*_+u*m+l*p+e[12],t[13]=i*_+s*m+h*p+e[13],t[14]=o*_+c*m+d*p+e[14],t[15]=a*_+f*m+v*p+e[15]),t}function m(t,e,r){let n=r[0],i=r[1],o=r[2];return t[0]=e[0]*n,t[1]=e[1]*n,t[2]=e[2]*n,t[3]=e[3]*n,t[4]=e[4]*i,t[5]=e[5]*i,t[6]=e[6]*i,t[7]=e[7]*i,t[8]=e[8]*o,t[9]=e[9]*o,t[10]=e[10]*o,t[11]=e[11]*o,t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t}function p(t,e,r,i){let o,a,u,s,c,f,l,h,d,v,_,m,p,y,b,g,M,x,T,E,w,O,R,P,S=i[0],A=i[1],N=i[2],C=Math.sqrt(S*S+A*A+N*N);return C<n.EPSILON?null:(S*=C=1/C,A*=C,N*=C,o=Math.sin(r),u=1-(a=Math.cos(r)),s=e[0],c=e[1],f=e[2],l=e[3],h=e[4],d=e[5],v=e[6],_=e[7],m=e[8],p=e[9],y=e[10],b=e[11],g=S*S*u+a,M=A*S*u+N*o,x=N*S*u-A*o,T=S*A*u-N*o,E=A*A*u+a,w=N*A*u+S*o,O=S*N*u+A*o,R=A*N*u-S*o,P=N*N*u+a,t[0]=s*g+h*M+m*x,t[1]=c*g+d*M+p*x,t[2]=f*g+v*M+y*x,t[3]=l*g+_*M+b*x,t[4]=s*T+h*E+m*w,t[5]=c*T+d*E+p*w,t[6]=f*T+v*E+y*w,t[7]=l*T+_*E+b*w,t[8]=s*O+h*R+m*P,t[9]=c*O+d*R+p*P,t[10]=f*O+v*R+y*P,t[11]=l*O+_*R+b*P,e!==t&&(t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t)}function y(t,e,r){let n=Math.sin(r),i=Math.cos(r),o=e[4],a=e[5],u=e[6],s=e[7],c=e[8],f=e[9],l=e[10],h=e[11];return e!==t&&(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[4]=o*i+c*n,t[5]=a*i+f*n,t[6]=u*i+l*n,t[7]=s*i+h*n,t[8]=c*i-o*n,t[9]=f*i-a*n,t[10]=l*i-u*n,t[11]=h*i-s*n,t}function b(t,e,r){let n=Math.sin(r),i=Math.cos(r),o=e[0],a=e[1],u=e[2],s=e[3],c=e[8],f=e[9],l=e[10],h=e[11];return e!==t&&(t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[0]=o*i-c*n,t[1]=a*i-f*n,t[2]=u*i-l*n,t[3]=s*i-h*n,t[8]=o*n+c*i,t[9]=a*n+f*i,t[10]=u*n+l*i,t[11]=s*n+h*i,t}function g(t,e,r){let n=Math.sin(r),i=Math.cos(r),o=e[0],a=e[1],u=e[2],s=e[3],c=e[4],f=e[5],l=e[6],h=e[7];return e!==t&&(t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[0]=o*i+c*n,t[1]=a*i+f*n,t[2]=u*i+l*n,t[3]=s*i+h*n,t[4]=c*i-o*n,t[5]=f*i-a*n,t[6]=l*i-u*n,t[7]=h*i-s*n,t}function M(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=e[0],t[13]=e[1],t[14]=e[2],t[15]=1,t}function x(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=e[1],t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=e[2],t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function T(t,e,r){let i,o,a,u=r[0],s=r[1],c=r[2],f=Math.sqrt(u*u+s*s+c*c);return f<n.EPSILON?null:(u*=f=1/f,s*=f,c*=f,i=Math.sin(e),a=1-(o=Math.cos(e)),t[0]=u*u*a+o,t[1]=s*u*a+c*i,t[2]=c*u*a-s*i,t[3]=0,t[4]=u*s*a-c*i,t[5]=s*s*a+o,t[6]=c*s*a+u*i,t[7]=0,t[8]=u*c*a+s*i,t[9]=s*c*a-u*i,t[10]=c*c*a+o,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t)}function E(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=n,t[6]=r,t[7]=0,t[8]=0,t[9]=-r,t[10]=n,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function w(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=0,t[2]=-r,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=r,t[9]=0,t[10]=n,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function O(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=0,t[3]=0,t[4]=-r,t[5]=n,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function R(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=n+n,s=i+i,c=o+o,f=n*u,l=n*s,h=n*c,d=i*s,v=i*c,_=o*c,m=a*u,p=a*s,y=a*c;return t[0]=1-(d+_),t[1]=l+y,t[2]=h-p,t[3]=0,t[4]=l-y,t[5]=1-(f+_),t[6]=v+m,t[7]=0,t[8]=h+p,t[9]=v-m,t[10]=1-(f+d),t[11]=0,t[12]=r[0],t[13]=r[1],t[14]=r[2],t[15]=1,t}function P(t,e){let r=new n.ARRAY_TYPE(3),i=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=i*i+o*o+a*a+u*u;return h>0?(r[0]=2*(s*u+l*i+c*a-f*o)/h,r[1]=2*(c*u+l*o+f*i-s*a)/h,r[2]=2*(f*u+l*a+s*o-c*i)/h):(r[0]=2*(s*u+l*i+c*a-f*o),r[1]=2*(c*u+l*o+f*i-s*a),r[2]=2*(f*u+l*a+s*o-c*i)),R(t,e,r),t}function S(t,e){return t[0]=e[12],t[1]=e[13],t[2]=e[14],t}function A(t,e){let r=e[0],n=e[1],i=e[2],o=e[4],a=e[5],u=e[6],s=e[8],c=e[9],f=e[10];return t[0]=Math.sqrt(r*r+n*n+i*i),t[1]=Math.sqrt(o*o+a*a+u*u),t[2]=Math.sqrt(s*s+c*c+f*f),t}function N(t,e){let r=e[0]+e[5]+e[10],n=0;return r>0?(n=2*Math.sqrt(r+1),t[3]=.25*n,t[0]=(e[6]-e[9])/n,t[1]=(e[8]-e[2])/n,t[2]=(e[1]-e[4])/n):e[0]>e[5]&&e[0]>e[10]?(n=2*Math.sqrt(1+e[0]-e[5]-e[10]),t[3]=(e[6]-e[9])/n,t[0]=.25*n,t[1]=(e[1]+e[4])/n,t[2]=(e[8]+e[2])/n):e[5]>e[10]?(n=2*Math.sqrt(1+e[5]-e[0]-e[10]),t[3]=(e[8]-e[2])/n,t[0]=(e[1]+e[4])/n,t[1]=.25*n,t[2]=(e[6]+e[9])/n):(n=2*Math.sqrt(1+e[10]-e[0]-e[5]),t[3]=(e[1]-e[4])/n,t[0]=(e[8]+e[2])/n,t[1]=(e[6]+e[9])/n,t[2]=.25*n),t}function C(t,e,r,n){let i=e[0],o=e[1],a=e[2],u=e[3],s=i+i,c=o+o,f=a+a,l=i*s,h=i*c,d=i*f,v=o*c,_=o*f,m=a*f,p=u*s,y=u*c,b=u*f,g=n[0],M=n[1],x=n[2];return t[0]=(1-(v+m))*g,t[1]=(h+b)*g,t[2]=(d-y)*g,t[3]=0,t[4]=(h-b)*M,t[5]=(1-(l+m))*M,t[6]=(_+p)*M,t[7]=0,t[8]=(d+y)*x,t[9]=(_-p)*x,t[10]=(1-(l+v))*x,t[11]=0,t[12]=r[0],t[13]=r[1],t[14]=r[2],t[15]=1,t}function I(t,e,r,n,i){let o=e[0],a=e[1],u=e[2],s=e[3],c=o+o,f=a+a,l=u+u,h=o*c,d=o*f,v=o*l,_=a*f,m=a*l,p=u*l,y=s*c,b=s*f,g=s*l,M=n[0],x=n[1],T=n[2],E=i[0],w=i[1],O=i[2],R=(1-(_+p))*M,P=(d+g)*M,S=(v-b)*M,A=(d-g)*x,N=(1-(h+p))*x,C=(m+y)*x,I=(v+b)*T,L=(m-y)*T,k=(1-(h+_))*T;return t[0]=R,t[1]=P,t[2]=S,t[3]=0,t[4]=A,t[5]=N,t[6]=C,t[7]=0,t[8]=I,t[9]=L,t[10]=k,t[11]=0,t[12]=r[0]+E-(R*E+A*w+I*O),t[13]=r[1]+w-(P*E+N*w+L*O),t[14]=r[2]+O-(S*E+C*w+k*O),t[15]=1,t}function L(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r+r,u=n+n,s=i+i,c=r*a,f=n*a,l=n*u,h=i*a,d=i*u,v=i*s,_=o*a,m=o*u,p=o*s;return t[0]=1-l-v,t[1]=f+p,t[2]=h-m,t[3]=0,t[4]=f-p,t[5]=1-c-v,t[6]=d+_,t[7]=0,t[8]=h+m,t[9]=d-_,t[10]=1-c-l,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function k(t,e,r,n,i,o,a){let u=1/(r-e),s=1/(i-n),c=1/(o-a);return t[0]=2*o*u,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*o*s,t[6]=0,t[7]=0,t[8]=(r+e)*u,t[9]=(i+n)*s,t[10]=(a+o)*c,t[11]=-1,t[12]=0,t[13]=0,t[14]=a*o*2*c,t[15]=0,t}function F(t,e,r,n,i){let o,a=1/Math.tan(e/2);return t[0]=a/r,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=a,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=-1,t[12]=0,t[13]=0,t[15]=0,null!=i&&i!==1/0?(o=1/(n-i),t[10]=(i+n)*o,t[14]=2*i*n*o):(t[10]=-1,t[14]=-2*n),t}function D(t,e,r,n){let i=Math.tan(e.upDegrees*Math.PI/180),o=Math.tan(e.downDegrees*Math.PI/180),a=Math.tan(e.leftDegrees*Math.PI/180),u=Math.tan(e.rightDegrees*Math.PI/180),s=2/(a+u),c=2/(i+o);return t[0]=s,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=c,t[6]=0,t[7]=0,t[8]=-(a-u)*s*.5,t[9]=(i-o)*c*.5,t[10]=n/(r-n),t[11]=-1,t[12]=0,t[13]=0,t[14]=n*r/(r-n),t[15]=0,t}function j(t,e,r,n,i,o,a){let u=1/(e-r),s=1/(n-i),c=1/(o-a);return t[0]=-2*u,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*s,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*c,t[11]=0,t[12]=(e+r)*u,t[13]=(i+n)*s,t[14]=(a+o)*c,t[15]=1,t}function B(t,e,r,i){let o,a,u,s,f,l,h,d,v,_,m=e[0],p=e[1],y=e[2],b=i[0],g=i[1],M=i[2],x=r[0],T=r[1],E=r[2];return Math.abs(m-x)<n.EPSILON&&Math.abs(p-T)<n.EPSILON&&Math.abs(y-E)<n.EPSILON?c(t):(h=m-x,d=p-T,v=y-E,o=g*(v*=_=1/Math.sqrt(h*h+d*d+v*v))-M*(d*=_),a=M*(h*=_)-b*v,u=b*d-g*h,(_=Math.sqrt(o*o+a*a+u*u))?(o*=_=1/_,a*=_,u*=_):(o=0,a=0,u=0),s=d*u-v*a,f=v*o-h*u,l=h*a-d*o,(_=Math.sqrt(s*s+f*f+l*l))?(s*=_=1/_,f*=_,l*=_):(s=0,f=0,l=0),t[0]=o,t[1]=s,t[2]=h,t[3]=0,t[4]=a,t[5]=f,t[6]=d,t[7]=0,t[8]=u,t[9]=l,t[10]=v,t[11]=0,t[12]=-(o*m+a*p+u*y),t[13]=-(s*m+f*p+l*y),t[14]=-(h*m+d*p+v*y),t[15]=1,t)}function U(t,e,r,n){let i=e[0],o=e[1],a=e[2],u=n[0],s=n[1],c=n[2],f=i-r[0],l=o-r[1],h=a-r[2],d=f*f+l*l+h*h;d>0&&(f*=d=1/Math.sqrt(d),l*=d,h*=d);let v=s*h-c*l,_=c*f-u*h,m=u*l-s*f;return(d=v*v+_*_+m*m)>0&&(v*=d=1/Math.sqrt(d),_*=d,m*=d),t[0]=v,t[1]=_,t[2]=m,t[3]=0,t[4]=l*m-h*_,t[5]=h*v-f*m,t[6]=f*_-l*v,t[7]=0,t[8]=f,t[9]=l,t[10]=h,t[11]=0,t[12]=i,t[13]=o,t[14]=a,t[15]=1,t}function V(t){return"mat4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+", "+t[9]+", "+t[10]+", "+t[11]+", "+t[12]+", "+t[13]+", "+t[14]+", "+t[15]+")"}function Y(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+Math.pow(t[6],2)+Math.pow(t[7],2)+Math.pow(t[8],2)+Math.pow(t[9],2)+Math.pow(t[10],2)+Math.pow(t[11],2)+Math.pow(t[12],2)+Math.pow(t[13],2)+Math.pow(t[14],2)+Math.pow(t[15],2))}function G(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t[6]=e[6]+r[6],t[7]=e[7]+r[7],t[8]=e[8]+r[8],t[9]=e[9]+r[9],t[10]=e[10]+r[10],t[11]=e[11]+r[11],t[12]=e[12]+r[12],t[13]=e[13]+r[13],t[14]=e[14]+r[14],t[15]=e[15]+r[15],t}function q(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t[4]=e[4]-r[4],t[5]=e[5]-r[5],t[6]=e[6]-r[6],t[7]=e[7]-r[7],t[8]=e[8]-r[8],t[9]=e[9]-r[9],t[10]=e[10]-r[10],t[11]=e[11]-r[11],t[12]=e[12]-r[12],t[13]=e[13]-r[13],t[14]=e[14]-r[14],t[15]=e[15]-r[15],t}function H(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t[6]=e[6]*r,t[7]=e[7]*r,t[8]=e[8]*r,t[9]=e[9]*r,t[10]=e[10]*r,t[11]=e[11]*r,t[12]=e[12]*r,t[13]=e[13]*r,t[14]=e[14]*r,t[15]=e[15]*r,t}function X(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t[4]=e[4]+r[4]*n,t[5]=e[5]+r[5]*n,t[6]=e[6]+r[6]*n,t[7]=e[7]+r[7]*n,t[8]=e[8]+r[8]*n,t[9]=e[9]+r[9]*n,t[10]=e[10]+r[10]*n,t[11]=e[11]+r[11]*n,t[12]=e[12]+r[12]*n,t[13]=e[13]+r[13]*n,t[14]=e[14]+r[14]*n,t[15]=e[15]+r[15]*n,t}function W(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]&&t[6]===e[6]&&t[7]===e[7]&&t[8]===e[8]&&t[9]===e[9]&&t[10]===e[10]&&t[11]===e[11]&&t[12]===e[12]&&t[13]===e[13]&&t[14]===e[14]&&t[15]===e[15]}function K(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=t[6],f=t[7],l=t[8],h=t[9],d=t[10],v=t[11],_=t[12],m=t[13],p=t[14],y=t[15],b=e[0],g=e[1],M=e[2],x=e[3],T=e[4],E=e[5],w=e[6],O=e[7],R=e[8],P=e[9],S=e[10],A=e[11],N=e[12],C=e[13],I=e[14],L=e[15];return Math.abs(r-b)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(b))&&Math.abs(i-g)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(g))&&Math.abs(o-M)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(M))&&Math.abs(a-x)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(x))&&Math.abs(u-T)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(T))&&Math.abs(s-E)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(E))&&Math.abs(c-w)<=n.EPSILON*Math.max(1,Math.abs(c),Math.abs(w))&&Math.abs(f-O)<=n.EPSILON*Math.max(1,Math.abs(f),Math.abs(O))&&Math.abs(l-R)<=n.EPSILON*Math.max(1,Math.abs(l),Math.abs(R))&&Math.abs(h-P)<=n.EPSILON*Math.max(1,Math.abs(h),Math.abs(P))&&Math.abs(d-S)<=n.EPSILON*Math.max(1,Math.abs(d),Math.abs(S))&&Math.abs(v-A)<=n.EPSILON*Math.max(1,Math.abs(v),Math.abs(A))&&Math.abs(_-N)<=n.EPSILON*Math.max(1,Math.abs(_),Math.abs(N))&&Math.abs(m-C)<=n.EPSILON*Math.max(1,Math.abs(m),Math.abs(C))&&Math.abs(p-I)<=n.EPSILON*Math.max(1,Math.abs(p),Math.abs(I))&&Math.abs(y-L)<=n.EPSILON*Math.max(1,Math.abs(y),Math.abs(L))}const z=v,Q=q},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Renderer=e.RenderTexture=e.RenderView=e.ATTRIB_MASK=e.ATTRIB=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();e.createWebGLContext=p;var i=r(3),o=r(2),a=r(21),u=r(8),s=r(6);function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var f=e.ATTRIB={POSITION:1,NORMAL:2,TANGENT:3,TEXCOORD_0:4,TEXCOORD_1:5,COLOR_0:6},l=e.ATTRIB_MASK={POSITION:1,NORMAL:2,TANGENT:4,TEXCOORD_0:8,TEXCOORD_1:16,COLOR_0:32},h=WebGLRenderingContext,d=new Float32Array([-.1,-1,-.2]),v=new Float32Array([3,3,3]),_=new RegExp("precision (lowp|mediump|highp) float;");function m(t){return 0==(t&t-1)}function p(t){t=t||{alpha:!1};var e=document.createElement("canvas"),r=t.webgl2?["webgl2"]:["webgl","experimental-webgl"],n=null,i=!0,o=!1,a=void 0;try{for(var u,s=r[Symbol.iterator]();!(i=(u=s.next()).done);i=!0){var c=u.value;if(n=e.getContext(c,t))break}}catch(t){o=!0,a=t}finally{try{!i&&s.return&&s.return()}finally{if(o)throw a}}if(!n){var f=t.webgl2?"WebGL 2":"WebGL";return console.error("This browser does not support "+f+"."),null}return n}e.RenderView=function(){function t(e,r){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"left";c(this,t),this.projectionMatrix=e,this.viewMatrix=r,this.viewport=n,this._eye=i,this._eyeIndex="left"==i?0:1}return n(t,[{key:"eye",get:function(){return this._eye},set:function(t){this._eye=t,this._eyeIndex="left"==t?0:1}},{key:"eyeIndex",get:function(){return this._eyeIndex}}]),t}();var y=function(){function t(e,r,n){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;c(this,t),this._target=e,this._usage=r,this._length=o,n instanceof Promise?(this._buffer=null,this._promise=n.then(function(t){return i._buffer=t,i})):(this._buffer=n,this._promise=Promise.resolve(this))}return n(t,[{key:"waitForComplete",value:function(){return this._promise}}]),t}(),b=function t(e){c(this,t),this._attrib_index=f[e.name],this._componentCount=e.componentCount,this._componentType=e.componentType,this._stride=e.stride,this._byteOffset=e.byteOffset,this._normalized=e.normalized},g=function t(e){c(this,t),this._buffer=e,this._attributes=[]},M=function(){function t(e){c(this,t),this._activeFrameId=0,this._instances=[],this._material=null,this.setPrimitive(e)}return n(t,[{key:"setPrimitive",value:function(t){this._mode=t.mode,this._elementCount=t.elementCount,this._promise=null,this._vao=null,this._complete=!1,this._attributeBuffers=[],this._attributeMask=0;var e=!0,r=!1,n=void 0;try{for(var i,o=t.attributes[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){var a=i.value;this._attributeMask|=l[a.name];var u=new b(a),c=!1,f=!0,h=!1,d=void 0;try{for(var v,_=this._attributeBuffers[Symbol.iterator]();!(f=(v=_.next()).done);f=!0){var m=v.value;if(m._buffer==a.buffer){m._attributes.push(u),c=!0;break}}}catch(t){h=!0,d=t}finally{try{!f&&_.return&&_.return()}finally{if(h)throw d}}if(!c){var p=new g(a.buffer);p._attributes.push(u),this._attributeBuffers.push(p)}}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}this._indexBuffer=null,this._indexByteOffset=0,this._indexType=0,t.indexBuffer&&(this._indexByteOffset=t.indexByteOffset,this._indexType=t.indexType,this._indexBuffer=t.indexBuffer),t._min?(this._min=s.vec3.clone(t._min),this._max=s.vec3.clone(t._max)):(this._min=null,this._max=null),null!=this._material&&this.waitForComplete()}},{key:"setRenderMaterial",value:function(t){this._material=t,this._promise=null,this._complete=!1,null!=this._material&&this.waitForComplete()}},{key:"markActive",value:function(t){if(this._complete&&this._activeFrameId!=t){if(this._material&&!this._material.markActive(t))return;this._activeFrameId=t}}},{key:"waitForComplete",value:function(){var t=this;if(!this._promise){if(!this._material)return Promise.reject("RenderPrimitive does not have a material");var e=[],r=!0,n=!1,i=void 0;try{for(var o,a=this._attributeBuffers[Symbol.iterator]();!(r=(o=a.next()).done);r=!0){var u=o.value;u._buffer._buffer||e.push(u._buffer._promise)}}catch(t){n=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(n)throw i}}this._indexBuffer&&!this._indexBuffer._buffer&&e.push(this._indexBuffer._promise),this._promise=Promise.all(e).then(function(){return t._complete=!0,t})}return this._promise}},{key:"samplers",get:function(){return this._material._samplerDictionary}},{key:"uniforms",get:function(){return this._material._uniform_dictionary}}]),t}(),x=e.RenderTexture=function(){function t(e){c(this,t),this._texture=e,this._complete=!1,this._activeFrameId=0,this._activeCallback=null}return n(t,[{key:"markActive",value:function(t){this._activeCallback&&this._activeFrameId!=t&&(this._activeFrameId=t,this._activeCallback(this))}}]),t}(),T=s.mat4.create();function E(t,e,r,n,i){var o=(i&r)-(n&r);o&&(o>0?t.enable(e):t.disable(e))}var w=function(){function t(e,r,n){c(this,t),this._renderer=e,this._uniformName=r._uniformName,this._renderTexture=e._getRenderTexture(r._texture),this._index=n}return n(t,[{key:"texture",set:function(t){this._renderTexture=this._renderer._getRenderTexture(t)}}]),t}(),O=function(){function t(e){c(this,t),this._uniformName=e._uniformName,this._uniform=null,this._length=e._length,e._value instanceof Array?this._value=new Float32Array(e._value):this._value=new Float32Array([e._value])}return n(t,[{key:"value",set:function(t){if(1==this._value.length)this._value[0]=t;else for(var e=0;e<this._value.length;++e)this._value[e]=t[e]}}]),t}(),R=function(){function t(e,r,n){c(this,t),this._program=n,this._state=r.state._state,this._activeFrameId=0,this._completeForActiveFrame=!1,this._samplerDictionary={},this._samplers=[];for(var o=0;o<r._samplers.length;++o){var a=new w(e,r._samplers[o],o);this._samplers.push(a),this._samplerDictionary[a._uniformName]=a}this._uniform_dictionary={},this._uniforms=[];var u=!0,s=!1,f=void 0;try{for(var l,h=r._uniforms[Symbol.iterator]();!(u=(l=h.next()).done);u=!0){var d=l.value,v=new O(d);this._uniforms.push(v),this._uniform_dictionary[v._uniformName]=v}}catch(t){s=!0,f=t}finally{try{!u&&h.return&&h.return()}finally{if(s)throw f}}this._firstBind=!0,this._renderOrder=r.renderOrder,this._renderOrder==i.RENDER_ORDER.DEFAULT&&(this._state&i.CAP.BLEND?this._renderOrder=i.RENDER_ORDER.TRANSPARENT:this._renderOrder=i.RENDER_ORDER.OPAQUE)}return n(t,[{key:"bind",value:function(t){if(this._firstBind){for(var e=0;e<this._samplers.length;){var r=this._samplers[e];this._program.uniform[r._uniformName]?++e:this._samplers.splice(e,1)}for(var n=0;n<this._uniforms.length;){var i=this._uniforms[n];i._uniform=this._program.uniform[i._uniformName],i._uniform?++n:this._uniforms.splice(n,1)}this._firstBind=!1}var o=!0,a=!1,u=void 0;try{for(var s,c=this._samplers[Symbol.iterator]();!(o=(s=c.next()).done);o=!0){var f=s.value;t.activeTexture(t.TEXTURE0+f._index),f._renderTexture&&f._renderTexture._complete?t.bindTexture(t.TEXTURE_2D,f._renderTexture._texture):t.bindTexture(t.TEXTURE_2D,null)}}catch(t){a=!0,u=t}finally{try{!o&&c.return&&c.return()}finally{if(a)throw u}}var l=!0,h=!1,d=void 0;try{for(var v,_=this._uniforms[Symbol.iterator]();!(l=(v=_.next()).done);l=!0){var m=v.value;switch(m._length){case 1:t.uniform1fv(m._uniform,m._value);break;case 2:t.uniform2fv(m._uniform,m._value);break;case 3:t.uniform3fv(m._uniform,m._value);break;case 4:t.uniform4fv(m._uniform,m._value)}}}catch(t){h=!0,d=t}finally{try{!l&&_.return&&_.return()}finally{if(h)throw d}}}},{key:"markActive",value:function(t){if(this._activeFrameId!=t){this._activeFrameId=t,this._completeForActiveFrame=!0;for(var e=0;e<this._samplers.length;++e){var r=this._samplers[e];if(r._renderTexture){if(!r._renderTexture._complete){this._completeForActiveFrame=!1;break}r._renderTexture.markActive(t)}}}return this._completeForActiveFrame}},{key:"_capsDiff",value:function(t){return t&i.MAT_STATE.CAPS_RANGE^this._state&i.MAT_STATE.CAPS_RANGE}},{key:"_blendDiff",value:function(t){return this._state&i.CAP.BLEND?t&i.MAT_STATE.BLEND_FUNC_RANGE^this._state&i.MAT_STATE.BLEND_FUNC_RANGE:0}},{key:"_depthFuncDiff",value:function(t){return this._state&i.CAP.DEPTH_TEST?t&i.MAT_STATE.DEPTH_FUNC_RANGE^this._state&i.MAT_STATE.DEPTH_FUNC_RANGE:0}},{key:"cullFace",get:function(){return!!(this._state&i.CAP.CULL_FACE)}},{key:"blend",get:function(){return!!(this._state&i.CAP.BLEND)}},{key:"depthTest",get:function(){return!!(this._state&i.CAP.DEPTH_TEST)}},{key:"stencilTest",get:function(){return!!(this._state&i.CAP.STENCIL_TEST)}},{key:"colorMask",get:function(){return!!(this._state&i.CAP.COLOR_MASK)}},{key:"depthMask",get:function(){return!!(this._state&i.CAP.DEPTH_MASK)}},{key:"stencilMask",get:function(){return!!(this._state&i.CAP.STENCIL_MASK)}},{key:"depthFunc",get:function(){return((this._state&i.MAT_STATE.DEPTH_FUNC_RANGE)>>i.MAT_STATE.DEPTH_FUNC_SHIFT)+h.NEVER}},{key:"blendFuncSrc",get:function(){return(0,i.stateToBlendFunc)(this._state,i.MAT_STATE.BLEND_SRC_RANGE,i.MAT_STATE.BLEND_SRC_SHIFT)}},{key:"blendFuncDst",get:function(){return(0,i.stateToBlendFunc)(this._state,i.MAT_STATE.BLEND_DST_RANGE,i.MAT_STATE.BLEND_DST_SHIFT)}}]),t}();e.Renderer=function(){function t(e){c(this,t),this._gl=e||p(),this._frameId=0,this._programCache={},this._textureCache={},this._renderPrimitives=Array(i.RENDER_ORDER.DEFAULT),this._cameraPositions=[],this._vaoExt=e.getExtension("OES_vertex_array_object");var r=e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT);this._defaultFragPrecision=r.precision>0?"highp":"mediump",this._depthMaskNeedsReset=!1,this._colorMaskNeedsReset=!1,this._globalLightColor=s.vec3.clone(v),this._globalLightDir=s.vec3.clone(d)}return n(t,[{key:"createRenderBuffer",value:function(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:h.STATIC_DRAW,n=this._gl,i=n.createBuffer();if(e instanceof Promise){var o=new y(t,r,e.then(function(e){return n.bindBuffer(t,i),n.bufferData(t,e,r),o._length=e.byteLength,i}));return o}return n.bindBuffer(t,i),n.bufferData(t,e,r),new y(t,r,i,e.byteLength)}},{key:"updateRenderBuffer",value:function(t,e){var r=this,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;if(t._buffer){var i=this._gl;i.bindBuffer(t._target,t._buffer),0==n&&t._length==e.byteLength?i.bufferData(t._target,e,t._usage):i.bufferSubData(t._target,n,e)}else t.waitForComplete().then(function(t){r.updateRenderBuffer(t,e,n)})}},{key:"createRenderPrimitive",value:function(t,e){var r=new M(t),n=this._getMaterialProgram(e,r),i=new R(this,e,n);return r.setRenderMaterial(i),this._renderPrimitives[i._renderOrder]||(this._renderPrimitives[i._renderOrder]=[]),this._renderPrimitives[i._renderOrder].push(r),r}},{key:"createMesh",value:function(t,e){var r=new o.Node;return r.addRenderPrimitive(this.createRenderPrimitive(t,e)),r}},{key:"drawViews",value:function(t,e){if(e){var r=this._gl;if(this._frameId++,e.markActive(this._frameId),1==t.length&&t[0].viewport){var n=t[0].viewport;this._gl.viewport(n.x,n.y,n.width,n.height)}for(var i=0;i<t.length;++i){s.mat4.invert(T,t[i].viewMatrix),this._cameraPositions.length<=i&&this._cameraPositions.push(s.vec3.create());var o=this._cameraPositions[i];s.vec3.set(o,0,0,0),s.vec3.transformMat4(o,o,T)}var a=!0,u=!1,c=void 0;try{for(var f,l=this._renderPrimitives[Symbol.iterator]();!(a=(f=l.next()).done);a=!0){var h=f.value;h&&h.length&&this._drawRenderPrimitiveSet(t,h)}}catch(t){u=!0,c=t}finally{try{!a&&l.return&&l.return()}finally{if(u)throw c}}this._vaoExt&&this._vaoExt.bindVertexArrayOES(null),this._depthMaskNeedsReset&&r.depthMask(!0),this._colorMaskNeedsReset&&r.colorMask(!0,!0,!0,!0)}}},{key:"_drawRenderPrimitiveSet",value:function(t,e){var r=this._gl,n=null,i=null,o=0,a=!0,u=!1,s=void 0;try{for(var c,f=e[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){var l=c.value;if(l._activeFrameId==this._frameId){n!=l._material._program&&((n=l._material._program).use(),n.uniform.LIGHT_DIRECTION&&r.uniform3fv(n.uniform.LIGHT_DIRECTION,this._globalLightDir),n.uniform.LIGHT_COLOR&&r.uniform3fv(n.uniform.LIGHT_COLOR,this._globalLightColor),1==t.length&&(r.uniformMatrix4fv(n.uniform.PROJECTION_MATRIX,!1,t[0].projectionMatrix),r.uniformMatrix4fv(n.uniform.VIEW_MATRIX,!1,t[0].viewMatrix),r.uniform3fv(n.uniform.CAMERA_POSITION,this._cameraPositions[0]),r.uniform1i(n.uniform.EYE_INDEX,t[0].eyeIndex))),i!=l._material&&(this._bindMaterialState(l._material,i),l._material.bind(r,n,i),i=l._material),this._vaoExt?l._vao?this._vaoExt.bindVertexArrayOES(l._vao):(l._vao=this._vaoExt.createVertexArrayOES(),this._vaoExt.bindVertexArrayOES(l._vao),this._bindPrimitive(l)):(this._bindPrimitive(l,o),o=l._attributeMask);for(var h=0;h<t.length;++h){var d=t[h];if(t.length>1){if(d.viewport){var v=d.viewport;r.viewport(v.x,v.y,v.width,v.height)}r.uniformMatrix4fv(n.uniform.PROJECTION_MATRIX,!1,d.projectionMatrix),r.uniformMatrix4fv(n.uniform.VIEW_MATRIX,!1,d.viewMatrix),r.uniform3fv(n.uniform.CAMERA_POSITION,this._cameraPositions[h]),r.uniform1i(n.uniform.EYE_INDEX,d.eyeIndex)}var _=!0,m=!1,p=void 0;try{for(var y,b=l._instances[Symbol.iterator]();!(_=(y=b.next()).done);_=!0){var g=y.value;g._activeFrameId==this._frameId&&(r.uniformMatrix4fv(n.uniform.MODEL_MATRIX,!1,g.worldMatrix),l._indexBuffer?r.drawElements(l._mode,l._elementCount,l._indexType,l._indexByteOffset):r.drawArrays(l._mode,0,l._elementCount))}}catch(t){m=!0,p=t}finally{try{!_&&b.return&&b.return()}finally{if(m)throw p}}}}}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}}},{key:"_getRenderTexture",value:function(t){var e=this;if(!t)return null;var r=t.textureKey;if(!r)throw new Error("Texure does not have a valid key");if(r in this._textureCache)return this._textureCache[r];var n=this._gl,i=n.createTexture(),o=new x(i);return this._textureCache[r]=o,t instanceof u.DataTexture?(n.bindTexture(n.TEXTURE_2D,i),n.texImage2D(n.TEXTURE_2D,0,t.format,t.width,t.height,0,t.format,t._type,t._data),this._setSamplerParameters(t),o._complete=!0):t.waitForComplete().then(function(){n.bindTexture(n.TEXTURE_2D,i),n.texImage2D(n.TEXTURE_2D,0,t.format,t.format,n.UNSIGNED_BYTE,t.source),e._setSamplerParameters(t),o._complete=!0,t instanceof u.VideoTexture&&t._video.addEventListener("playing",function(){o._activeCallback=function(){t._video.paused||t._video.waiting||(n.bindTexture(n.TEXTURE_2D,i),n.texImage2D(n.TEXTURE_2D,0,t.format,t.format,n.UNSIGNED_BYTE,t.source))}})}),o}},{key:"_setSamplerParameters",value:function(t){var e=this._gl,r=t.sampler,n=m(t.width)&&m(t.height),i=n&&t.mipmap;i&&e.generateMipmap(e.TEXTURE_2D);var o=r.minFilter||(i?e.LINEAR_MIPMAP_LINEAR:e.LINEAR),a=r.wrapS||(n?e.REPEAT:e.CLAMP_TO_EDGE),u=r.wrapT||(n?e.REPEAT:e.CLAMP_TO_EDGE);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,r.magFilter||e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,o),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,a),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,u)}},{key:"_getProgramKey",value:function(t,e){var r=t+":";for(var n in e)r+=n+"="+e[n]+",";return r}},{key:"_getMaterialProgram",value:function(t,e){var r=this,n=t.materialName,i=t.vertexSource,o=t.fragmentSource;if(null==n)throw new Error("Material does not have a name");if(null==i)throw new Error('Material "'+n+'" does not have a vertex source');if(null==o)throw new Error('Material "'+n+'" does not have a fragment source');var u=t.getProgramDefines(e),s=this._getProgramKey(n,u);if(s in this._programCache)return this._programCache[s];var c=i;c+="\nuniform mat4 PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX;\n\nvoid main() {\n gl_Position = vertex_main(PROJECTION_MATRIX, VIEW_MATRIX, MODEL_MATRIX);\n}\n";var l=(o.match(_)?"":"precision "+this._defaultFragPrecision+" float;\n")+o;l+="\nvoid main() {\n gl_FragColor = fragment_main();\n}\n";var h=new a.Program(this._gl,c,l,f,u);return this._programCache[s]=h,h.onNextUse(function(e){for(var n=0;n<t._samplers.length;++n){var i=t._samplers[n],o=e.uniform[i._uniformName];o&&r._gl.uniform1i(o,n)}}),h}},{key:"_bindPrimitive",value:function(t,e){var r=this._gl;if(e!=t._attributeMask)for(var n in f)t._attributeMask&l[n]?r.enableVertexAttribArray(f[n]):r.disableVertexAttribArray(f[n]);var i=!0,o=!1,a=void 0;try{for(var u,s=t._attributeBuffers[Symbol.iterator]();!(i=(u=s.next()).done);i=!0){var c=u.value;r.bindBuffer(r.ARRAY_BUFFER,c._buffer._buffer);var h=!0,d=!1,v=void 0;try{for(var _,m=c._attributes[Symbol.iterator]();!(h=(_=m.next()).done);h=!0){var p=_.value;r.vertexAttribPointer(p._attrib_index,p._componentCount,p._componentType,p._normalized,p._stride,p._byteOffset)}}catch(t){d=!0,v=t}finally{try{!h&&m.return&&m.return()}finally{if(d)throw v}}}}catch(t){o=!0,a=t}finally{try{!i&&s.return&&s.return()}finally{if(o)throw a}}t._indexBuffer?r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,t._indexBuffer._buffer):r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,null)}},{key:"_bindMaterialState",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=this._gl,n=t._state,o=e?e._state:~n;if(n!=o){if(t._capsDiff(o)){E(r,r.CULL_FACE,i.CAP.CULL_FACE,o,n),E(r,r.BLEND,i.CAP.BLEND,o,n),E(r,r.DEPTH_TEST,i.CAP.DEPTH_TEST,o,n),E(r,r.STENCIL_TEST,i.CAP.STENCIL_TEST,o,n);var a=(n&i.CAP.COLOR_MASK)-(o&i.CAP.COLOR_MASK);if(a){var u=a>1;this._colorMaskNeedsReset=!u,r.colorMask(u,u,u,u)}var s=(n&i.CAP.DEPTH_MASK)-(o&i.CAP.DEPTH_MASK);s&&(this._depthMaskNeedsReset=!(s>1),r.depthMask(s>1));var c=(n&i.CAP.STENCIL_MASK)-(o&i.CAP.STENCIL_MASK);c&&r.stencilMask(c>1)}t._blendDiff(o)&&r.blendFunc(t.blendFuncSrc,t.blendFuncDst),t._depthFuncDiff(o)&&r.depthFunc(t.depthFunc)}}},{key:"gl",get:function(){return this._gl}},{key:"globalLightColor",set:function(t){s.vec3.copy(this._globalLightColor,t)},get:function(){return s.vec3.clone(this._globalLightColor)}},{key:"globalLightDir",set:function(t){s.vec3.copy(this._globalLightDir,t)},get:function(){return s.vec3.clone(this._globalLightDir)}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"fromMat4",function(){return o}),r.d(e,"clone",function(){return a}),r.d(e,"copy",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"identity",function(){return f}),r.d(e,"transpose",function(){return l}),r.d(e,"invert",function(){return h}),r.d(e,"adjoint",function(){return d}),r.d(e,"determinant",function(){return v}),r.d(e,"multiply",function(){return _}),r.d(e,"translate",function(){return m}),r.d(e,"rotate",function(){return p}),r.d(e,"scale",function(){return y}),r.d(e,"fromTranslation",function(){return b}),r.d(e,"fromRotation",function(){return g}),r.d(e,"fromScaling",function(){return M}),r.d(e,"fromMat2d",function(){return x}),r.d(e,"fromQuat",function(){return T}),r.d(e,"normalFromMat4",function(){return E}),r.d(e,"projection",function(){return w}),r.d(e,"str",function(){return O}),r.d(e,"frob",function(){return R}),r.d(e,"add",function(){return P}),r.d(e,"subtract",function(){return S}),r.d(e,"multiplyScalar",function(){return A}),r.d(e,"multiplyScalarAndAdd",function(){return N}),r.d(e,"exactEquals",function(){return C}),r.d(e,"equals",function(){return I}),r.d(e,"mul",function(){return L}),r.d(e,"sub",function(){return k});var n=r(0);function i(){let t=new n.ARRAY_TYPE(9);return n.ARRAY_TYPE!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function o(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[4],t[4]=e[5],t[5]=e[6],t[6]=e[8],t[7]=e[9],t[8]=e[10],t}function a(t){let e=new n.ARRAY_TYPE(9);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e}function u(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t}function s(t,e,r,i,o,a,u,s,c){let f=new n.ARRAY_TYPE(9);return f[0]=t,f[1]=e,f[2]=r,f[3]=i,f[4]=o,f[5]=a,f[6]=u,f[7]=s,f[8]=c,f}function c(t,e,r,n,i,o,a,u,s,c){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t[6]=u,t[7]=s,t[8]=c,t}function f(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function l(t,e){if(t===e){let r=e[1],n=e[2],i=e[5];t[1]=e[3],t[2]=e[6],t[3]=r,t[5]=e[7],t[6]=n,t[7]=i}else t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8];return t}function h(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=f*a-u*c,h=-f*o+u*s,d=c*o-a*s,v=r*l+n*h+i*d;return v?(v=1/v,t[0]=l*v,t[1]=(-f*n+i*c)*v,t[2]=(u*n-i*a)*v,t[3]=h*v,t[4]=(f*r-i*s)*v,t[5]=(-u*r+i*o)*v,t[6]=d*v,t[7]=(-c*r+n*s)*v,t[8]=(a*r-n*o)*v,t):null}function d(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8];return t[0]=a*f-u*c,t[1]=i*c-n*f,t[2]=n*u-i*a,t[3]=u*s-o*f,t[4]=r*f-i*s,t[5]=i*o-r*u,t[6]=o*c-a*s,t[7]=n*s-r*c,t[8]=r*a-n*o,t}function v(t){let e=t[0],r=t[1],n=t[2],i=t[3],o=t[4],a=t[5],u=t[6],s=t[7],c=t[8];return e*(c*o-a*s)+r*(-c*i+a*u)+n*(s*i-o*u)}function _(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=r[0],d=r[1],v=r[2],_=r[3],m=r[4],p=r[5],y=r[6],b=r[7],g=r[8];return t[0]=h*n+d*a+v*c,t[1]=h*i+d*u+v*f,t[2]=h*o+d*s+v*l,t[3]=_*n+m*a+p*c,t[4]=_*i+m*u+p*f,t[5]=_*o+m*s+p*l,t[6]=y*n+b*a+g*c,t[7]=y*i+b*u+g*f,t[8]=y*o+b*s+g*l,t}function m(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=r[0],d=r[1];return t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=u,t[5]=s,t[6]=h*n+d*a+c,t[7]=h*i+d*u+f,t[8]=h*o+d*s+l,t}function p(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=e[6],f=e[7],l=e[8],h=Math.sin(r),d=Math.cos(r);return t[0]=d*n+h*a,t[1]=d*i+h*u,t[2]=d*o+h*s,t[3]=d*a-h*n,t[4]=d*u-h*i,t[5]=d*s-h*o,t[6]=c,t[7]=f,t[8]=l,t}function y(t,e,r){let n=r[0],i=r[1];return t[0]=n*e[0],t[1]=n*e[1],t[2]=n*e[2],t[3]=i*e[3],t[4]=i*e[4],t[5]=i*e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t}function b(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=e[0],t[7]=e[1],t[8]=1,t}function g(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=0,t[3]=-r,t[4]=n,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function M(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=0,t[4]=e[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function x(t,e){return t[0]=e[0],t[1]=e[1],t[2]=0,t[3]=e[2],t[4]=e[3],t[5]=0,t[6]=e[4],t[7]=e[5],t[8]=1,t}function T(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r+r,u=n+n,s=i+i,c=r*a,f=n*a,l=n*u,h=i*a,d=i*u,v=i*s,_=o*a,m=o*u,p=o*s;return t[0]=1-l-v,t[3]=f-p,t[6]=h+m,t[1]=f+p,t[4]=1-c-v,t[7]=d-_,t[2]=h-m,t[5]=d+_,t[8]=1-c-l,t}function E(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=e[6],c=e[7],f=e[8],l=e[9],h=e[10],d=e[11],v=e[12],_=e[13],m=e[14],p=e[15],y=r*u-n*a,b=r*s-i*a,g=r*c-o*a,M=n*s-i*u,x=n*c-o*u,T=i*c-o*s,E=f*_-l*v,w=f*m-h*v,O=f*p-d*v,R=l*m-h*_,P=l*p-d*_,S=h*p-d*m,A=y*S-b*P+g*R+M*O-x*w+T*E;return A?(A=1/A,t[0]=(u*S-s*P+c*R)*A,t[1]=(s*O-a*S-c*w)*A,t[2]=(a*P-u*O+c*E)*A,t[3]=(i*P-n*S-o*R)*A,t[4]=(r*S-i*O+o*w)*A,t[5]=(n*O-r*P-o*E)*A,t[6]=(_*T-m*x+p*M)*A,t[7]=(m*g-v*T-p*b)*A,t[8]=(v*x-_*g+p*y)*A,t):null}function w(t,e,r){return t[0]=2/e,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/r,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t}function O(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"}function R(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+Math.pow(t[6],2)+Math.pow(t[7],2)+Math.pow(t[8],2))}function P(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t[6]=e[6]+r[6],t[7]=e[7]+r[7],t[8]=e[8]+r[8],t}function S(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t[4]=e[4]-r[4],t[5]=e[5]-r[5],t[6]=e[6]-r[6],t[7]=e[7]-r[7],t[8]=e[8]-r[8],t}function A(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t[6]=e[6]*r,t[7]=e[7]*r,t[8]=e[8]*r,t}function N(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t[4]=e[4]+r[4]*n,t[5]=e[5]+r[5]*n,t[6]=e[6]+r[6]*n,t[7]=e[7]+r[7]*n,t[8]=e[8]+r[8]*n,t}function C(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]&&t[6]===e[6]&&t[7]===e[7]&&t[8]===e[8]}function I(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=t[6],f=t[7],l=t[8],h=e[0],d=e[1],v=e[2],_=e[3],m=e[4],p=e[5],y=e[6],b=e[7],g=e[8];return Math.abs(r-h)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(h))&&Math.abs(i-d)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(d))&&Math.abs(o-v)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(v))&&Math.abs(a-_)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(_))&&Math.abs(u-m)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(m))&&Math.abs(s-p)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(p))&&Math.abs(c-y)<=n.EPSILON*Math.max(1,Math.abs(c),Math.abs(y))&&Math.abs(f-b)<=n.EPSILON*Math.max(1,Math.abs(f),Math.abs(b))&&Math.abs(l-g)<=n.EPSILON*Math.max(1,Math.abs(l),Math.abs(g))}const L=_,k=S},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.BoxBuilder=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(9);e.BoxBuilder=function(t){function e(){return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,i.GeometryBuilderBase),n(e,[{key:"pushBox",value:function(t,e){var r=this.primitiveStream,n=.5*(e[0]-t[0]),i=.5*(e[1]-t[1]),o=.5*(e[2]-t[2]),a=t[0]+n,u=t[1]+i,s=t[2]+o;r.startGeometry();var c=r.nextVertexIndex;r.pushTriangle(c,c+1,c+2),r.pushTriangle(c,c+2,c+3),r.pushVertex(-n+a,-i+u,-o+s,0,1,0,-1,0),r.pushVertex(+n+a,-i+u,-o+s,1,1,0,-1,0),r.pushVertex(+n+a,-i+u,+o+s,1,0,0,-1,0),r.pushVertex(-n+a,-i+u,+o+s,0,0,0,-1,0),c=r.nextVertexIndex,r.pushTriangle(c,c+2,c+1),r.pushTriangle(c,c+3,c+2),r.pushVertex(-n+a,+i+u,-o+s,0,0,0,1,0),r.pushVertex(+n+a,+i+u,-o+s,1,0,0,1,0),r.pushVertex(+n+a,+i+u,+o+s,1,1,0,1,0),r.pushVertex(-n+a,+i+u,+o+s,0,1,0,1,0),c=r.nextVertexIndex,r.pushTriangle(c,c+2,c+1),r.pushTriangle(c,c+3,c+2),r.pushVertex(-n+a,-i+u,-o+s,0,1,-1,0,0),r.pushVertex(-n+a,+i+u,-o+s,0,0,-1,0,0),r.pushVertex(-n+a,+i+u,+o+s,1,0,-1,0,0),r.pushVertex(-n+a,-i+u,+o+s,1,1,-1,0,0),c=r.nextVertexIndex,r.pushTriangle(c,c+1,c+2),r.pushTriangle(c,c+2,c+3),r.pushVertex(+n+a,-i+u,-o+s,1,1,1,0,0),r.pushVertex(+n+a,+i+u,-o+s,1,0,1,0,0),r.pushVertex(+n+a,+i+u,+o+s,0,0,1,0,0),r.pushVertex(+n+a,-i+u,+o+s,0,1,1,0,0),c=r.nextVertexIndex,r.pushTriangle(c,c+2,c+1),r.pushTriangle(c,c+3,c+2),r.pushVertex(-n+a,-i+u,-o+s,1,1,0,0,-1),r.pushVertex(+n+a,-i+u,-o+s,0,1,0,0,-1),r.pushVertex(+n+a,+i+u,-o+s,0,0,0,0,-1),r.pushVertex(-n+a,+i+u,-o+s,1,0,0,0,-1),c=r.nextVertexIndex,r.pushTriangle(c,c+1,c+2),r.pushTriangle(c,c+2,c+3),r.pushVertex(-n+a,-i+u,+o+s,0,1,0,0,1),r.pushVertex(+n+a,-i+u,+o+s,1,1,0,0,1),r.pushVertex(+n+a,+i+u,+o+s,1,0,0,0,1),r.pushVertex(-n+a,+i+u,+o+s,0,0,0,0,1),r.endGeometry()}},{key:"pushCube",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[0,0,0],e=.5*(arguments.length>1&&void 0!==arguments[1]?arguments[1]:1);this.pushBox([t[0]-e,t[1]-e,t[2]-e],[t[0]+e,t[1]+e,t[2]+e])}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.PbrMaterial=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(11);e.PbrMaterial=function(t){function e(){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e);var t=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.baseColor=t.defineSampler("baseColorTex"),t.metallicRoughness=t.defineSampler("metallicRoughnessTex"),t.normal=t.defineSampler("normalTex"),t.occlusion=t.defineSampler("occlusionTex"),t.emissive=t.defineSampler("emissiveTex"),t.baseColorFactor=t.defineUniform("baseColorFactor",[1,1,1,1]),t.metallicRoughnessFactor=t.defineUniform("metallicRoughnessFactor",[1,1]),t.occlusionStrength=t.defineUniform("occlusionStrength",1),t.emissiveFactor=t.defineUniform("emissiveFactor",[0,0,0]),t}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,i.Material),n(e,[{key:"getProgramDefines",value:function(t){var e={};return t._attributeMask&o.ATTRIB_MASK.COLOR_0&&(e.USE_VERTEX_COLOR=1),t._attributeMask&o.ATTRIB_MASK.TEXCOORD_0&&(this.baseColor.texture&&(e.USE_BASE_COLOR_MAP=1),this.normal.texture&&t._attributeMask&o.ATTRIB_MASK.TANGENT&&(e.USE_NORMAL_MAP=1),this.metallicRoughness.texture&&(e.USE_METAL_ROUGH_MAP=1),this.occlusion.texture&&(e.USE_OCCLUSION=1),this.emissive.texture&&(e.USE_EMISSIVE_TEXTURE=1)),this.metallicRoughness.texture&&t._attributeMask&o.ATTRIB_MASK.TEXCOORD_0||1!=this.metallicRoughnessFactor.value[1]||(e.FULLY_ROUGH=1),e}},{key:"materialName",get:function(){return"PBR"}},{key:"vertexSource",get:function(){return"\nattribute vec3 POSITION, NORMAL;\nattribute vec2 TEXCOORD_0, TEXCOORD_1;\n\nuniform vec3 CAMERA_POSITION;\nuniform vec3 LIGHT_DIRECTION;\n\nvarying vec3 vLight; // Vector from vertex to light.\nvarying vec3 vView; // Vector from vertex to camera.\nvarying vec2 vTex;\n\n#ifdef USE_NORMAL_MAP\nattribute vec4 TANGENT;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_VERTEX_COLOR\nattribute vec4 COLOR_0;\nvarying vec4 vCol;\n#endif\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 n = normalize(vec3(model * vec4(NORMAL, 0.0)));\n#ifdef USE_NORMAL_MAP\n vec3 t = normalize(vec3(model * vec4(TANGENT.xyz, 0.0)));\n vec3 b = cross(n, t) * TANGENT.w;\n vTBN = mat3(t, b, n);\n#else\n vNorm = n;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n vCol = COLOR_0;\n#endif\n\n vTex = TEXCOORD_0;\n vec4 mPos = model * vec4(POSITION, 1.0);\n vLight = -LIGHT_DIRECTION;\n vView = CAMERA_POSITION - mPos.xyz;\n return proj * view * mPos;\n}"}},{key:"fragmentSource",get:function(){return"\n#define M_PI 3.14159265\n\nuniform vec4 baseColorFactor;\n#ifdef USE_BASE_COLOR_MAP\nuniform sampler2D baseColorTex;\n#endif\n\nvarying vec3 vLight;\nvarying vec3 vView;\nvarying vec2 vTex;\n\n#ifdef USE_VERTEX_COLOR\nvarying vec4 vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\nuniform sampler2D normalTex;\nvarying mat3 vTBN;\n#else\nvarying vec3 vNorm;\n#endif\n\n#ifdef USE_METAL_ROUGH_MAP\nuniform sampler2D metallicRoughnessTex;\n#endif\nuniform vec2 metallicRoughnessFactor;\n\n#ifdef USE_OCCLUSION\nuniform sampler2D occlusionTex;\nuniform float occlusionStrength;\n#endif\n\n#ifdef USE_EMISSIVE_TEXTURE\nuniform sampler2D emissiveTex;\n#endif\nuniform vec3 emissiveFactor;\n\nuniform vec3 LIGHT_COLOR;\n\nconst vec3 dielectricSpec = vec3(0.04);\nconst vec3 black = vec3(0.0);\n\n\nvec3 lambertDiffuse(vec3 cDiff) {\n return cDiff / M_PI;\n}\n\nfloat specD(float a, float nDotH) {\n float aSqr = a * a;\n float f = ((nDotH * nDotH) * (aSqr - 1.0) + 1.0);\n return aSqr / (M_PI * f * f);\n}\n\nfloat specG(float roughness, float nDotL, float nDotV) {\n float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n float gl = nDotL / (nDotL * (1.0 - k) + k);\n float gv = nDotV / (nDotV * (1.0 - k) + k);\n return gl * gv;\n}\n\nvec3 specF(float vDotH, vec3 F0) {\n float exponent = (-5.55473 * vDotH - 6.98316) * vDotH;\n float base = 2.0;\n return F0 + (1.0 - F0) * pow(base, exponent);\n}\n\nvec4 fragment_main() {\n#ifdef USE_BASE_COLOR_MAP\n vec4 baseColor = texture2D(baseColorTex, vTex) * baseColorFactor;\n#else\n vec4 baseColor = baseColorFactor;\n#endif\n\n#ifdef USE_VERTEX_COLOR\n baseColor *= vCol;\n#endif\n\n#ifdef USE_NORMAL_MAP\n vec3 n = texture2D(normalTex, vTex).rgb;\n n = normalize(vTBN * (2.0 * n - 1.0));\n#else\n vec3 n = normalize(vNorm);\n#endif\n\n#ifdef FULLY_ROUGH\n float metallic = 0.0;\n#else\n float metallic = metallicRoughnessFactor.x;\n#endif\n\n float roughness = metallicRoughnessFactor.y;\n\n#ifdef USE_METAL_ROUGH_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessTex, vTex);\n metallic *= metallicRoughness.b;\n roughness *= metallicRoughness.g;\n#endif\n \n vec3 l = normalize(vLight);\n vec3 v = normalize(vView);\n vec3 h = normalize(l+v);\n\n float nDotL = clamp(dot(n, l), 0.001, 1.0);\n float nDotV = abs(dot(n, v)) + 0.001;\n float nDotH = max(dot(n, h), 0.0);\n float vDotH = max(dot(v, h), 0.0);\n\n // From GLTF Spec\n vec3 cDiff = mix(baseColor.rgb * (1.0 - dielectricSpec.r), black, metallic); // Diffuse color\n vec3 F0 = mix(dielectricSpec, baseColor.rgb, metallic); // Specular color\n float a = roughness * roughness;\n\n#ifdef FULLY_ROUGH\n vec3 specular = F0 * 0.45;\n#else\n vec3 F = specF(vDotH, F0);\n float D = specD(a, nDotH);\n float G = specG(roughness, nDotL, nDotV);\n vec3 specular = (D * F * G) / (4.0 * nDotL * nDotV);\n#endif\n float halfLambert = dot(n, l) * 0.5 + 0.5;\n halfLambert *= halfLambert;\n\n vec3 color = (halfLambert * LIGHT_COLOR * lambertDiffuse(cDiff)) + specular;\n\n#ifdef USE_OCCLUSION\n float occlusion = texture2D(occlusionTex, vTex).r;\n color = mix(color, color * occlusion, occlusionStrength);\n#endif\n \n vec3 emissive = emissiveFactor;\n#ifdef USE_EMISSIVE_TEXTURE\n emissive *= texture2D(emissiveTex, vTex).rgb;\n#endif\n color += emissive;\n\n // gamma correction\n //color = pow(color, vec3(1.0/2.2));\n\n return vec4(color, baseColor.a);\n}"}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=r(2);Object.defineProperty(e,"Node",{enumerable:!0,get:function(){return n.Node}});var i=r(11);Object.defineProperty(e,"Renderer",{enumerable:!0,get:function(){return i.Renderer}}),Object.defineProperty(e,"createWebGLContext",{enumerable:!0,get:function(){return i.createWebGLContext}});var o=r(8);Object.defineProperty(e,"UrlTexture",{enumerable:!0,get:function(){return o.UrlTexture}});var a=r(9);Object.defineProperty(e,"PrimitiveStream",{enumerable:!0,get:function(){return a.PrimitiveStream}});var u=r(13);Object.defineProperty(e,"BoxBuilder",{enumerable:!0,get:function(){return u.BoxBuilder}});var s=r(14);Object.defineProperty(e,"PbrMaterial",{enumerable:!0,get:function(){return s.PbrMaterial}});var c=r(6);Object.defineProperty(e,"mat4",{enumerable:!0,get:function(){return c.mat4}}),Object.defineProperty(e,"mat3",{enumerable:!0,get:function(){return c.mat3}}),Object.defineProperty(e,"vec3",{enumerable:!0,get:function(){return c.vec3}}),Object.defineProperty(e,"vec4",{enumerable:!0,get:function(){return c.vec4}}),Object.defineProperty(e,"quat",{enumerable:!0,get:function(){return c.quat}});var f=r(22);Object.defineProperty(e,"BoundsRenderer",{enumerable:!0,get:function(){return f.BoundsRenderer}});var l=r(23);Object.defineProperty(e,"ButtonNode",{enumerable:!0,get:function(){return l.ButtonNode}});var h=r(24);Object.defineProperty(e,"DropShadowNode",{enumerable:!0,get:function(){return h.DropShadowNode}});var d=r(25);Object.defineProperty(e,"CubeSeaNode",{enumerable:!0,get:function(){return d.CubeSeaNode}});var v=r(26);Object.defineProperty(e,"Gltf2Node",{enumerable:!0,get:function(){return v.Gltf2Node}});var _=r(28);Object.defineProperty(e,"SkyboxNode",{enumerable:!0,get:function(){return _.SkyboxNode}});var m=r(29);Object.defineProperty(e,"VideoNode",{enumerable:!0,get:function(){return m.VideoNode}});var p=r(30);Object.defineProperty(e,"WebXRView",{enumerable:!0,get:function(){return p.WebXRView}}),Object.defineProperty(e,"Scene",{enumerable:!0,get:function(){return p.Scene}});var y=r(34);Object.defineProperty(e,"FallbackHelper",{enumerable:!0,get:function(){return y.FallbackHelper}});var b=r(35);Object.defineProperty(e,"QueryArgs",{enumerable:!0,get:function(){return b.QueryArgs}})},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Ray=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(6);var o=i.mat3.create();e.Ray=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.origin=i.vec3.create(),this._dir=i.vec3.create(),this._dir[2]=-1,e&&(i.vec3.transformMat4(this.origin,this.origin,e),i.mat3.fromMat4(o,e),i.vec3.transformMat3(this._dir,this._dir,o)),this.dir=this._dir}return n(t,[{key:"intersectsAABB",value:function(t,e){var r=this,n=[t,e],o=(n[r.sign[0]][0]-r.origin[0])*r.inv_dir[0],a=(n[1-r.sign[0]][0]-r.origin[0])*r.inv_dir[0],u=(n[r.sign[1]][1]-r.origin[1])*r.inv_dir[1],s=(n[1-r.sign[1]][1]-r.origin[1])*r.inv_dir[1];if(o>s||u>a)return null;u>o&&(o=u),s<a&&(a=s);var c=(n[r.sign[2]][2]-r.origin[2])*r.inv_dir[2],f=(n[1-r.sign[2]][2]-r.origin[2])*r.inv_dir[2];if(o>f||c>a)return null;c>o&&(o=c),f<a&&(a=f);var l=-1;if(o>0&&a>0)l=Math.min(o,a);else if(o>0)l=o;else{if(!(a>0))return null;l=a}l-=.02;var h=i.vec3.clone(this._dir);return i.vec3.scale(h,h,l),i.vec3.add(h,h,this.origin),h}},{key:"dir",get:function(){return this._dir},set:function(t){this._dir=i.vec3.copy(this._dir,t),i.vec3.normalize(this._dir,this._dir),this.inv_dir=i.vec3.fromValues(1/this._dir[0],1/this._dir[1],1/this._dir[2]),this.sign=[this.inv_dir[0]<0?1:0,this.inv_dir[1]<0?1:0,this.inv_dir[2]<0?1:0]}}]),t}()},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"copy",function(){return a}),r.d(e,"identity",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"transpose",function(){return f}),r.d(e,"invert",function(){return l}),r.d(e,"adjoint",function(){return h}),r.d(e,"determinant",function(){return d}),r.d(e,"multiply",function(){return v}),r.d(e,"rotate",function(){return _}),r.d(e,"scale",function(){return m}),r.d(e,"fromRotation",function(){return p}),r.d(e,"fromScaling",function(){return y}),r.d(e,"str",function(){return b}),r.d(e,"frob",function(){return g}),r.d(e,"LDU",function(){return M}),r.d(e,"add",function(){return x}),r.d(e,"subtract",function(){return T}),r.d(e,"exactEquals",function(){return E}),r.d(e,"equals",function(){return w}),r.d(e,"multiplyScalar",function(){return O}),r.d(e,"multiplyScalarAndAdd",function(){return R}),r.d(e,"mul",function(){return P}),r.d(e,"sub",function(){return S});var n=r(0);function i(){let t=new n.ARRAY_TYPE(4);return n.ARRAY_TYPE!=Float32Array&&(t[1]=0,t[2]=0),t[0]=1,t[3]=1,t}function o(t){let e=new n.ARRAY_TYPE(4);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function a(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t}function u(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t}function s(t,e,r,i){let o=new n.ARRAY_TYPE(4);return o[0]=t,o[1]=e,o[2]=r,o[3]=i,o}function c(t,e,r,n,i){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t}function f(t,e){if(t===e){let r=e[1];t[1]=e[2],t[2]=r}else t[0]=e[0],t[1]=e[2],t[2]=e[1],t[3]=e[3];return t}function l(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=r*o-i*n;return a?(a=1/a,t[0]=o*a,t[1]=-n*a,t[2]=-i*a,t[3]=r*a,t):null}function h(t,e){let r=e[0];return t[0]=e[3],t[1]=-e[1],t[2]=-e[2],t[3]=r,t}function d(t){return t[0]*t[3]-t[2]*t[1]}function v(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1],c=r[2],f=r[3];return t[0]=n*u+o*s,t[1]=i*u+a*s,t[2]=n*c+o*f,t[3]=i*c+a*f,t}function _(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=Math.sin(r),s=Math.cos(r);return t[0]=n*s+o*u,t[1]=i*s+a*u,t[2]=n*-u+o*s,t[3]=i*-u+a*s,t}function m(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1];return t[0]=n*u,t[1]=i*u,t[2]=o*s,t[3]=a*s,t}function p(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=-r,t[3]=n,t}function y(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=e[1],t}function b(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}function g(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2))}function M(t,e,r,n){return t[2]=n[2]/n[0],r[0]=n[0],r[1]=n[1],r[3]=n[3]-t[2]*r[1],[t,e,r]}function x(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t}function T(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t}function E(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]}function w(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=e[0],s=e[1],c=e[2],f=e[3];return Math.abs(r-u)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(u))&&Math.abs(i-s)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(s))&&Math.abs(o-c)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(c))&&Math.abs(a-f)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(f))}function O(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t}function R(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t}const P=v,S=T},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"copy",function(){return a}),r.d(e,"identity",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"set",function(){return c}),r.d(e,"invert",function(){return f}),r.d(e,"determinant",function(){return l}),r.d(e,"multiply",function(){return h}),r.d(e,"rotate",function(){return d}),r.d(e,"scale",function(){return v}),r.d(e,"translate",function(){return _}),r.d(e,"fromRotation",function(){return m}),r.d(e,"fromScaling",function(){return p}),r.d(e,"fromTranslation",function(){return y}),r.d(e,"str",function(){return b}),r.d(e,"frob",function(){return g}),r.d(e,"add",function(){return M}),r.d(e,"subtract",function(){return x}),r.d(e,"multiplyScalar",function(){return T}),r.d(e,"multiplyScalarAndAdd",function(){return E}),r.d(e,"exactEquals",function(){return w}),r.d(e,"equals",function(){return O}),r.d(e,"mul",function(){return R}),r.d(e,"sub",function(){return P});var n=r(0);function i(){let t=new n.ARRAY_TYPE(6);return n.ARRAY_TYPE!=Float32Array&&(t[1]=0,t[2]=0,t[4]=0,t[5]=0),t[0]=1,t[3]=1,t}function o(t){let e=new n.ARRAY_TYPE(6);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e}function a(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t}function u(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t}function s(t,e,r,i,o,a){let u=new n.ARRAY_TYPE(6);return u[0]=t,u[1]=e,u[2]=r,u[3]=i,u[4]=o,u[5]=a,u}function c(t,e,r,n,i,o,a){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t}function f(t,e){let r=e[0],n=e[1],i=e[2],o=e[3],a=e[4],u=e[5],s=r*o-n*i;return s?(s=1/s,t[0]=o*s,t[1]=-n*s,t[2]=-i*s,t[3]=r*s,t[4]=(i*u-o*a)*s,t[5]=(n*a-r*u)*s,t):null}function l(t){return t[0]*t[3]-t[1]*t[2]}function h(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=r[0],f=r[1],l=r[2],h=r[3],d=r[4],v=r[5];return t[0]=n*c+o*f,t[1]=i*c+a*f,t[2]=n*l+o*h,t[3]=i*l+a*h,t[4]=n*d+o*v+u,t[5]=i*d+a*v+s,t}function d(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=Math.sin(r),f=Math.cos(r);return t[0]=n*f+o*c,t[1]=i*f+a*c,t[2]=n*-c+o*f,t[3]=i*-c+a*f,t[4]=u,t[5]=s,t}function v(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=r[0],f=r[1];return t[0]=n*c,t[1]=i*c,t[2]=o*f,t[3]=a*f,t[4]=u,t[5]=s,t}function _(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=e[4],s=e[5],c=r[0],f=r[1];return t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=n*c+o*f+u,t[5]=i*c+a*f+s,t}function m(t,e){let r=Math.sin(e),n=Math.cos(e);return t[0]=n,t[1]=r,t[2]=-r,t[3]=n,t[4]=0,t[5]=0,t}function p(t,e){return t[0]=e[0],t[1]=0,t[2]=0,t[3]=e[1],t[4]=0,t[5]=0,t}function y(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=e[0],t[5]=e[1],t}function b(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"}function g(t){return Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)+Math.pow(t[2],2)+Math.pow(t[3],2)+Math.pow(t[4],2)+Math.pow(t[5],2)+1)}function M(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t}function x(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t[2]=e[2]-r[2],t[3]=e[3]-r[3],t[4]=e[4]-r[4],t[5]=e[5]-r[5],t}function T(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t}function E(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t[2]=e[2]+r[2]*n,t[3]=e[3]+r[3]*n,t[4]=e[4]+r[4]*n,t[5]=e[5]+r[5]*n,t}function w(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]}function O(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=e[0],f=e[1],l=e[2],h=e[3],d=e[4],v=e[5];return Math.abs(r-c)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(c))&&Math.abs(i-f)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(f))&&Math.abs(o-l)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(l))&&Math.abs(a-h)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(h))&&Math.abs(u-d)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(d))&&Math.abs(s-v)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(v))}const R=h,P=x},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return a}),r.d(e,"clone",function(){return u}),r.d(e,"fromValues",function(){return s}),r.d(e,"fromRotationTranslationValues",function(){return c}),r.d(e,"fromRotationTranslation",function(){return f}),r.d(e,"fromTranslation",function(){return l}),r.d(e,"fromRotation",function(){return h}),r.d(e,"fromMat4",function(){return d}),r.d(e,"copy",function(){return v}),r.d(e,"identity",function(){return _}),r.d(e,"set",function(){return m}),r.d(e,"getReal",function(){return p}),r.d(e,"getDual",function(){return y}),r.d(e,"setReal",function(){return b}),r.d(e,"setDual",function(){return g}),r.d(e,"getTranslation",function(){return M}),r.d(e,"translate",function(){return x}),r.d(e,"rotateX",function(){return T}),r.d(e,"rotateY",function(){return E}),r.d(e,"rotateZ",function(){return w}),r.d(e,"rotateByQuatAppend",function(){return O}),r.d(e,"rotateByQuatPrepend",function(){return R}),r.d(e,"rotateAroundAxis",function(){return P}),r.d(e,"add",function(){return S}),r.d(e,"multiply",function(){return A}),r.d(e,"mul",function(){return N}),r.d(e,"scale",function(){return C}),r.d(e,"dot",function(){return I}),r.d(e,"lerp",function(){return L}),r.d(e,"invert",function(){return k}),r.d(e,"conjugate",function(){return F}),r.d(e,"length",function(){return D}),r.d(e,"len",function(){return j}),r.d(e,"squaredLength",function(){return B}),r.d(e,"sqrLen",function(){return U}),r.d(e,"normalize",function(){return V}),r.d(e,"str",function(){return Y}),r.d(e,"exactEquals",function(){return G}),r.d(e,"equals",function(){return q});var n=r(0),i=r(4),o=r(10);function a(){let t=new n.ARRAY_TYPE(8);return n.ARRAY_TYPE!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[4]=0,t[5]=0,t[6]=0,t[7]=0),t[3]=1,t}function u(t){let e=new n.ARRAY_TYPE(8);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e}function s(t,e,r,i,o,a,u,s){let c=new n.ARRAY_TYPE(8);return c[0]=t,c[1]=e,c[2]=r,c[3]=i,c[4]=o,c[5]=a,c[6]=u,c[7]=s,c}function c(t,e,r,i,o,a,u){let s=new n.ARRAY_TYPE(8);s[0]=t,s[1]=e,s[2]=r,s[3]=i;let c=.5*o,f=.5*a,l=.5*u;return s[4]=c*i+f*r-l*e,s[5]=f*i+l*t-c*r,s[6]=l*i+c*e-f*t,s[7]=-c*t-f*e-l*r,s}function f(t,e,r){let n=.5*r[0],i=.5*r[1],o=.5*r[2],a=e[0],u=e[1],s=e[2],c=e[3];return t[0]=a,t[1]=u,t[2]=s,t[3]=c,t[4]=n*c+i*s-o*u,t[5]=i*c+o*a-n*s,t[6]=o*c+n*u-i*a,t[7]=-n*a-i*u-o*s,t}function l(t,e){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=.5*e[0],t[5]=.5*e[1],t[6]=.5*e[2],t[7]=0,t}function h(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=0,t[5]=0,t[6]=0,t[7]=0,t}function d(t,e){let r=i.create();o.getRotation(r,e);let a=new n.ARRAY_TYPE(3);return o.getTranslation(a,e),f(t,r,a),t}function v(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t}function _(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t}function m(t,e,r,n,i,o,a,u,s){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t[6]=u,t[7]=s,t}const p=i.copy;function y(t,e){return t[0]=e[4],t[1]=e[5],t[2]=e[6],t[3]=e[7],t}const b=i.copy;function g(t,e){return t[4]=e[0],t[5]=e[1],t[6]=e[2],t[7]=e[3],t}function M(t,e){let r=e[4],n=e[5],i=e[6],o=e[7],a=-e[0],u=-e[1],s=-e[2],c=e[3];return t[0]=2*(r*c+o*a+n*s-i*u),t[1]=2*(n*c+o*u+i*a-r*s),t[2]=2*(i*c+o*s+r*u-n*a),t}function x(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=.5*r[0],s=.5*r[1],c=.5*r[2],f=e[4],l=e[5],h=e[6],d=e[7];return t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=a*u+i*c-o*s+f,t[5]=a*s+o*u-n*c+l,t[6]=a*c+n*s-i*u+h,t[7]=-n*u-i*s-o*c+d,t}function T(t,e,r){let n=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=s*u+l*n+c*a-f*o,d=c*u+l*o+f*n-s*a,v=f*u+l*a+s*o-c*n,_=l*u-s*n-c*o-f*a;return i.rotateX(t,e,r),n=t[0],o=t[1],a=t[2],u=t[3],t[4]=h*u+_*n+d*a-v*o,t[5]=d*u+_*o+v*n-h*a,t[6]=v*u+_*a+h*o-d*n,t[7]=_*u-h*n-d*o-v*a,t}function E(t,e,r){let n=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=s*u+l*n+c*a-f*o,d=c*u+l*o+f*n-s*a,v=f*u+l*a+s*o-c*n,_=l*u-s*n-c*o-f*a;return i.rotateY(t,e,r),n=t[0],o=t[1],a=t[2],u=t[3],t[4]=h*u+_*n+d*a-v*o,t[5]=d*u+_*o+v*n-h*a,t[6]=v*u+_*a+h*o-d*n,t[7]=_*u-h*n-d*o-v*a,t}function w(t,e,r){let n=-e[0],o=-e[1],a=-e[2],u=e[3],s=e[4],c=e[5],f=e[6],l=e[7],h=s*u+l*n+c*a-f*o,d=c*u+l*o+f*n-s*a,v=f*u+l*a+s*o-c*n,_=l*u-s*n-c*o-f*a;return i.rotateZ(t,e,r),n=t[0],o=t[1],a=t[2],u=t[3],t[4]=h*u+_*n+d*a-v*o,t[5]=d*u+_*o+v*n-h*a,t[6]=v*u+_*a+h*o-d*n,t[7]=_*u-h*n-d*o-v*a,t}function O(t,e,r){let n=r[0],i=r[1],o=r[2],a=r[3],u=e[0],s=e[1],c=e[2],f=e[3];return t[0]=u*a+f*n+s*o-c*i,t[1]=s*a+f*i+c*n-u*o,t[2]=c*a+f*o+u*i-s*n,t[3]=f*a-u*n-s*i-c*o,u=e[4],s=e[5],c=e[6],f=e[7],t[4]=u*a+f*n+s*o-c*i,t[5]=s*a+f*i+c*n-u*o,t[6]=c*a+f*o+u*i-s*n,t[7]=f*a-u*n-s*i-c*o,t}function R(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[0],s=r[1],c=r[2],f=r[3];return t[0]=n*f+a*u+i*c-o*s,t[1]=i*f+a*s+o*u-n*c,t[2]=o*f+a*c+n*s-i*u,t[3]=a*f-n*u-i*s-o*c,u=r[4],s=r[5],c=r[6],f=r[7],t[4]=n*f+a*u+i*c-o*s,t[5]=i*f+a*s+o*u-n*c,t[6]=o*f+a*c+n*s-i*u,t[7]=a*f-n*u-i*s-o*c,t}function P(t,e,r,i){if(Math.abs(i)<n.EPSILON)return v(t,e);let o=Math.sqrt(r[0]*r[0]+r[1]*r[1]+r[2]*r[2]);i*=.5;let a=Math.sin(i),u=a*r[0]/o,s=a*r[1]/o,c=a*r[2]/o,f=Math.cos(i),l=e[0],h=e[1],d=e[2],_=e[3];t[0]=l*f+_*u+h*c-d*s,t[1]=h*f+_*s+d*u-l*c,t[2]=d*f+_*c+l*s-h*u,t[3]=_*f-l*u-h*s-d*c;let m=e[4],p=e[5],y=e[6],b=e[7];return t[4]=m*f+b*u+p*c-y*s,t[5]=p*f+b*s+y*u-m*c,t[6]=y*f+b*c+m*s-p*u,t[7]=b*f-m*u-p*s-y*c,t}function S(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t[2]=e[2]+r[2],t[3]=e[3]+r[3],t[4]=e[4]+r[4],t[5]=e[5]+r[5],t[6]=e[6]+r[6],t[7]=e[7]+r[7],t}function A(t,e,r){let n=e[0],i=e[1],o=e[2],a=e[3],u=r[4],s=r[5],c=r[6],f=r[7],l=e[4],h=e[5],d=e[6],v=e[7],_=r[0],m=r[1],p=r[2],y=r[3];return t[0]=n*y+a*_+i*p-o*m,t[1]=i*y+a*m+o*_-n*p,t[2]=o*y+a*p+n*m-i*_,t[3]=a*y-n*_-i*m-o*p,t[4]=n*f+a*u+i*c-o*s+l*y+v*_+h*p-d*m,t[5]=i*f+a*s+o*u-n*c+h*y+v*m+d*_-l*p,t[6]=o*f+a*c+n*s-i*u+d*y+v*p+l*m-h*_,t[7]=a*f-n*u-i*s-o*c+v*y-l*_-h*m-d*p,t}const N=A;function C(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*r,t[5]=e[5]*r,t[6]=e[6]*r,t[7]=e[7]*r,t}const I=i.dot;function L(t,e,r,n){let i=1-n;return I(e,r)<0&&(n=-n),t[0]=e[0]*i+r[0]*n,t[1]=e[1]*i+r[1]*n,t[2]=e[2]*i+r[2]*n,t[3]=e[3]*i+r[3]*n,t[4]=e[4]*i+r[4]*n,t[5]=e[5]*i+r[5]*n,t[6]=e[6]*i+r[6]*n,t[7]=e[7]*i+r[7]*n,t}function k(t,e){let r=B(e);return t[0]=-e[0]/r,t[1]=-e[1]/r,t[2]=-e[2]/r,t[3]=e[3]/r,t[4]=-e[4]/r,t[5]=-e[5]/r,t[6]=-e[6]/r,t[7]=e[7]/r,t}function F(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=e[3],t[4]=-e[4],t[5]=-e[5],t[6]=-e[6],t[7]=e[7],t}const D=i.length,j=D,B=i.squaredLength,U=B;function V(t,e){let r=B(e);if(r>0){r=Math.sqrt(r);let n=e[0]/r,i=e[1]/r,o=e[2]/r,a=e[3]/r,u=e[4],s=e[5],c=e[6],f=e[7],l=n*u+i*s+o*c+a*f;t[0]=n,t[1]=i,t[2]=o,t[3]=a,t[4]=(u-n*l)/r,t[5]=(s-i*l)/r,t[6]=(c-o*l)/r,t[7]=(f-a*l)/r}return t}function Y(t){return"quat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+")"}function G(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]&&t[4]===e[4]&&t[5]===e[5]&&t[6]===e[6]&&t[7]===e[7]}function q(t,e){let r=t[0],i=t[1],o=t[2],a=t[3],u=t[4],s=t[5],c=t[6],f=t[7],l=e[0],h=e[1],d=e[2],v=e[3],_=e[4],m=e[5],p=e[6],y=e[7];return Math.abs(r-l)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(l))&&Math.abs(i-h)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(h))&&Math.abs(o-d)<=n.EPSILON*Math.max(1,Math.abs(o),Math.abs(d))&&Math.abs(a-v)<=n.EPSILON*Math.max(1,Math.abs(a),Math.abs(v))&&Math.abs(u-_)<=n.EPSILON*Math.max(1,Math.abs(u),Math.abs(_))&&Math.abs(s-m)<=n.EPSILON*Math.max(1,Math.abs(s),Math.abs(m))&&Math.abs(c-p)<=n.EPSILON*Math.max(1,Math.abs(c),Math.abs(p))&&Math.abs(f-y)<=n.EPSILON*Math.max(1,Math.abs(f),Math.abs(y))}},function(t,e,r){"use strict";r.r(e),r.d(e,"create",function(){return i}),r.d(e,"clone",function(){return o}),r.d(e,"fromValues",function(){return a}),r.d(e,"copy",function(){return u}),r.d(e,"set",function(){return s}),r.d(e,"add",function(){return c}),r.d(e,"subtract",function(){return f}),r.d(e,"multiply",function(){return l}),r.d(e,"divide",function(){return h}),r.d(e,"ceil",function(){return d}),r.d(e,"floor",function(){return v}),r.d(e,"min",function(){return _}),r.d(e,"max",function(){return m}),r.d(e,"round",function(){return p}),r.d(e,"scale",function(){return y}),r.d(e,"scaleAndAdd",function(){return b}),r.d(e,"distance",function(){return g}),r.d(e,"squaredDistance",function(){return M}),r.d(e,"length",function(){return x}),r.d(e,"squaredLength",function(){return T}),r.d(e,"negate",function(){return E}),r.d(e,"inverse",function(){return w}),r.d(e,"normalize",function(){return O}),r.d(e,"dot",function(){return R}),r.d(e,"cross",function(){return P}),r.d(e,"lerp",function(){return S}),r.d(e,"random",function(){return A}),r.d(e,"transformMat2",function(){return N}),r.d(e,"transformMat2d",function(){return C}),r.d(e,"transformMat3",function(){return I}),r.d(e,"transformMat4",function(){return L}),r.d(e,"rotate",function(){return k}),r.d(e,"angle",function(){return F}),r.d(e,"str",function(){return D}),r.d(e,"exactEquals",function(){return j}),r.d(e,"equals",function(){return B}),r.d(e,"len",function(){return U}),r.d(e,"sub",function(){return V}),r.d(e,"mul",function(){return Y}),r.d(e,"div",function(){return G}),r.d(e,"dist",function(){return q}),r.d(e,"sqrDist",function(){return H}),r.d(e,"sqrLen",function(){return X}),r.d(e,"forEach",function(){return W});var n=r(0);function i(){let t=new n.ARRAY_TYPE(2);return n.ARRAY_TYPE!=Float32Array&&(t[0]=0,t[1]=0),t}function o(t){let e=new n.ARRAY_TYPE(2);return e[0]=t[0],e[1]=t[1],e}function a(t,e){let r=new n.ARRAY_TYPE(2);return r[0]=t,r[1]=e,r}function u(t,e){return t[0]=e[0],t[1]=e[1],t}function s(t,e,r){return t[0]=e,t[1]=r,t}function c(t,e,r){return t[0]=e[0]+r[0],t[1]=e[1]+r[1],t}function f(t,e,r){return t[0]=e[0]-r[0],t[1]=e[1]-r[1],t}function l(t,e,r){return t[0]=e[0]*r[0],t[1]=e[1]*r[1],t}function h(t,e,r){return t[0]=e[0]/r[0],t[1]=e[1]/r[1],t}function d(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t}function v(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t}function _(t,e,r){return t[0]=Math.min(e[0],r[0]),t[1]=Math.min(e[1],r[1]),t}function m(t,e,r){return t[0]=Math.max(e[0],r[0]),t[1]=Math.max(e[1],r[1]),t}function p(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t}function y(t,e,r){return t[0]=e[0]*r,t[1]=e[1]*r,t}function b(t,e,r,n){return t[0]=e[0]+r[0]*n,t[1]=e[1]+r[1]*n,t}function g(t,e){var r=e[0]-t[0],n=e[1]-t[1];return Math.sqrt(r*r+n*n)}function M(t,e){var r=e[0]-t[0],n=e[1]-t[1];return r*r+n*n}function x(t){var e=t[0],r=t[1];return Math.sqrt(e*e+r*r)}function T(t){var e=t[0],r=t[1];return e*e+r*r}function E(t,e){return t[0]=-e[0],t[1]=-e[1],t}function w(t,e){return t[0]=1/e[0],t[1]=1/e[1],t}function O(t,e){var r=e[0],n=e[1],i=r*r+n*n;return i>0&&(i=1/Math.sqrt(i),t[0]=e[0]*i,t[1]=e[1]*i),t}function R(t,e){return t[0]*e[0]+t[1]*e[1]}function P(t,e,r){var n=e[0]*r[1]-e[1]*r[0];return t[0]=t[1]=0,t[2]=n,t}function S(t,e,r,n){var i=e[0],o=e[1];return t[0]=i+n*(r[0]-i),t[1]=o+n*(r[1]-o),t}function A(t,e){e=e||1;var r=2*n.RANDOM()*Math.PI;return t[0]=Math.cos(r)*e,t[1]=Math.sin(r)*e,t}function N(t,e,r){var n=e[0],i=e[1];return t[0]=r[0]*n+r[2]*i,t[1]=r[1]*n+r[3]*i,t}function C(t,e,r){var n=e[0],i=e[1];return t[0]=r[0]*n+r[2]*i+r[4],t[1]=r[1]*n+r[3]*i+r[5],t}function I(t,e,r){var n=e[0],i=e[1];return t[0]=r[0]*n+r[3]*i+r[6],t[1]=r[1]*n+r[4]*i+r[7],t}function L(t,e,r){let n=e[0],i=e[1];return t[0]=r[0]*n+r[4]*i+r[12],t[1]=r[1]*n+r[5]*i+r[13],t}function k(t,e,r,n){let i=e[0]-r[0],o=e[1]-r[1],a=Math.sin(n),u=Math.cos(n);return t[0]=i*u-o*a+r[0],t[1]=i*a+o*u+r[1],t}function F(t,e){let r=t[0],n=t[1],i=e[0],o=e[1],a=r*r+n*n;a>0&&(a=1/Math.sqrt(a));let u=i*i+o*o;u>0&&(u=1/Math.sqrt(u));let s=(r*i+n*o)*a*u;return s>1?0:s<-1?Math.PI:Math.acos(s)}function D(t){return"vec2("+t[0]+", "+t[1]+")"}function j(t,e){return t[0]===e[0]&&t[1]===e[1]}function B(t,e){let r=t[0],i=t[1],o=e[0],a=e[1];return Math.abs(r-o)<=n.EPSILON*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(i-a)<=n.EPSILON*Math.max(1,Math.abs(i),Math.abs(a))}const U=x,V=f,Y=l,G=h,q=g,H=M,X=T,W=function(){let t=i();return function(e,r,n,i,o,a){let u,s;for(r||(r=2),n||(n=0),s=i?Math.min(i*r+n,e.length):e.length,u=n;u<s;u+=r)t[0]=e[u],t[1]=e[u+1],o(t,t,a),e[u]=t[0],e[u+1]=t[1];return e}}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();e.Program=function(){function t(e,r,n,i,o){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this._gl=e,this.program=e.createProgram(),this.attrib=null,this.uniform=null,this.defines={},this._firstUse=!0,this._nextUseCallbacks=[];var a="";if(o)for(var u in o)this.defines[u]=o[u],a+="#define "+u+" "+o[u]+"\n";if(this._vertShader=e.createShader(e.VERTEX_SHADER),e.attachShader(this.program,this._vertShader),e.shaderSource(this._vertShader,a+r),e.compileShader(this._vertShader),this._fragShader=e.createShader(e.FRAGMENT_SHADER),e.attachShader(this.program,this._fragShader),e.shaderSource(this._fragShader,a+n),e.compileShader(this._fragShader),i)for(var s in this.attrib={},i)e.bindAttribLocation(this.program,i[s],s),this.attrib[s]=i[s];e.linkProgram(this.program)}return n(t,[{key:"onNextUse",value:function(t){this._nextUseCallbacks.push(t)}},{key:"use",value:function(){var t=this._gl;if(this._firstUse){if(this._firstUse=!1,t.getProgramParameter(this.program,t.LINK_STATUS)){if(!this.attrib){this.attrib={};for(var e=t.getProgramParameter(this.program,t.ACTIVE_ATTRIBUTES),r=0;r<e;r++){var n=t.getActiveAttrib(this.program,r);this.attrib[n.name]=t.getAttribLocation(this.program,n.name)}}this.uniform={};for(var i=t.getProgramParameter(this.program,t.ACTIVE_UNIFORMS),o="",a=0;a<i;a++){o=t.getActiveUniform(this.program,a).name.replace("[0]",""),this.uniform[o]=t.getUniformLocation(this.program,o)}}else t.getShaderParameter(this._vertShader,t.COMPILE_STATUS)?t.getShaderParameter(this._fragShader,t.COMPILE_STATUS)?console.error("Program link error: "+t.getProgramInfoLog(this.program)):console.error("Fragment shader compile error: "+t.getShaderInfoLog(this._fragShader)):console.error("Vertex shader compile error: "+t.getShaderInfoLog(this._vertShader)),t.deleteProgram(this.program),this.program=null;t.deleteShader(this._vertShader),t.deleteShader(this._fragShader)}if(t.useProgram(this.program),this._nextUseCallbacks.length){var u=!0,s=!1,c=void 0;try{for(var f,l=this._nextUseCallbacks[Symbol.iterator]();!(u=(f=l.next()).done);u=!0){(0,f.value)(this)}}catch(t){s=!0,c=t}finally{try{!u&&l.return&&l.return()}finally{if(s)throw c}}this._nextUseCallbacks=[]}}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.BoundsRenderer=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7);function u(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function c(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var f=WebGLRenderingContext,l=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.state.blendFuncSrc=f.SRC_ALPHA,t.state.blendFuncDst=f.ONE,t.state.depthTest=!1,t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"BOUNDS_RENDERER"}},{key:"vertexSource",get:function(){return"\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n\n vec4 fragment_main() {\n return vec4(0.0, 1.0, 0.0, 0.3);\n }"}}]),e}();e.BoundsRenderer=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._stageBounds=null,t}return c(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this.stageBounds=this._stageBounds}},{key:"stageBounds",get:function(){return this._stageBounds},set:function(t){if(this._stageBounds&&this.clearRenderPrimitives(),this._stageBounds=t,t&&0!==t.length&&this._renderer){for(var e=[],r=[],n=t.geometry.length,i=0;i<n;i++){var o=t.geometry[i];e.push(o.x,0,o.z),r.push(i,0===i?n-1:i-1,n)}e.push(0,0,0);var u=this._renderer.createRenderBuffer(f.ARRAY_BUFFER,new Float32Array(e)),s=this._renderer.createRenderBuffer(f.ELEMENT_ARRAY_BUFFER,new Uint16Array(r)),c=[new a.PrimitiveAttribute("POSITION",u,3,f.FLOAT,12,0)],h=new a.Primitive(c,r.length);h.setIndexBuffer(s);var d=this._renderer.createRenderPrimitive(h,new l);this.addRenderPrimitive(d)}}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.ButtonNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(9);function u(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function c(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var f=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.defineUniform("hoverAmount",0),t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"BUTTON_MATERIAL"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n\n uniform float hoverAmount;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n float scale = mix(1.0, 1.1, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform float hoverAmount;\n\n const vec4 default_color = vec4(0.75, 0.75, 0.75, 0.85);\n const vec4 hover_color = vec4(0.9, 0.9,\n 0.9, 1);\n\n vec4 fragment_main() {\n return mix(default_color, hover_color, hoverAmount);\n }"}}]),e}(),l=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.defineUniform("hoverAmount",0),t.icon=t.defineSampler("icon"),t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"BUTTON_ICON_MATERIAL"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n uniform float hoverAmount;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n float scale = mix(1.0, 1.1, hoverAmount);\n vec4 pos = vec4(POSITION.x * scale, POSITION.y * scale, POSITION.z * (scale + (hoverAmount * 0.2)), 1.0);\n return proj * view * model * pos;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform sampler2D icon;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(icon, vTexCoord);\n }"}}]),e}();e.ButtonNode=function(t){function e(t,r){u(this,e);var n=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return n.selectable=!0,n._selectHandler=r,n._iconTexture=t,n._hovered=!1,n._hoverT=0,n}return c(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=new a.PrimitiveStream,r=.0025,n=.05,i=n-.025;e.startGeometry();for(var o=0;o<32;++o){var u=o*(2*Math.PI/32),s=.025*Math.cos(u),c=.025*Math.sin(u);switch(Math.floor(o/8)){case 0:s+=i,c+=i;break;case 1:s-=i,c+=i;break;case 2:s-=i,c-=i;break;case 3:s+=i,c-=i}e.pushVertex(s,c,-r,0,0,0,0,1),o>1&&e.pushTriangle(0,o-1,o)}e.endGeometry();var h=e.finishPrimitive(t);this._buttonRenderPrimitive=t.createRenderPrimitive(h,new f),this.addRenderPrimitive(this._buttonRenderPrimitive),n=.035,e.clear(),e.startGeometry(),e.pushVertex(-n,n,r,0,0,0,0,1),e.pushVertex(-n,-n,r,0,1,0,0,1),e.pushVertex(n,-n,r,1,1,0,0,1),e.pushVertex(n,n,r,1,0,0,0,1),e.pushTriangle(0,1,2),e.pushTriangle(0,2,3),e.endGeometry();var d=e.finishPrimitive(t),v=new l;v.icon.texture=this._iconTexture,this._iconRenderPrimitive=t.createRenderPrimitive(d,v),this.addRenderPrimitive(this._iconRenderPrimitive)}},{key:"onHoverStart",value:function(){this._hovered=!0}},{key:"onHoverEnd",value:function(){this._hovered=!1}},{key:"_updateHoverState",value:function(){var t=this._hoverT/200,e=t<.5?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1;this._buttonRenderPrimitive.uniforms.hoverAmount.value=e,this._iconRenderPrimitive.uniforms.hoverAmount.value=e}},{key:"onUpdate",value:function(t,e){this._hovered&&this._hoverT<200?(this._hoverT=Math.min(200,this._hoverT+e),this._updateHoverState()):!this._hovered&&this._hoverT>0&&(this._hoverT=Math.max(0,this._hoverT-e),this._updateHoverState())}},{key:"iconTexture",get:function(){return this._iconTexture},set:function(t){this._iconTexture!=t&&(this._iconTexture=t,this._iconRenderPrimitive.samplers.icon.texture=t)}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.DropShadowNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(9);function u(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function c(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var f=WebGLRenderingContext,l=function(t){function e(){u(this,e);var t=s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.state.blend=!0,t.state.blendFuncSrc=f.ONE,t.state.blendFuncDst=f.ONE_MINUS_SRC_ALPHA,t.state.depthFunc=f.LEQUAL,t.state.depthMask=!1,t}return c(e,i.Material),n(e,[{key:"materialName",get:function(){return"DROP_SHADOW_MATERIAL"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying float vShadow;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vShadow = TEXCOORD_0.x;\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n varying float vShadow;\n\n vec4 fragment_main() {\n return vec4(0.0, 0.0, 0.0, vShadow);\n }"}}]),e}();e.DropShadowNode=function(t){function e(t,r){return u(this,e),s(this,(e.__proto__||Object.getPrototypeOf(e)).call(this))}return c(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=new a.PrimitiveStream;e.startGeometry(),e.pushVertex(0,.01,0,.7);for(var r=2*Math.PI/32,n=void 0,i=0;i<32;++i){n=e.nextVertexIndex;var o=i*r,u=Math.cos(o),s=Math.sin(o);e.pushVertex(.6*u,.01,.6*s,.3),e.pushVertex(1*u,.01,1*s,0),i>0&&(e.pushTriangle(0,n,n-2),e.pushTriangle(n,n+1,n-1),e.pushTriangle(n,n-1,n-2))}e.pushTriangle(0,1,n),e.pushTriangle(1,2,n+1),e.pushTriangle(1,n+1,n),e.endGeometry();var c=e.finishPrimitive(t);this._shadowRenderPrimitive=t.createRenderPrimitive(c,new l),this.addRenderPrimitive(this._shadowRenderPrimitive)}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.CubeSeaNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(8),u=r(13),s=r(6);function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function f(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var h=function(t){function e(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];c(this,e);var r=f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r.heavy=t,r.baseColor=r.defineSampler("baseColor"),r}return l(e,i.Material),n(e,[{key:"materialName",get:function(){return"CUBE_SEA"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n attribute vec3 NORMAL;\n\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n const vec3 lightDir = vec3(0.75, 0.5, 1.0);\n const vec3 ambientColor = vec3(0.5, 0.5, 0.5);\n const vec3 lightColor = vec3(0.75, 0.75, 0.75);\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec3 normalRotated = vec3(model * vec4(NORMAL, 0.0));\n float lightFactor = max(dot(normalize(lightDir), normalRotated), 0.0);\n vLight = ambientColor + (lightColor * lightFactor);\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return this.heavy?"\n precision mediump float;\n\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec2 dimensions = vec2(64, 64);\n float seed = 0.42;\n\n vec2 hash( vec2 p ) {\n p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3)));\n return fract(sin(p)*18.5453);\n }\n\n vec3 hash3( vec2 p ) {\n vec3 q = vec3( dot(p,vec2(127.1,311.7)),\n dot(p,vec2(269.5,183.3)),\n dot(p,vec2(419.2,371.9)) );\n return fract(sin(q)*43758.5453);\n }\n\n float iqnoise( in vec2 x, float u, float v ) {\n vec2 p = floor(x);\n vec2 f = fract(x);\n float k = 1.0+63.0*pow(1.0-v,4.0);\n float va = 0.0;\n float wt = 0.0;\n for( int j=-2; j<=2; j++ )\n for( int i=-2; i<=2; i++ ) {\n vec2 g = vec2( float(i),float(j) );\n vec3 o = hash3( p + g )*vec3(u,u,1.0);\n vec2 r = g - f + o.xy;\n float d = dot(r,r);\n float ww = pow( 1.0-smoothstep(0.0,1.414,sqrt(d)), k );\n va += o.z*ww;\n wt += ww;\n }\n return va/wt;\n }\n\n // return distance, and cell id\n vec2 voronoi( in vec2 x ) {\n vec2 n = floor( x );\n vec2 f = fract( x );\n vec3 m = vec3( 8.0 );\n for( int j=-1; j<=1; j++ )\n for( int i=-1; i<=1; i++ ) {\n vec2 g = vec2( float(i), float(j) );\n vec2 o = hash( n + g );\n vec2 r = g - f + (0.5+0.5*sin(seed+6.2831*o));\n float d = dot( r, r );\n if( d<m.x )\n m = vec3( d, o );\n }\n return vec2( sqrt(m.x), m.y+m.z );\n }\n\n vec4 fragment_main() {\n vec2 uv = ( vTexCoord );\n uv *= vec2( 10., 10. );\n uv += seed;\n vec2 p = 0.5 - 0.5*sin( 0.*vec2(1.01,1.71) );\n\n vec2 c = voronoi( uv );\n vec3 col = vec3( c.y / 2. );\n\n float f = iqnoise( 1. * uv + c.y, p.x, p.y );\n col *= 1.0 + .25 * vec3( f );\n\n return vec4(vLight, 1.0) * texture2D(diffuse, vTexCoord) * vec4( col, 1. );\n }":"\n precision mediump float;\n uniform sampler2D baseColor;\n varying vec2 vTexCoord;\n varying vec3 vLight;\n\n vec4 fragment_main() {\n return vec4(vLight, 1.0) * texture2D(baseColor, vTexCoord);\n }"}}]),e}();e.CubeSeaNode=function(t){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};c(this,e);var r=f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r.heavyGpu=!!t.heavyGpu,r.cubeCount=t.cubeCount||(r.heavyGpu?12:10),r.cubeScale=t.cubeScale||1,r.halfOnly=!!t.halfOnly,r.autoRotate=!!t.autoRotate,r._texture=new a.UrlTexture(t.imageUrl||"media/textures/cube-sea.png"),r._material=new h(r.heavyGpu),r._material.baseColor.texture=r._texture,r._renderPrimitive=null,r}return l(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this._renderPrimitive=null;var e=new u.BoxBuilder;e.pushCube([0,.25,-.8],.1),e.pushCube([.8,.25,0],.1),e.pushCube([0,.25,.8],.1),e.pushCube([-.8,.25,0],.1);var r=e.finishPrimitive(t);return this.heroNode=t.createMesh(r,this._material),this.rebuildCubes(e),this.cubeSeaNode=new o.Node,this.cubeSeaNode.addRenderPrimitive(this._renderPrimitive),this.addNode(this.cubeSeaNode),this.addNode(this.heroNode),this.waitForComplete()}},{key:"rebuildCubes",value:function(t){if(this._renderer){t?t.clear():t=new u.BoxBuilder;for(var e=.4*this.cubeScale,r=.5*this.cubeCount,n=0;n<this.cubeCount;++n)for(var i=0;i<this.cubeCount;++i)for(var o=0;o<this.cubeCount;++o){var a=[n-r,i-r,o-r];this.halfOnly&&a[0]<0||(0==a[0]&&0==a[1]&&0==a[2]||t.pushCube(a,e))}this.cubeCount>12&&(t.indexType=5125);var s=t.finishPrimitive(this._renderer);this._renderPrimitive?this._renderPrimitive.setPrimitive(s):this._renderPrimitive=this._renderer.createRenderPrimitive(s,this._material)}}},{key:"onUpdate",value:function(t,e){this.autoRotate&&s.mat4.fromRotation(this.cubeSeaNode.matrix,t/500,[0,-1,0]),s.mat4.fromRotation(this.heroNode.matrix,t/2e3,[0,1,0])}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Gltf2Node=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(2),o=r(27);var a=new WeakMap;e.Gltf2Node=function(t){function e(t){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e);var r=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._url=t.url,r._promise=null,r._resolver=null,r._rejecter=null,r}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,i.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=this,r=a.get(t);r||(r=new o.Gltf2Loader(t),a.set(t,r)),!this._resolver&&this._promise&&(this._promise=null),this._ensurePromise(),r.loadFromUrl(this._url).then(function(t){e.addNode(t),e._resolver(t.waitForComplete()),e._resolver=null,e._rejecter=null}).catch(function(t){e._rejecter(t),e._resolver=null,e._rejecter=null})}},{key:"_ensurePromise",value:function(){var t=this;return this._promise||(this._promise=new Promise(function(e,r){t._resolver=e,t._rejecter=r})),this._promise}},{key:"waitForComplete",value:function(){return this._ensurePromise()}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Gltf2Loader=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(14),o=r(2),a=r(7),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var c=WebGLRenderingContext,f=1313821514,l=5130562;function h(t){return!!t.match(/^data:/)}function d(t,e){return function(t){var e=new RegExp("^"+window.location.protocol,"i");return!!t.match(e)}(t)||h(t)?t:e+t}function v(t){switch(t){case"SCALAR":return 1;case"VEC2":return 2;case"VEC3":return 3;case"VEC4":return 4;default:return 0}}e.Gltf2Loader=function(){function t(e){s(this,t),this.renderer=e,this._gl=e._gl}return n(t,[{key:"loadFromUrl",value:function(t){var e=this;return fetch(t).then(function(r){var n=t.lastIndexOf("/"),i=0!==n?t.substring(0,n+1):"";if(t.endsWith(".gltf"))return r.json().then(function(t){return e.loadFromJson(t,i)});if(t.endsWith(".glb"))return r.arrayBuffer().then(function(t){return e.loadFromBinary(t,i)});throw new Error("Unrecognized file extension")})}},{key:"loadFromBinary",value:function(t,e){var r=new DataView(t,0,12),n=r.getUint32(0,!0),i=r.getUint32(4,!0),o=r.getUint32(8,!0);if(1179937895!=n)throw new Error("Invalid magic string in binary header.");if(2!=i)throw new Error("Incompatible version in binary header.");for(var a={},u=12;u<o;){var s=new DataView(t,u,8),c=s.getUint32(0,!0);a[s.getUint32(4,!0)]=t.slice(u+8,u+8+c),u+=c+8}if(!a[f])throw new Error("File contained no json chunk.");var h=new TextDecoder("utf-8").decode(a[f]),d=JSON.parse(h);return this.loadFromJson(d,e,a[l])}},{key:"loadFromJson",value:function(t,e,r){if(!t.asset)throw new Error("Missing asset description.");if("2.0"!=t.asset.minVersion&&"2.0"!=t.asset.version)throw new Error("Incompatible asset version.");var n=[];if(r)n[0]=new p({},e,r);else{var s=!0,f=!1,l=void 0;try{for(var h,d=t.buffers[Symbol.iterator]();!(s=(h=d.next()).done);s=!0){var y=h.value;n.push(new p(y,e))}}catch(t){f=!0,l=t}finally{try{!s&&d.return&&d.return()}finally{if(f)throw l}}}var b=[],g=!0,M=!1,x=void 0;try{for(var T,E=t.bufferViews[Symbol.iterator]();!(g=(T=E.next()).done);g=!0){var w=T.value;b.push(new m(w,n))}}catch(t){M=!0,x=t}finally{try{!g&&E.return&&E.return()}finally{if(M)throw x}}var O=[];if(t.images){var R=!0,P=!1,S=void 0;try{for(var A,N=t.images[Symbol.iterator]();!(R=(A=N.next()).done);R=!0){var C=A.value;O.push(new p(C,e))}}catch(t){P=!0,S=t}finally{try{!R&&N.return&&N.return()}finally{if(P)throw S}}}var I=[];if(t.textures){var L=!0,k=!1,F=void 0;try{for(var D,j=t.textures[Symbol.iterator]();!(L=(D=j.next()).done);L=!0){var B=D.value,U=O[B.source].texture(b);if(B.sampler){var V=V[B.sampler];U.sampler.minFilter=V.minFilter,U.sampler.magFilter=V.magFilter,U.sampler.wrapS=V.wrapS,U.sampler.wrapT=V.wrapT}I.push(U)}}catch(t){k=!0,F=t}finally{try{!L&&j.return&&j.return()}finally{if(k)throw F}}}function Y(t){return t?I[t.index]:null}var G=[];if(t.materials){var q=!0,H=!1,X=void 0;try{for(var W,K=t.materials[Symbol.iterator]();!(q=(W=K.next()).done);q=!0){var z=W.value,Q=new i.PbrMaterial,J=z.pbrMetallicRoughness||{};switch(Q.baseColorFactor.value=J.baseColorFactor||[1,1,1,1],Q.baseColor.texture=Y(J.baseColorTexture),Q.metallicRoughnessFactor.value=[J.metallicFactor||1,J.roughnessFactor||1],Q.metallicRoughness.texture=Y(J.metallicRoughnessTexture),Q.normal.texture=Y(t.normalTexture),Q.occlusion.texture=Y(t.occlusionTexture),Q.occlusionStrength.value=t.occlusionTexture&&t.occlusionTexture.strength?t.occlusionTexture.strength:1,Q.emissiveFactor.value=z.emissiveFactor||[0,0,0],Q.emissive.texture=Y(t.emissiveTexture),!Q.emissive.texture&&t.emissiveFactor&&(Q.emissive.texture=new u.ColorTexture(1,1,1,1)),z.alphaMode){case"BLEND":case"MASK":Q.state.blend=!0;break;default:Q.state.blend=!1}Q.state.cullFace=!z.doubleSided,G.push(Q)}}catch(t){H=!0,X=t}finally{try{!q&&K.return&&K.return()}finally{if(H)throw X}}}var Z=t.accessors,$=[],tt=!0,et=!1,rt=void 0;try{for(var nt,it=t.meshes[Symbol.iterator]();!(tt=(nt=it.next()).done);tt=!0){var ot=nt.value,at=new _;$.push(at);var ut=!0,st=!1,ct=void 0;try{for(var ft,lt=ot.primitives[Symbol.iterator]();!(ut=(ft=lt.next()).done);ut=!0){var ht=ft.value,dt=null;dt="material"in ht?G[ht.material]:new i.PbrMaterial;var vt=[],_t=0,mt=null,pt=null;for(var yt in ht.attributes){var bt=Z[ht.attributes[yt]],gt=b[bt.bufferView];_t=bt.count;var Mt=new a.PrimitiveAttribute(yt,gt.renderBuffer(this.renderer,c.ARRAY_BUFFER),v(bt.type),bt.componentType,gt.byteStride||0,bt.byteOffset||0);Mt.normalized=bt.normalized||!1,"POSITION"==yt&&(mt=bt.min,pt=bt.max),vt.push(Mt)}var xt=new a.Primitive(vt,_t,ht.mode);if("indices"in ht){var Tt=Z[ht.indices],Et=b[Tt.bufferView];xt.setIndexBuffer(Et.renderBuffer(this.renderer,c.ELEMENT_ARRAY_BUFFER),Tt.byteOffset||0,Tt.componentType),xt.indexType=Tt.componentType,xt.indexByteOffset=Tt.byteOffset||0,xt.elementCount=Tt.count}mt&&pt&&xt.setBounds(mt,pt),at.primitives.push(this.renderer.createRenderPrimitive(xt,dt))}}catch(t){st=!0,ct=t}finally{try{!ut&<.return&<.return()}finally{if(st)throw ct}}}}catch(t){et=!0,rt=t}finally{try{!tt&&it.return&&it.return()}finally{if(et)throw rt}}var wt=new o.Node,Ot=t.scenes[t.scene],Rt=!0,Pt=!1,St=void 0;try{for(var At,Nt=Ot.nodes[Symbol.iterator]();!(Rt=(At=Nt.next()).done);Rt=!0){var Ct=At.value,It=t.nodes[Ct];wt.addNode(this.processNodes(It,t.nodes,$))}}catch(t){Pt=!0,St=t}finally{try{!Rt&&Nt.return&&Nt.return()}finally{if(Pt)throw St}}return wt}},{key:"processNodes",value:function(t,e,r){var n=new o.Node;if(n.name=t.name,"mesh"in t){var i=r[t.mesh],a=!0,u=!1,s=void 0;try{for(var c,f=i.primitives[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){var l=c.value;n.addRenderPrimitive(l)}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}}if(t.matrix?n.matrix=new Float32Array(t.matrix):(t.translation||t.rotation||t.scale)&&(t.translation&&(n.translation=new Float32Array(t.translation)),t.rotation&&(n.rotation=new Float32Array(t.rotation)),t.scale&&(n.scale=new Float32Array(t.scale))),t.children){var h=!0,d=!1,v=void 0;try{for(var _,m=t.children[Symbol.iterator]();!(h=(_=m.next()).done);h=!0){var p=e[_.value];n.addNode(this.processNodes(p,e,r))}}catch(t){d=!0,v=t}finally{try{!h&&m.return&&m.return()}finally{if(d)throw v}}}return n}}]),t}();var _=function t(){s(this,t),this.primitives=[]},m=function(){function t(e,r){s(this,t),this.buffer=r[e.buffer],this.byteOffset=e.byteOffset||0,this.byteLength=e.byteLength||null,this.byteStride=e.byteStride,this._viewPromise=null,this._renderBuffer=null}return n(t,[{key:"dataView",value:function(){var t=this;return this._viewPromise||(this._viewPromise=this.buffer.arrayBuffer().then(function(e){return new DataView(e,t.byteOffset,t.byteLength)})),this._viewPromise}},{key:"renderBuffer",value:function(t,e){return this._renderBuffer||(this._renderBuffer=t.createRenderBuffer(e,this.dataView())),this._renderBuffer}}]),t}(),p=function(){function t(e,r,n){s(this,t),this.json=e,this.baseUrl=r,this._dataPromise=null,this._texture=null,n&&(this._dataPromise=Promise.resolve(n))}return n(t,[{key:"arrayBuffer",value:function(){if(!this._dataPromise){if(h(this.json.uri)){var t=this.json.uri.replace("data:application/octet-stream;base64,",""),e=Uint8Array.from(atob(t),function(t){return t.charCodeAt(0)});return this._dataPromise=Promise.resolve(e.buffer),this._dataPromise}this._dataPromise=fetch(d(this.json.uri,this.baseUrl)).then(function(t){return t.arrayBuffer()})}return this._dataPromise}},{key:"texture",value:function(t){var e=this;if(!this._texture){var r=new Image;if(this._texture=new u.ImageTexture(r),this.json.uri)h(this.json.uri)?r.src=this.json.uri:r.src=""+this.baseUrl+this.json.uri;else t[this.json.bufferView].dataView().then(function(t){var n=new Blob([t],{type:e.json.mimeType});r.src=window.URL.createObjectURL(n)})}return this._texture}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.SkyboxNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(7),a=r(2),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=WebGLRenderingContext,h=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.SKY,t.state.depthFunc=l.LEQUAL,t.state.depthMask=!1,t.image=t.defineSampler("diffuse"),t.texCoordScaleOffset=t.defineUniform("texCoordScaleOffset",[1,1,0,0,1,1,0,0],4),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"SKYBOX"}},{key:"vertexSource",get:function(){return"\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n // Drop the translation portion of the view matrix\n view[3].xyz = vec3(0.0, 0.0, 0.0);\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n\n // Returning the W component for both Z and W forces the geometry depth to\n // the far plane. When combined with a depth func of LEQUAL this makes the\n // sky write to any depth fragment that has not been written to yet.\n return out_vec.xyww;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }"}}]),e}();e.SkyboxNode=function(t){function e(t){s(this,e);var r=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._url=t.url,r._displayMode=t.displayMode||"mono",r._rotationY=t.rotationY||0,r}return f(e,a.Node),n(e,[{key:"onRendererChanged",value:function(t){for(var e=[],r=[],n=0;n<=40;++n)for(var i=n*Math.PI/40,a=Math.sin(i),s=Math.cos(i),c=41*n,f=41*(n+1),d=0;d<=40;++d){var v=2*d*Math.PI/40+this._rotationY,_=Math.sin(v)*a,m=s,p=-Math.cos(v)*a,y=d/40,b=n/40;if(e.push(_,m,p,y,b),n<40&&d<40){var g=c+d,M=f+d;r.push(g,M,g+1,M,M+1,g+1)}}var x=t.createRenderBuffer(l.ARRAY_BUFFER,new Float32Array(e)),T=t.createRenderBuffer(l.ELEMENT_ARRAY_BUFFER,new Uint16Array(r)),E=[new o.PrimitiveAttribute("POSITION",x,3,l.FLOAT,20,0),new o.PrimitiveAttribute("TEXCOORD_0",x,2,l.FLOAT,20,12)],w=new o.Primitive(E,r.length);w.setIndexBuffer(T);var O=new h;switch(O.image.texture=new u.UrlTexture(this._url),this._displayMode){case"mono":O.texCoordScaleOffset.value=[1,1,0,0,1,1,0,0];break;case"stereoTopBottom":O.texCoordScaleOffset.value=[1,.5,0,0,1,.5,0,.5];break;case"stereoLeftRight":O.texCoordScaleOffset.value=[.5,1,0,0,.5,1,.5,0]}var R=t.createRenderPrimitive(w,O);this.addRenderPrimitive(R)}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.VideoNode=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(7),a=r(2),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=WebGLRenderingContext,h=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.image=t.defineSampler("diffuse"),t.texCoordScaleOffset=t.defineUniform("texCoordScaleOffset",[1,1,0,0,1,1,0,0],4),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"VIDEO_PLAYER"}},{key:"vertexSource",get:function(){return"\n uniform int EYE_INDEX;\n uniform vec4 texCoordScaleOffset[2];\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];\n vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;\n vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);\n return out_vec;\n }"}},{key:"fragmentSource",get:function(){return"\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n vec4 fragment_main() {\n return texture2D(diffuse, vTexCoord);\n }"}}]),e}();e.VideoNode=function(t){function e(t){s(this,e);var r=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return r._video=t.video,r._displayMode=t.displayMode||"mono",r._video_texture=new u.VideoTexture(r._video),r}return f(e,a.Node),n(e,[{key:"onRendererChanged",value:function(t){var e=[0,2,1,0,3,2],r=t.createRenderBuffer(l.ARRAY_BUFFER,new Float32Array([-1,1,0,0,0,1,1,0,1,0,1,-1,0,1,1,-1,-1,0,0,1])),n=t.createRenderBuffer(l.ELEMENT_ARRAY_BUFFER,new Uint16Array(e)),i=[new o.PrimitiveAttribute("POSITION",r,3,l.FLOAT,20,0),new o.PrimitiveAttribute("TEXCOORD_0",r,2,l.FLOAT,20,12)],a=new o.Primitive(i,e.length);a.setIndexBuffer(n),a.setBounds([-1,-1,0],[1,1,.015]);var u=new h;switch(u.image.texture=this._video_texture,this._displayMode){case"mono":u.texCoordScaleOffset.value=[1,1,0,0,1,1,0,0];break;case"stereoTopBottom":u.texCoordScaleOffset.value=[1,.5,0,0,1,.5,0,.5];break;case"stereoLeftRight":u.texCoordScaleOffset.value=[.5,1,0,0,.5,1,.5,0]}var s=t.createRenderPrimitive(a,u);this.addRenderPrimitive(s)}},{key:"aspectRatio",get:function(){var t=this._video.videoWidth,e=this._video.videoHeight;switch(this._displayMode){case"stereoTopBottom":e*=.5;break;case"stereoLeftRight":t*=.5}return e&&t?t/e:1}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Scene=e.WebXRView=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(11),o=r(31),a=r(32),u=r(2),s=r(6);function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function f(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var h=e.WebXRView=function(t){function e(t,r){return c(this,e),f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t?t.projectionMatrix:null,t?t.viewMatrix:null,r&&t?r.getViewport(t):null,t?t.eye:"left"))}return l(e,i.RenderView),e}();e.Scene=function(t){function e(){c(this,e);var t=f(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._timestamp=-1,t._frameDelta=0,t._statsStanding=!1,t._stats=null,t._statsEnabled=!1,t.enableStats(!0),t._inputRenderer=null,t._resetInputEndFrame=!0,t._lastTimestamp=0,t._hoverFrame=0,t._hoveredNodes=[],t.clear=!0,t}return l(e,u.Node),n(e,[{key:"setRenderer",value:function(t){this._setRenderer(t)}},{key:"loseRenderer",value:function(){this._renderer&&(this._stats=null,this._renderer=null,this._inputRenderer=null)}},{key:"updateInputSources",value:function(t,e){if(t.session.getInputSources){var r=t.session.getInputSources(),n=[],i=this._hoverFrame;this._hoverFrame++;var o=!0,a=!1,u=void 0;try{for(var c,f=r[Symbol.iterator]();!(o=(c=f.next()).done);o=!0){var l=c.value,h=t.getInputPose(l,e);if(h&&(h.gripMatrix&&this.inputRenderer.addController(h.gripMatrix),h.targetRay)){"tracked-pointer"==l.targetRayMode&&this.inputRenderer.addLaserPointer(h.targetRay);var d=this.hitTest(h.targetRay);if(d)this.inputRenderer.addCursor(d.intersection),d.node._hoverFrameId!=i&&d.node.onHoverStart(),d.node._hoverFrameId=this._hoverFrame,n.push(d.node);else{var v=s.vec3.fromValues(h.targetRay.origin.x,h.targetRay.origin.y,h.targetRay.origin.z);s.vec3.add(v,v,[1*h.targetRay.direction.x,1*h.targetRay.direction.y,1*h.targetRay.direction.z]),this.inputRenderer.addCursor(v)}}}}catch(t){a=!0,u=t}finally{try{!o&&f.return&&f.return()}finally{if(a)throw u}}var _=!0,m=!1,p=void 0;try{for(var y,b=this._hoveredNodes[Symbol.iterator]();!(_=(y=b.next()).done);_=!0){var g=y.value;g._hoverFrameId!=this._hoverFrame&&g.onHoverEnd()}}catch(t){m=!0,p=t}finally{try{!_&&b.return&&b.return()}finally{if(m)throw p}}this._hoveredNodes=n}}},{key:"handleSelect",value:function(t,e,r){var n=e.getInputPose(t,r);n&&this.handleSelectPointer(n.targetRay)}},{key:"handleSelectPointer",value:function(t){if(t){var e=this.hitTest(t);e&&e.node.handleSelect()}}},{key:"enableStats",value:function(t){t!=this._statsEnabled&&(this._statsEnabled=t,t?(this._stats=new a.StatsViewer,this._stats.selectable=!0,this.addNode(this._stats),this._statsStanding?this._stats.translation=[0,1.4,-.75]:this._stats.translation=[0,-.3,-.5],this._stats.scale=[.3,.3,.3],s.quat.fromEuler(this._stats.rotation,-45,0,0)):t||this._stats&&(this.removeNode(this._stats),this._stats=null))}},{key:"standingStats",value:function(t){this._statsStanding=t,this._stats&&(this._statsStanding?this._stats.translation=[0,1.4,-.75]:this._stats.translation=[0,-.3,-.5],this._stats.scale=[.3,.3,.3],s.quat.fromEuler(this._stats.rotation,-45,0,0))}},{key:"draw",value:function(t,e,r){var n=new i.RenderView;n.projectionMatrix=t,n.viewMatrix=e,r&&(n.eye=r),this.drawViewArray([n])}},{key:"drawXRFrame",value:function(t,e){if(this._renderer&&e){var r=this._renderer.gl,n=t.session.baseLayer;if(r){r.bindFramebuffer(r.FRAMEBUFFER,n.framebuffer),this.clear&&r.clear(r.COLOR_BUFFER_BIT|r.DEPTH_BUFFER_BIT);var i=[],o=!0,a=!1,u=void 0;try{for(var s,c=e.views[Symbol.iterator]();!(o=(s=c.next()).done);o=!0){var f=s.value;i.push(new h(f,n))}}catch(t){a=!0,u=t}finally{try{!o&&c.return&&c.return()}finally{if(a)throw u}}this.drawViewArray(i)}}}},{key:"drawViewArray",value:function(t){this._renderer&&this._renderer.drawViews(t,this)}},{key:"startFrame",value:function(){var t=this._timestamp;return this._timestamp=performance.now(),this._stats&&this._stats.begin(),this._frameDelta=t>=0?this._timestamp-t:0,this._update(this._timestamp,this._frameDelta),this._frameDelta}},{key:"endFrame",value:function(){this._inputRenderer&&this._resetInputEndFrame&&this._inputRenderer.reset(),this._stats&&this._stats.end()}},{key:"onLoadScene",value:function(t){return Promise.resolve()}},{key:"inputRenderer",get:function(){return this._inputRenderer||(this._inputRenderer=new o.InputRenderer,this.addNode(this._inputRenderer)),this._inputRenderer}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.InputRenderer=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7),u=r(8);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=WebGLRenderingContext,h=new Uint8Array([255,255,255,1,255,255,255,2,191,191,191,4,204,204,204,5,219,219,219,7,204,204,204,10,216,216,216,13,210,210,210,17,206,206,206,21,206,206,206,26,206,206,206,31,205,205,205,36,200,200,200,42,201,201,201,47,201,201,201,52,201,201,201,57,201,201,201,61,200,200,200,65,203,203,203,68,238,238,238,135,250,250,250,200,249,249,249,201,249,249,249,201,250,250,250,201,250,250,250,201,249,249,249,201,249,249,249,201,250,250,250,200,238,238,238,135,203,203,203,68,200,200,200,65,201,201,201,61,201,201,201,57,201,201,201,52,201,201,201,47,200,200,200,42,205,205,205,36,206,206,206,31,206,206,206,26,206,206,206,21,210,210,210,17,216,216,216,13,204,204,204,10,219,219,219,7,204,204,204,5,191,191,191,4,255,255,255,2,255,255,255,1]),d=[1,1,1,.25],v=[1,1,1,1],_=[.5,.5,.5,.25],m={controllers:!0,lasers:!0,cursors:!0},p=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.ADDITIVE,t.state.cullFace=!1,t.state.blend=!0,t.state.blendFuncSrc=l.ONE,t.state.blendFuncDst=l.ONE,t.state.depthMask=!1,t.laser=t.defineSampler("diffuse"),t.laser.texture=new u.DataTexture(h,48,1),t.laserColor=t.defineUniform("laserColor",d),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"INPUT_LASER"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec2 TEXCOORD_0;\n\n varying vec2 vTexCoord;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vTexCoord = TEXCOORD_0;\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n\n uniform vec4 laserColor;\n uniform sampler2D diffuse;\n varying vec2 vTexCoord;\n\n const float fadePoint = 0.5335;\n const float fadeEnd = 0.535;\n\n vec4 fragment_main() {\n vec2 uv = vTexCoord;\n float front_fade_factor = 1.0 - clamp(1.0 - (uv.y - fadePoint) / (1.0 - fadePoint), 0.0, 1.0);\n float back_fade_factor = clamp((uv.y - fadePoint) / (fadeEnd - fadePoint), 0.0, 1.0);\n vec4 color = laserColor * texture2D(diffuse, vTexCoord);\n float opacity = color.a * front_fade_factor * back_fade_factor;\n return vec4(color.rgb * opacity, opacity);\n }"}}]),e}(),y="\nattribute vec4 POSITION;\n\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vLuminance = POSITION.z;\n vOpacity = POSITION.w;\n\n // Billboarded, constant size vertex transform.\n vec4 screenPos = proj * view * model * vec4(0.0, 0.0, 0.0, 1.0);\n screenPos /= screenPos.w;\n screenPos.xy += POSITION.xy;\n return screenPos;\n}",b="\nprecision mediump float;\n\nuniform vec4 cursorColor;\nvarying float vLuminance;\nvarying float vOpacity;\n\nvec4 fragment_main() {\n vec3 color = cursorColor.rgb * vLuminance;\n float opacity = cursorColor.a * vOpacity;\n return vec4(color * opacity, opacity);\n}",g=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.ADDITIVE,t.state.cullFace=!1,t.state.blend=!0,t.state.blendFuncSrc=l.ONE,t.state.depthMask=!1,t.cursorColor=t.defineUniform("cursorColor",v),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"INPUT_CURSOR"}},{key:"vertexSource",get:function(){return y}},{key:"fragmentSource",get:function(){return b}}]),e}(),M=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t.renderOrder=i.RENDER_ORDER.ADDITIVE,t.state.cullFace=!1,t.state.blend=!0,t.state.blendFuncSrc=l.ONE,t.state.depthFunc=l.GEQUAL,t.state.depthMask=!1,t.cursorColor=t.defineUniform("cursorColor",_),t}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"INPUT_CURSOR_2"}},{key:"vertexSource",get:function(){return y}},{key:"fragmentSource",get:function(){return b}}]),e}();e.InputRenderer=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._maxInputElements=32,t._controllers=[],t._controllerNode=null,t._controllerNodeHandedness=null,t._lasers=null,t._cursors=null,t._activeControllers=0,t._activeLasers=0,t._activeCursors=0,t}return f(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this._controllers=[],this._controllerNode=null,this._controllerNodeHandedness=null,this._lasers=null,this._cursors=null,this._activeControllers=0,this._activeLasers=0,this._activeCursors=0}},{key:"setControllerMesh",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"right";this._controllerNode=t,this._controllerNode.visible=!1,this.addNode(this._controllerNode),this._controllerNodeHandedness=e}},{key:"addController",value:function(t){if(this._controllerNode){var e=null;this._activeControllers<this._controllers.length?e=this._controllers[this._activeControllers]:(e=this._controllerNode.clone(),this.addNode(e),this._controllers.push(e)),this._activeControllers=(this._activeControllers+1)%this._maxInputElements,e.matrix=t,e.visible=!0}}},{key:"addLaserPointer",value:function(t){!this._lasers&&this._renderer&&(this._lasers=[this._createLaserMesh()],this.addNode(this._lasers[0]));var e=null;this._activeLasers<this._lasers.length?e=this._lasers[this._activeLasers]:(e=this._lasers[0].clone(),this.addNode(e),this._lasers.push(e)),this._activeLasers=(this._activeLasers+1)%this._maxInputElements,e.matrix=t.transformMatrix,e.visible=!0}},{key:"addCursor",value:function(t){!this._cursors&&this._renderer&&(this._cursors=[this._createCursorMesh()],this.addNode(this._cursors[0]));var e=null;this._activeCursors<this._cursors.length?e=this._cursors[this._activeCursors]:(e=this._cursors[0].clone(),this.addNode(e),this._cursors.push(e)),this._activeCursors=(this._activeCursors+1)%this._maxInputElements,e.translation=t,e.visible=!0}},{key:"reset",value:function(t){if(t||(t=m),this._controllers&&t.controllers){var e=!0,r=!1,n=void 0;try{for(var i,o=this._controllers[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){i.value.visible=!1}}catch(t){r=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(r)throw n}}this._activeControllers=0}if(this._lasers&&t.lasers){var a=!0,u=!1,s=void 0;try{for(var c,f=this._lasers[Symbol.iterator]();!(a=(c=f.next()).done);a=!0){c.value.visible=!1}}catch(t){u=!0,s=t}finally{try{!a&&f.return&&f.return()}finally{if(u)throw s}}this._activeLasers=0}if(this._cursors&&t.cursors){var l=!0,h=!1,d=void 0;try{for(var v,_=this._cursors[Symbol.iterator]();!(l=(v=_.next()).done);l=!0){v.value.visible=!1}}catch(t){h=!0,d=t}finally{try{!l&&_.return&&_.return()}finally{if(h)throw d}}this._activeCursors=0}}},{key:"_createLaserMesh",value:function(){var t=this._renderer._gl,e=.005,r=[0,e,0,0,1,0,e,-1,0,0,0,-e,0,1,1,0,-e,-1,1,0,e,0,0,0,1,e,0,-1,0,0,-e,0,0,1,1,-e,0,-1,1,0,0,-e,0,0,1,0,-e,-1,0,0,0,e,0,1,1,0,e,-1,1,0,-e,0,0,0,1,-e,0,-1,0,0,e,0,0,1,1,e,0,-1,1,0],n=[0,1,2,1,3,2,4,5,6,5,7,6,8,9,10,9,11,10,12,13,14,13,15,14],i=this._renderer.createRenderBuffer(t.ARRAY_BUFFER,new Float32Array(r)),u=this._renderer.createRenderBuffer(t.ELEMENT_ARRAY_BUFFER,new Uint16Array(n)),s=n.length,c=[new a.PrimitiveAttribute("POSITION",i,3,t.FLOAT,20,0),new a.PrimitiveAttribute("TEXCOORD_0",i,2,t.FLOAT,20,12)],f=new a.Primitive(c,s);f.setIndexBuffer(u);var l=new p,h=this._renderer.createRenderPrimitive(f,l),d=new o.Node;return d.addRenderPrimitive(h),d}},{key:"_createCursorMesh",value:function(){for(var t=this._renderer._gl,e=[],r=[],n=2*Math.PI/16,i=0;i<16;++i){var u=i*n,s=Math.cos(u),c=Math.sin(u);e.push(.004*s,.004*c,1,.9),i>1&&r.push(0,i-1,i)}for(var f=0;f<16;++f){var l=f*n,h=Math.cos(l),d=Math.sin(l);if(e.push(.004*h,.004*d,.5,.75),e.push(.007*h,.007*d,0,0),f>0){var v=16+2*f;r.push(v-2,v-1,v),r.push(v-1,v+1,v)}}r.push(46,47,16),r.push(47,17,16);var _=this._renderer.createRenderBuffer(t.ARRAY_BUFFER,new Float32Array(e)),m=this._renderer.createRenderBuffer(t.ELEMENT_ARRAY_BUFFER,new Uint16Array(r)),p=r.length,y=[new a.PrimitiveAttribute("POSITION",_,4,t.FLOAT,16,0)],b=new a.Primitive(y,p);b.setIndexBuffer(m);var x=new g,T=new M,E=this._renderer.createRenderPrimitive(b,x),w=this._renderer.createRenderPrimitive(b,T),O=new o.Node;return O.addRenderPrimitive(E),O.addRenderPrimitive(w),O}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.StatsViewer=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7),u=r(33);function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=30,h=90,d=function(t){function e(){return s(this,e),c(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"STATS_VIEWER"}},{key:"vertexSource",get:function(){return"\n attribute vec3 POSITION;\n attribute vec3 COLOR_0;\n varying vec4 vColor;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n vColor = vec4(COLOR_0, 1.0);\n return proj * view * model * vec4(POSITION, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n varying vec4 vColor;\n\n vec4 fragment_main() {\n return vColor;\n }"}}]),e}();function v(t){return.9/l*t-.45}function _(t){return Math.min(t,h)*(.7/h)-.45}var m=window.performance&&performance.now?performance.now.bind(performance):Date.now;e.StatsViewer=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._performanceMonitoring=!1,t._startTime=m(),t._prevFrameTime=t._startTime,t._prevGraphUpdateTime=t._startTime,t._frames=0,t._fpsAverage=0,t._fpsMin=0,t._fpsStep=t._performanceMonitoring?1e3:250,t._lastSegment=0,t._fpsVertexBuffer=null,t._fpsRenderPrimitive=null,t._fpsNode=null,t._sevenSegmentNode=new u.SevenSegmentText,t._sevenSegmentNode.matrix=new Float32Array([.075,0,0,0,0,.075,0,0,0,0,1,0,-.3625,.3625,.02,1]),t}return f(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this.clearNodes();for(var e=t.gl,r=[],n=[],i=0;i<l;++i){r.push(v(i),_(0),.02,0,1,1),r.push(v(i+1),_(0),.02,0,1,1),r.push(v(i),_(0),.02,0,1,1),r.push(v(i+1),_(0),.02,0,1,1);var u=4*i;n.push(u,u+3,u+1,u+3,u,u+2)}function s(t,e,i,o,a,u,s,c){var f=r.length/6;r.push(t,e,a,u,s,c),r.push(i,o,a,u,s,c),r.push(t,o,a,u,s,c),r.push(i,e,a,u,s,c),n.push(f,f+1,f+2,f,f+3,f+1)}s(-.5,-.5,.5,.5,0,0,0,.125),s(-.45,-.45,.45,.25,.01,0,0,.4),s(-.45,_(30),.45,_(32),.015,.5,0,.5),s(-.45,_(60),.45,_(62),.015,.2,0,.75),this._fpsVertexBuffer=t.createRenderBuffer(e.ARRAY_BUFFER,new Float32Array(r),e.DYNAMIC_DRAW);var c=t.createRenderBuffer(e.ELEMENT_ARRAY_BUFFER,new Uint16Array(n)),f=[new a.PrimitiveAttribute("POSITION",this._fpsVertexBuffer,3,e.FLOAT,24,0),new a.PrimitiveAttribute("COLOR_0",this._fpsVertexBuffer,3,e.FLOAT,24,12)],h=new a.Primitive(f,n.length);h.setIndexBuffer(c),h.setBounds([-.5,-.5,0],[.5,.5,.015]),this._fpsRenderPrimitive=t.createRenderPrimitive(h,new d),this._fpsNode=new o.Node,this._fpsNode.addRenderPrimitive(this._fpsRenderPrimitive),this.addNode(this._fpsNode),this.addNode(this._sevenSegmentNode)}},{key:"begin",value:function(){this._startTime=m()}},{key:"end",value:function(){var t=m(),e=1e3/(t-this._prevFrameTime);if(this._prevFrameTime=t,this._fpsMin=this._frames?Math.min(this._fpsMin,e):e,this._frames++,t>this._prevGraphUpdateTime+this._fpsStep){var r=t-this._prevGraphUpdateTime;this._fpsAverage=Math.round(1e3/(r/this._frames)),this._updateGraph(this._fpsMin,this._fpsAverage),this._performanceMonitoring&&console.log("Average FPS: "+this._fpsAverage+" Min FPS: "+this._fpsMin),this._prevGraphUpdateTime=t,this._frames=0,this._fpsMin=0}}},{key:"_updateGraph",value:function(t,e){var r,n=(r=t,{r:Math.max(0,Math.min(1,1-r/60)),g:Math.max(0,Math.min(1,(r-15)/(h-15))),b:Math.max(0,Math.min(1,(r-15)/(h-15)))}),i=_(t-1),o=_(e+1),a=[v(this._lastSegment),o,.02,n.r,n.g,n.b,v(this._lastSegment+1),o,.02,n.r,n.g,n.b,v(this._lastSegment),i,.02,n.r,n.g,n.b,v(this._lastSegment+1),i,.02,n.r,n.g,n.b];n.r=.2,n.g=1,n.b=.2,this._lastSegment==l-1?(this._renderer.updateRenderBuffer(this._fpsVertexBuffer,new Float32Array(a),24*this._lastSegment*4),a=[v(0),_(h),.02,n.r,n.g,n.b,v(.25),_(h),.02,n.r,n.g,n.b,v(0),_(0),.02,n.r,n.g,n.b,v(.25),_(0),.02,n.r,n.g,n.b],this._renderer.updateRenderBuffer(this._fpsVertexBuffer,new Float32Array(a),0)):(a.push(v(this._lastSegment+1),_(h),.02,n.r,n.g,n.b,v(this._lastSegment+1.25),_(h),.02,n.r,n.g,n.b,v(this._lastSegment+1),_(0),.02,n.r,n.g,n.b,v(this._lastSegment+1.25),_(0),.02,n.r,n.g,n.b),this._renderer.updateRenderBuffer(this._fpsVertexBuffer,new Float32Array(a),24*this._lastSegment*4)),this._lastSegment=(this._lastSegment+1)%l,this._sevenSegmentNode.text=this._fpsAverage+" FP5"}},{key:"performanceMonitoring",get:function(){return this._performanceMonitoring},set:function(t){this._performanceMonitoring=t,this._fpsStep=t?1e3:250}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.SevenSegmentText=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(3),o=r(2),a=r(7);function u(t){if(Array.isArray(t)){for(var e=0,r=Array(t.length);e<t.length;e++)r[e]=t[e];return r}return Array.from(t)}function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function c(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var l=function(t){function e(){return s(this,e),c(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return f(e,i.Material),n(e,[{key:"materialName",get:function(){return"SEVEN_SEGMENT_TEXT"}},{key:"vertexSource",get:function(){return"\n attribute vec2 POSITION;\n\n vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {\n return proj * view * model * vec4(POSITION, 0.0, 1.0);\n }"}},{key:"fragmentSource",get:function(){return"\n precision mediump float;\n const vec4 color = vec4(0.0, 1.0, 0.0, 1.0);\n\n vec4 fragment_main() {\n return color;\n }"}}]),e}();e.SevenSegmentText=function(t){function e(){s(this,e);var t=c(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));return t._text="",t._charNodes=[],t}return f(e,o.Node),n(e,[{key:"onRendererChanged",value:function(t){this.clearNodes(),this._charNodes=[];var e=[],r={},n=[];function i(t,n,i,o,a){var u=e.length/2;e.push(n,i,o,i,o,a,n,a),r[t]=[u,u+2,u+1,u,u+3,u+2]}var o={};function s(t,e){for(var i={character:t,offset:2*n.length,count:0},a=0;a<e.length;++a){var s=e[a],c=r[s];i.count+=c.length,n.push.apply(n,u(c))}o[t]=i}i(0,-1,1,.5,.75),i(1,-1,.125,.5,-.125),i(2,-1,-.75,.5,-1),i(3,-1,1,-.75,-.125),i(4,.25,1,.5,-.125),i(5,-1,.125,-.75,-1),i(6,.25,.125,.5,-1),s("0",[0,2,3,4,5,6]),s("1",[4,6]),s("2",[0,1,2,4,5]),s("3",[0,1,2,4,6]),s("4",[1,3,4,6]),s("5",[0,1,2,3,6]),s("6",[0,1,2,3,5,6]),s("7",[0,4,6]),s("8",[0,1,2,3,4,5,6]),s("9",[0,1,2,3,4,6]),s("A",[0,1,3,4,5,6]),s("B",[1,2,3,5,6]),s("C",[0,2,3,5]),s("D",[1,2,4,5,6]),s("E",[0,1,2,4,6]),s("F",[0,1,3,5]),s("P",[0,1,3,4,5]),s("-",[1]),s(" ",[]),s("_",[2]);var c=t.gl,f=t.createRenderBuffer(c.ARRAY_BUFFER,new Float32Array(e)),h=t.createRenderBuffer(c.ELEMENT_ARRAY_BUFFER,new Uint16Array(n)),d=[new a.PrimitiveAttribute("POSITION",f,2,c.FLOAT,8,0)],v=new a.Primitive(d,n.length);v.setIndexBuffer(h);var _=new l;for(var m in this._charPrimitives={},o){var p=o[m];v.elementCount=p.count,v.indexByteOffset=p.offset,this._charPrimitives[m]=t.createRenderPrimitive(v,_)}this.text=this._text}},{key:"text",get:function(){return this._text},set:function(t){this._text=t;for(var e=0,r=null;e<t.length;++e)if(r=t[e]in this._charPrimitives?this._charPrimitives[t[e]]:this._charPrimitives._,this._charNodes.length<=e){var n=new o.Node;n.addRenderPrimitive(r);var i=2*e;n.translation=[i,0,0],this._charNodes.push(n),this.addNode(n)}else this._charNodes[e].clearRenderPrimitives(),this._charNodes[e].addRenderPrimitive(r),this._charNodes[e].visible=!0;for(;e<this._charNodes.length;++e)this._charNodes[e].visible=!1}}]),e}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.FallbackHelper=void 0;var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),i=r(6);e.FallbackHelper=function(){function t(e,r){var n=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.scene=e,this.gl=r,this._emulateStage=!1,this.lookYaw=0,this.lookPitch=0,this.viewMatrix=i.mat4.create();var o=i.mat4.create();function a(){r.canvas.width=r.canvas.offsetWidth*window.devicePixelRatio,r.canvas.height=r.canvas.offsetHeight*window.devicePixelRatio,i.mat4.perspective(o,.4*Math.PI,r.canvas.width/r.canvas.height,.1,1e3),r.viewport(0,0,r.drawingBufferWidth,r.drawingBufferHeight)}this.projectionMatrix=o,i.mat4.identity(this.viewMatrix),window.addEventListener("resize",a),a();var u=r.canvas,s=0,c=0;u.addEventListener("touchstart",function(t){2==t.touches.length&&(s=t.touches[1].pageX,c=t.touches[1].pageY)}),u.addEventListener("touchmove",function(t){2==t.touches.length&&(n.onLook(t.touches[1].pageX-s,t.touches[1].pageY-c),s=t.touches[1].pageX,c=t.touches[1].pageY)}),u.addEventListener("mousemove",function(t){2&t.buttons&&n.onLook(t.movementX,t.movementY)}),u.addEventListener("contextmenu",function(t){t.preventDefault()}),this.boundOnFrame=this.onFrame.bind(this),window.requestAnimationFrame(this.boundOnFrame)}return n(t,[{key:"onLook",value:function(t,e){this.lookYaw+=.0025*t,this.lookPitch+=.0025*e,this.lookPitch<.5*-Math.PI&&(this.lookPitch=.5*-Math.PI),this.lookPitch>.5*Math.PI&&(this.lookPitch=.5*Math.PI),this.updateView()}},{key:"onFrame",value:function(t){var e=this.gl;window.requestAnimationFrame(this.boundOnFrame),this.scene.startFrame(),e.clear(e.COLOR_BUFFER_BIT|e.DEPTH_BUFFER_BIT),this.scene.draw(this.projectionMatrix,this.viewMatrix),this.scene.endFrame()}},{key:"updateView",value:function(){i.mat4.identity(this.viewMatrix),i.mat4.rotateX(this.viewMatrix,this.viewMatrix,-this.lookPitch),i.mat4.rotateY(this.viewMatrix,this.viewMatrix,-this.lookYaw),this._emulateStage&&i.mat4.translate(this.viewMatrix,this.viewMatrix,[0,-1.6,0])}},{key:"emulateStage",get:function(){return this._emulateStage},set:function(t){this._emulateStage=t,this.updateView()}}]),t}()},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();var i=null;function o(){if(!i){i={};for(var t=(window.location.search.substring(1)||window.location.hash.substring(1)).split("&"),e=0;e<t.length;e++){var r=t[e].split("=");i[r[0].toLowerCase()]=decodeURIComponent(r[1])}}}window.onhashchange=function(){i=null};e.QueryArgs=function(){function t(){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t)}return n(t,null,[{key:"getString",value:function(t,e){o();var r=t.toLowerCase();return r in i?i[r]:e}},{key:"getInt",value:function(t,e){o();var r=t.toLowerCase();return r in i?parseInt(i[r],10):e}},{key:"getFloat",value:function(t,e){o();var r=t.toLowerCase();return r in i?parseFloat(i[r]):e}},{key:"getBool",value:function(t,e){o();var r=t.toLowerCase();return r in i?0!=parseInt(i[r],10):e}}]),t}()}])}); \ No newline at end of file
diff --git a/third_party/webxr_test_pages/webxr-samples/js/cottontail/package.json b/third_party/webxr_test_pages/webxr-samples/js/cottontail/package.json index 62c747d..41ce01b 100644 --- a/third_party/webxr_test_pages/webxr-samples/js/cottontail/package.json +++ b/third_party/webxr_test_pages/webxr-samples/js/cottontail/package.json
@@ -24,7 +24,7 @@ "eslint": "^4.19.1", "eslint-config-google": "^0.9.1", "gl-matrix": "^2.5.1", - "webpack": "^4.6.0", - "webpack-cli": "^2.0.15" + "webpack": "^4.29.0", + "webpack-cli": "^3.2.1" } }
diff --git a/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js b/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js index 7566851c..ba60b82 100644 --- a/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js +++ b/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js
@@ -25,10 +25,10 @@ import {vec3, quat} from '../math/gl-matrix.js'; export class WebXRView extends RenderView { - constructor(view, pose, layer) { + constructor(view, layer) { super( view ? view.projectionMatrix : null, - (pose && view) ? pose.getViewMatrix(view) : null, + view ? view.viewMatrix : null, (layer && view) ? layer.getViewport(view) : null, view ? view.eye : 'left' ); @@ -253,8 +253,8 @@ } let views = []; - for (let view of xrFrame.views) { - views.push(new WebXRView(view, pose, layer)); + for (let view of pose.views) { + views.push(new WebXRView(view, layer)); } this.drawViewArray(views);
diff --git a/third_party/webxr_test_pages/webxr-samples/js/webxr-version-shim.js b/third_party/webxr_test_pages/webxr-samples/js/webxr-version-shim.js index 465b8d5..359fd08 100644 --- a/third_party/webxr_test_pages/webxr-samples/js/webxr-version-shim.js +++ b/third_party/webxr_test_pages/webxr-samples/js/webxr-version-shim.js
@@ -108,25 +108,28 @@ // We can't test for the existence of the enums in question directly, so this code // will just try to create the requested type and fall back if it fails. - const NATIVE_REQUEST_FRAME_OF_REFERENCE = XRSession.prototype.requestFrameOfReference; - XRSession.prototype.requestFrameOfReference = function(type, options) { + const NATIVE_REQUEST_FRAME_OF_REFERENCE = XRSession.prototype.requestReferenceSpace; + XRSession.prototype.requestFrameOfReference = function(type, options_original) { let session = this; + let options = options_original || {}; + options["type"] = "stationary"; + options["subtype"] = type; // Try the current type. - return NATIVE_REQUEST_FRAME_OF_REFERENCE.call(session, type, options).catch((error)=>{ + return NATIVE_REQUEST_FRAME_OF_REFERENCE.call(session, options).catch((error)=>{ // FIXME: Should be checking for TypeError specifically. Requires a polyfill update. if(error instanceof Error) { // If the current type fails, switch to the other version. switch(type) { case 'eye-level': - type = 'eyeLevel'; + options["subtype"] = 'eyeLevel'; break; case 'head-model': - type = 'headModel'; + options["subtype"] = 'headModel'; break; default: return Promise.reject(error); } - return Promise.resolve(NATIVE_REQUEST_FRAME_OF_REFERENCE.call(session, type, options)); + return Promise.resolve(NATIVE_REQUEST_FRAME_OF_REFERENCE.call(session, options)); } else { return Promise.reject(error); }
diff --git a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html index e5a4ff3..201501a 100644 --- a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html +++ b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html
@@ -144,7 +144,8 @@ if (!gl) { gl = createWebGLContext({ - compatibleXRDevice: session.device + compatibleXRDevice: session.device, + xrCompatible : true, }); renderer = new Renderer(gl); @@ -226,7 +227,7 @@ // Called every time a XRSession requests that a new frame be drawn. function onXRFrame(t, frame) { let session = frame.session; - let pose = frame.getDevicePose(xrFrameOfRef); + let pose = frame.getViewerPose(xrFrameOfRef); // If requested, use the pose to cast a reticle into the scene using a // continuous hit test. For the moment we're just using the flower
diff --git a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html index 141d1e6..69c502d 100644 --- a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html +++ b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html
@@ -139,7 +139,8 @@ if (!gl) { gl = createWebGLContext({ - compatibleXRDevice: session.device + compatibleXRDevice: session.device, + xrCompatible : true, }); renderer = new Renderer(gl); @@ -168,7 +169,7 @@ // Called every time a XRSession requests that a new frame be drawn. function onXRFrame(t, frame) { let session = frame.session; - let pose = frame.getDevicePose(xrFrameOfRef); + let pose = frame.getViewerPose(xrFrameOfRef); scene.startFrame();
diff --git a/tools/OWNERS b/tools/OWNERS index b4e4d992..4f3ab75 100644 --- a/tools/OWNERS +++ b/tools/OWNERS
@@ -38,6 +38,9 @@ per-file licenses.py=ichikawa@chromium.org +per-file nocompile_driver.py=ajwong@chromium.org +per-file nocompile_driver.py=wychen@chromium.org + per-file remove_stale_pyc_files.py=dtu@chromium.org per-file roll_angle.py=kbr@chromium.org
diff --git a/tools/android/audio_focus_grabber/java/AndroidManifest.xml b/tools/android/audio_focus_grabber/java/AndroidManifest.xml index e83b915..677bc976 100644 --- a/tools/android/audio_focus_grabber/java/AndroidManifest.xml +++ b/tools/android/audio_focus_grabber/java/AndroidManifest.xml
@@ -8,7 +8,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.tools.audio_focus_grabber" > - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <application android:label="@string/app_name" >
diff --git a/tools/android/push_apps_to_background/AndroidManifest.xml b/tools/android/push_apps_to_background/AndroidManifest.xml index 92753f3..45a0cda9 100644 --- a/tools/android/push_apps_to_background/AndroidManifest.xml +++ b/tools/android/push_apps_to_background/AndroidManifest.xml
@@ -10,7 +10,7 @@ android:versionCode="1" android:versionName="1.0" > - <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> <application android:icon="@drawable/ic_launcher"
diff --git a/tools/cygprofile/orderfile_generator_backend.py b/tools/cygprofile/orderfile_generator_backend.py index 8e3799df0f..6649a8d 100755 --- a/tools/cygprofile/orderfile_generator_backend.py +++ b/tools/cygprofile/orderfile_generator_backend.py
@@ -47,6 +47,14 @@ constants.SetBuildType('Release') +# Architecture specific GN args. Trying to build an orderfile for an +# architecture not listed here will eventually throw. +_ARCH_GN_ARGS = { + 'arm': [ 'target_cpu = "arm"' ], + 'arm64': [ 'target_cpu = "arm64"', + 'android_64bit_browser = true'], +} + class CommandError(Exception): """Indicates that a dispatched shell command exited with a non-zero status.""" @@ -269,11 +277,11 @@ 'is_chrome_branded=true', 'is_debug=false', 'is_official_build=true', - 'target_cpu="' + self._arch + '"', 'target_os="android"', 'use_goma=' + str(self._use_goma).lower(), 'use_order_profiling=' + str(instrumented).lower(), ] + args += _ARCH_GN_ARGS[self._arch] if self._goma_dir: args += ['goma_dir="%s"' % self._goma_dir] if self._system_health_profiling: @@ -779,8 +787,8 @@ help='If true, the script only verifies the current orderfile') parser.add_argument('--target-arch', action='store', dest='arch', default='arm', - choices=['arm', 'arm64', 'x86', 'x86_64', 'x64', 'mips'], - help='The target architecture for which to build') + choices=['arm', 'arm64'], + help='The target architecture for which to build.') parser.add_argument('--output-json', action='store', dest='json_file', help='Location to save stats in json format') parser.add_argument(
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 4253a763..fa4579d 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -108,6 +108,7 @@ 'chromium.chromiumos': { 'Linux ChromiumOS Full': 'chromeos_with_codecs_release_bot', + 'chromeos-amd64-generic-cfi-thin-lto-rel': 'cros_chrome_sdk_headless_ozone_cfi_thin_lto', 'chromeos-amd64-generic-rel': 'cros_chrome_sdk_headless_ozone', 'chromeos-daisy-rel': 'cros_chrome_sdk', 'linux-chromeos-rel': 'chromeos_with_codecs_release_bot', @@ -582,6 +583,7 @@ 'tryserver.chromium.android': { 'android-kitkat-arm-rel': 'android_release_trybot', 'android-marshmallow-arm64-rel': 'gpu_tests_android_release_trybot_arm64_no_symbols', + 'android-oreo-arm64-cts-networkservice-dbg': 'android_debug_trybot_arm64', 'android_archive_rel_ng': 'android_release_trybot', 'android_arm64_dbg_recipe': 'android_debug_trybot_compile_only_arm64', 'android-binary-size': 'android_binary_size', @@ -643,8 +645,9 @@ }, 'tryserver.chromium.chromiumos': { - # TODO(crbug.com/913750): Enable DCHECKS on this bot when the PFQ has it - # enabled. + # TODO(crbug.com/913750): Enable DCHECKS on the two amd64-generic bots + # when the PFQ has it enabled. + 'chromeos-amd64-generic-cfi-thin-lto-rel': 'cros_chrome_sdk_headless_ozone_cfi_thin_lto', 'chromeos-amd64-generic-rel': 'cros_chrome_sdk_headless_ozone', 'chromeos-daisy-rel': 'cros_chrome_sdk_dchecks_always_on', 'chromeos-kevin-rel': 'cros_chrome_sdk_headless_ozone_dcheck_always_on', @@ -1288,6 +1291,10 @@ 'cros_chrome_sdk', 'ozone_platform_headless', ], + 'cros_chrome_sdk_headless_ozone_cfi_thin_lto': [ + 'cros_chrome_sdk', 'ozone_platform_headless', 'cfi_full', 'thin_lto', + ], + 'cros_chrome_sdk_headless_ozone_dcheck_always_on': [ 'cros_chrome_sdk', 'ozone_platform_headless', 'dcheck_always_on', ],
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 7f12e9b..4847be1 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -1239,6 +1239,23 @@ <int value="15" label="RESULT_WSC_NOT_AVAILABLE"/> </enum> +<enum name="ApkDownloadTelemetryIncompleteReason"> + <int value="0" label="MISSING_WEB_CONTENTS"/> + <int value="1" label="SB_NAVIGATION_MANAGER_NOT_READY"/> + <int value="2" label="COMPLETE"/> +</enum> + +<enum name="ApkDownloadTelemetryOutcome"> + <int value="0" label="NOT_SENT_SAFE_BROWSING_NOT_ENABLED"/> + <int value="1" label="NOT_SENT_MISSING_WEB_CONTENTS"/> + <int value="2" label="NOT_SENT_INCOGNITO"/> + <int value="3" label="NOT_SENT_EXTENDED_REPORTING_DISABLED"/> + <int value="4" label="NOT_SENT_DOWNLOAD_CANCELLED"/> + <int value="5" label="NOT_SENT_FAILED_TO_SERIALIZE"/> + <int value="6" label="NOT_SENT_FEATURE_NOT_ENABLED"/> + <int value="7" label="SENT"/> +</enum> + <enum name="AppBannersBeforeInstallEvent"> <int value="1" label="Event created and dispatched"/> <int value="2" label="Showing the banner"/> @@ -9984,6 +10001,7 @@ <int value="1" label="Cached and severe memory pressure"/> <int value="2" label="Cached and mild memory pressure and time exceeded"/> <int value="3" label="Cached and app hidden and time exceeded"/> + <int value="4" label="Module loader setup changed"/> </enum> <enum name="CustomTabsDynamicModuleLoadResult"> @@ -16343,6 +16361,8 @@ <int value="430" label="STORAGE_LOCAL_ON_CHANGE"/> <int value="431" label="STORAGE_SYNC_ON_CHANGE"/> <int value="432" label="STORAGE_MANAGED_ON_CHANGE"/> + <int value="433" label="AUTOFILL_PRIVATE_ON_LOCAL_CREDIT_CARD_LIST_CHANGED"/> + <int value="434" label="AUTOFILL_PRIVATE_ON_SERVER_CREDIT_CARD_LIST_CHANGED"/> </enum> <enum name="ExtensionFileWriteResult"> @@ -17718,6 +17738,8 @@ <int value="1310" label="ACCESSIBILITY_PRIVATE_GETBATTERYDESCRIPTION"/> <int value="1311" label="IDLE_GETAUTOLOCKDELAY"/> <int value="1312" label="AUTOTESTPRIVATE_GETPRIMARYDISPLAYSCALEFACTOR"/> + <int value="1313" label="AUTOFILLPRIVATE_GETLOCALCREDITCARDLIST"/> + <int value="1314" label="AUTOFILLPRIVATE_GETSERVERCREDITCARDLIST"/> </enum> <enum name="ExtensionIconState"> @@ -18519,6 +18541,13 @@ <int value="4" label="Failed"/> </enum> +<enum name="FeatureModuleInstallStatus"> + <int value="0" label="Success"/> + <int value="1" label="Failure"/> + <int value="2" label="Request Error"/> + <int value="3" label="Cancellation"/> +</enum> + <enum name="FeatureObserver"> <!-- Generated from third_party/blink/public/platform/web_feature.mojom.--> @@ -38095,6 +38124,7 @@ <int value="3" label="Parsing failed"/> <int value="4" label="Decoding failed"/> <int value="5" label="Logo revalidated"/> + <int value="6" label="Missing image"/> </enum> <enum name="NewTabPageLogoShown"> @@ -51218,6 +51248,11 @@ <int value="28" label="Language"/> </enum> +<enum name="SystemNotificationActionType"> + <int value="0" label="Download paused"/> + <int value="1" label="Download resumed"/> +</enum> + <enum name="SystemNotificationType"> <int value="0" label="Downloads - Files"/> <int value="1" label="Downloads - Pages"/>
diff --git a/tools/metrics/histograms/extract_histograms.py b/tools/metrics/histograms/extract_histograms.py index c18e4ab..549a166f 100644 --- a/tools/metrics/histograms/extract_histograms.py +++ b/tools/metrics/histograms/extract_histograms.py
@@ -303,14 +303,14 @@ # Handle expiry attribute. if histogram.hasAttribute('expires_after'): expiry_str = histogram.getAttribute('expires_after') - if _ValidateMilestoneString(expiry_str) or _ValidateDateString( - expiry_str): + if (expiry_str == "never" or _ValidateMilestoneString(expiry_str) or + _ValidateDateString(expiry_str)): histogram_entry['expires_after'] = expiry_str else: logging.error( - 'Expiry of histogram %s does not match expected date format: "%s"' - ' or milestone format: M* found %s.', name, EXPIRY_DATE_PATTERN, - expiry_str) + 'Expiry of histogram %s does not match expected date format ("%s"),' + ' milestone format (M*), or "never": found %s.', name, + EXPIRY_DATE_PATTERN, expiry_str) have_errors = True # Find <owner> tag.
diff --git a/tools/metrics/histograms/generate_expired_histograms_array.py b/tools/metrics/histograms/generate_expired_histograms_array.py index bbf283f..a122247 100755 --- a/tools/metrics/histograms/generate_expired_histograms_array.py +++ b/tools/metrics/histograms/generate_expired_histograms_array.py
@@ -67,6 +67,8 @@ if "obsolete" in content or "expires_after" not in content: continue expiry_str = content["expires_after"] + if expiry_str == "never": + continue match = _MILESTONE_EXPIRY_RE.search(expiry_str) if match:
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 2a21f6d..3f9e971 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -1945,7 +1945,7 @@ </histogram> <histogram name="Android.DownloadManager.ViewRetentionTime.Audio" - units="minutes"> + units="minutes" expires_after="2020-01-30"> <owner>xingliu@chromium.org</owner> <summary> The duration between when an audio file is downloaded and when the file is @@ -1954,7 +1954,7 @@ </histogram> <histogram name="Android.DownloadManager.ViewRetentionTime.Video" - units="minutes" expires_after="2019-01-30"> + units="minutes" expires_after="2020-01-30"> <owner>xingliu@chromium.org</owner> <summary> The duration between when a video file is downloaded and when the file is @@ -1962,6 +1962,19 @@ </summary> </histogram> +<histogram base="true" name="Android.FeatureModules.InstallStatus" + enum="FeatureModuleInstallStatus"> +<!-- Name completed by histogram_suffixes + name="AndroidFeatureModuleName" --> + + <owner>tiborg@chromium.org</owner> + <owner>agrieve@chromium.org</owner> + <summary> + Install status for each dynamic feature module. Recorded after the + installation has finished. + </summary> +</histogram> + <histogram name="Android.HistoryPage.OpenSelected"> <owner>twellington@chromium.org</owner> <summary> @@ -16555,9 +16568,9 @@ </histogram> <histogram name="ContentSettings.PermissionRequested" enum="PermissionType"> - <owner>kcarattini@chromium.org</owner> <owner>dominickn@chromium.org</owner> - <owner>miguelg@chromium.org</owner> + <owner>engedy@chromium.org</owner> + <owner>hkamila@chromium.org</owner> <summary> Number of times a given permission was requested by a website and the user has the permission set to prompt (i.e. not blocked or allowed). @@ -16578,9 +16591,9 @@ <histogram name="ContentSettings.PermissionRequested_InsecureOrigin" enum="PermissionType"> - <owner>kcarattini@chromium.org</owner> <owner>dominickn@chromium.org</owner> - <owner>miguelg@chromium.org</owner> + <owner>engedy@chromium.org</owner> + <owner>hkamila@chromium.org</owner> <summary> Number of times a given permission was requested by an insecure origin and the user has the permission set to prompt (i.e. not blocked or allowed). @@ -16601,9 +16614,9 @@ <histogram name="ContentSettings.PermissionRequested_SecureOrigin" enum="PermissionType"> - <owner>kcarattini@chromium.org</owner> <owner>dominickn@chromium.org</owner> - <owner>miguelg@chromium.org</owner> + <owner>engedy@chromium.org</owner> + <owner>hkamila@chromium.org</owner> <summary> Number of times a given permission was requested by a secure origin and the user has the permission set to prompt (i.e. not blocked or allowed). @@ -23512,6 +23525,16 @@ </summary> </histogram> +<histogram name="DomainBoundCerts.DBExists" enum="BooleanExists" + expires_after="M77"> + <owner>nharper@chromium.org</owner> + <summary> + Tracks whether the "Origin Bound Certs" file exists in a profile. + Logged each time the network context params are created for a profile, which + should happen approximately once per session for a profile. + </summary> +</histogram> + <histogram name="DomainBoundCerts.DBLoadedCount"> <obsolete> Removed January 2018. @@ -24512,7 +24535,8 @@ </summary> </histogram> -<histogram name="Download.DeleteRetentionTime.Audio" units="hours"> +<histogram name="Download.DeleteRetentionTime.Audio" units="hours" + expires_after="2020-01-30"> <owner>xingliu@chromium.org</owner> <summary> How long users keep downloaded audio files on disk. Recorded when the @@ -24521,7 +24545,7 @@ </histogram> <histogram name="Download.DeleteRetentionTime.Video" units="hours" - expires_after="2019-01-30"> + expires_after="2020-01-30"> <owner>xingliu@chromium.org</owner> <summary> How long users keep downloaded video files on disk. Recorded when the @@ -25102,7 +25126,7 @@ </histogram> <histogram name="Download.ParallelDownloadAddStreamSuccess" - enum="BooleanSuccess" expires_after="2019-01-30"> + enum="BooleanSuccess" expires_after="2020-01-30"> <owner>xingliu@chromium.org</owner> <summary> Records if the byte stream reader of a subsequent request is successfully @@ -25111,7 +25135,7 @@ </histogram> <histogram name="Download.ParallelDownloadRequestCount" units="requests" - expires_after="2019-01-30"> + expires_after="2020-01-30"> <owner>xingliu@chromium.org</owner> <summary> The total number of requests sent for a parallel download, including the @@ -53041,6 +53065,17 @@ <summary>Android: The number of system installed browsers.</summary> </histogram> +<histogram name="Mobile.SystemNotification.Action.Click" + enum="SystemNotificationActionType" expires_after="2020-01-22"> + <owner>dtrainor@chromium.org</owner> + <owner>xingliu@chromium.org</owner> + <summary> + Records which Android notifications users interact with. Recorded when an + user taps the button in a notification, for any Chrome-generated + notification on Android that includes a button tap-target. + </summary> +</histogram> + <histogram name="Mobile.SystemNotification.Blocked" enum="SystemNotificationType"> <owner>dtrainor@chromium.org</owner> @@ -77397,6 +77432,11 @@ </histogram> <histogram name="PageLoad.InteractiveTiming.FirstInputDelay" units="ms"> + <obsolete> + Deprecated on January 2019 in favor of + PageLoad.InteractiveTiming.FirstInputDelay2, which correctly excludes some + scrolling cases that were previously not excluded from this metric. + </obsolete> <owner>tdresser@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary> @@ -77410,7 +77450,27 @@ </summary> </histogram> +<histogram name="PageLoad.InteractiveTiming.FirstInputDelay2" units="ms" + expires_after="2020-01-23"> + <owner>tdresser@chromium.org</owner> + <owner>speed-metrics-dev@chromium.org</owner> + <summary> + Measures First Input Delay, the duration between the hardware timestamp and + the start of event processing on the main thread for the first meaningful + input per navigation. See https://goo.gl/tr1oTZ for a detailed explanation. + Excludes scrolls. In ms. + + Do not modify this metric in any way without contacting + speed-metrics-dev@chromium.org. + </summary> +</histogram> + <histogram name="PageLoad.InteractiveTiming.FirstInputTimestamp" units="ms"> + <obsolete> + Deprecated on January 2019 in favor of + PageLoad.InteractiveTiming.FirstInputTimestamp2, which correctly excludes + some scrolling cases that were previously not excluded from this metric. + </obsolete> <owner>tdresser@chromium.org</owner> <summary> The duration between navigation start and the hardware timestamp of the @@ -77419,7 +77479,23 @@ </summary> </histogram> +<histogram name="PageLoad.InteractiveTiming.FirstInputTimestamp2" units="ms" + expires_after="2020-01-23"> + <owner>tdresser@chromium.org</owner> + <owner>speed-metrics-dev@chromium.org</owner> + <summary> + The duration between navigation start and the hardware timestamp of the + first meaningful input per navigation. See https://goo.gl/tr1oTZ for a + detailed explanation. Excludes scrolls. In ms. + </summary> +</histogram> + <histogram name="PageLoad.InteractiveTiming.InputDelay" units="ms"> + <obsolete> + Deprecated on January 2019 in favor of + PageLoad.InteractiveTiming.InputDelay2, which correctly excludes some + scrolling cases that were previously not excluded from this metric. + </obsolete> <owner>tdresser@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary> @@ -77431,7 +77507,26 @@ </summary> </histogram> +<histogram name="PageLoad.InteractiveTiming.InputDelay2" units="ms" + expires_after="2020-01-23"> + <owner>tdresser@chromium.org</owner> + <owner>speed-metrics-dev@chromium.org</owner> + <summary> + The duration between the hardware timestamp and the start of event + processing on the main thread for a meaningful input. Excludes scrolls. In + ms. + + Do not modify this metric in any way without contacting + speed-metrics-dev@chromium.org. + </summary> +</histogram> + <histogram name="PageLoad.InteractiveTiming.InputTimestamp" units="ms"> + <obsolete> + Deprecated on January 2019 in favor of + PageLoad.InteractiveTiming.InputTimestamp2, which correctly excludes some + scrolling cases that were previously not excluded from this metric. + </obsolete> <owner>tdresser@chromium.org</owner> <summary> The duration between navigation start and the hardware timestamp of a @@ -77439,7 +77534,22 @@ </summary> </histogram> +<histogram name="PageLoad.InteractiveTiming.InputTimestamp2" units="ms" + expires_after="2020-01-23"> + <owner>tdresser@chromium.org</owner> + <owner>speed-metrics-dev@chromium.org</owner> + <summary> + The duration between navigation start and the hardware timestamp of a + meaningful input. Excludes scrolls. In ms. + </summary> +</histogram> + <histogram name="PageLoad.InteractiveTiming.LongestInputDelay" units="ms"> + <obsolete> + Deprecated on January 2019 in favor of + PageLoad.InteractiveTiming.LongestInputDelay2, which correctly excludes some + scrolling cases that were previously not excluded from this metric. + </obsolete> <owner>tdresser@chromium.org</owner> <summary> Measures longest Input Delay, the longest duration between the hardware @@ -77448,7 +77558,23 @@ </summary> </histogram> +<histogram name="PageLoad.InteractiveTiming.LongestInputDelay2" units="ms" + expires_after="2020-01-23"> + <owner>tdresser@chromium.org</owner> + <owner>speed-metrics-dev@chromium.org</owner> + <summary> + Measures longest Input Delay, the longest duration between the hardware + timestamp and the start of event processing on the main thread for the + meaningful input per navigation. Excludes scrolls. In ms. + </summary> +</histogram> + <histogram name="PageLoad.InteractiveTiming.LongestInputTimestamp" units="ms"> + <obsolete> + Deprecated on January 2019 in favor of + PageLoad.InteractiveTiming.LongestInputTimestamp2, which correctly excludes + some scrolling cases that were previously not excluded from this metric. + </obsolete> <owner>tdresser@chromium.org</owner> <summary> The duration between navigation start and the hardware timestamp of the @@ -77456,6 +77582,17 @@ </summary> </histogram> +<histogram name="PageLoad.InteractiveTiming.LongestInputTimestamp2" units="ms" + expires_after="2020-01-23"> + <owner>tdresser@chromium.org</owner> + <owner>speed-metrics-dev@chromium.org</owner> + <summary> + The duration between navigation start and the hardware timestamp of the + meaningful input with longest queuing delay per navigation. Excludes + scrolls. In ms. + </summary> +</histogram> + <histogram name="PageLoad.Internal.ClientRedirect.FirstPaintToNavigation" units="ms"> <owner>bmcquade@chromium.org</owner> @@ -81317,8 +81454,8 @@ <histogram name="Permissions.Action" enum="PermissionAction"> <owner>dominickn@chromium.org</owner> - <owner>kcarattini@chromium.org</owner> - <owner>miguelg@chromium.org</owner> + <owner>engedy@chromium.org</owner> + <owner>hkamila@chromium.org</owner> <owner>mlamouri@chromium.org</owner> <summary> Tracks whether a permission was granted, rejected, etc. The suffix of the @@ -81328,8 +81465,8 @@ <histogram name="Permissions.Action.InsecureOrigin" enum="PermissionAction"> <owner>dominickn@chromium.org</owner> - <owner>kcarattini@chromium.org</owner> - <owner>miguelg@chromium.org</owner> + <owner>engedy@chromium.org</owner> + <owner>hkamila@chromium.org</owner> <owner>mlamouri@chromium.org</owner> <summary> Tracks whether a permission was granted, rejected, etc on an insecure @@ -81339,8 +81476,8 @@ <histogram name="Permissions.Action.SecureOrigin" enum="PermissionAction"> <owner>dominickn@chromium.org</owner> - <owner>kcarattini@chromium.org</owner> - <owner>miguelg@chromium.org</owner> + <owner>engedy@chromium.org</owner> + <owner>hkamila@chromium.org</owner> <owner>mlamouri@chromium.org</owner> <summary> Tracks whether a permission was granted, rejected, etc on a secure origin. @@ -94478,6 +94615,26 @@ </summary> </histogram> +<histogram name="SafeBrowsing.AndroidTelemetry.ApkDownload.IncompleteReason" + enum="ApkDownloadTelemetryIncompleteReason"> + <owner>vakh@chromium.org</owner> + <summary> + Records if the telemetry ping sent for APK download contained a full + referrer chain, or if there was an error collecting the referrer chain. + Logged each time a user opted into extended reporting downloads an APK file + from a normal window on Android. + </summary> +</histogram> + +<histogram name="SafeBrowsing.AndroidTelemetry.ApkDownload.Outcome" + enum="ApkDownloadTelemetryOutcome"> + <owner>vakh@chromium.org</owner> + <summary> + Records whether a telemetry ping for APK download was sent, or if not, then + why not. Logged each time a user downloads an APK file on Android. + </summary> +</histogram> + <histogram name="SafeBrowsing.ContentsSize.Height" units="DIPs" expires_after="M77"> <owner>chrome-safebrowsing-alerts@google.com</owner> @@ -94794,7 +94951,7 @@ <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> The length of referrer URL chain we get from referrer attribution. This is - incremented each time a safe browsing ping or download ping is generated. + logged each time a safe browsing ping or download ping is generated. </summary> </histogram> @@ -130225,6 +130382,12 @@ <affected-histogram name="Android.DownloadManager.InitialCount.Viewed"/> </histogram_suffixes> +<histogram_suffixes name="AndroidFeatureModuleName" separator="."> + <suffix name="ar" label="Augmented Reality Module"/> + <suffix name="vr" label="Virtual Reality Module"/> + <affected-histogram name="Android.FeatureModules.InstallStatus"/> +</histogram_suffixes> + <histogram_suffixes name="AndroidGATTEvents" separator="."> <suffix name="onCharacteristicRead.Status"/> <suffix name="onCharacteristicWrite.Status"/> @@ -134464,14 +134627,28 @@ <histogram_suffixes name="LevelDBClients" separator="."> <suffix name="BudgetManager" label="Database for storing budget information for origins."/> + <suffix name="CachedImageFetcherDatabase" + label="Database for CachedImageFetcher metadata."/> <suffix name="DomDistillerStore" label="Databases for DomDistillerStore"/> <suffix name="DownloadDB" label="Databases for in-progress download."/> <suffix name="FeatureEngagementTrackerAvailabilityStore" label="Database for FeatureEngagementTracker feature availability."/> <suffix name="FeatureEngagementTrackerEventStore" label="Database for FeatureEngagementTracker events."/> - <suffix name="FeedImageDatabase" label="Databases for Feed Image Loader."/> - <suffix name="FeedStorageDatabase" label="Databases for Feed Storage."/> + <suffix name="FeedContentDatabase" + label="Database for Feed content storage."/> + <suffix name="FeedImageDatabase" label="Databases for Feed Image Loader."> + <obsolete> + Deprecated since 11/18. + </obsolete> + </suffix> + <suffix name="FeedJournalDatabase" + label="Database for Feed journal storage."/> + <suffix name="FeedStorageDatabase" label="Databases for Feed Storage."> + <obsolete> + Deprecated since 08/18. + </obsolete> + </suffix> <suffix name="GCMKeyStore" label="Databases for GCMKeyStore"/> <suffix name="ImageManager" label="Databases for ImageManager"/> <suffix name="OfflinePageMetadataStore" @@ -134615,6 +134792,7 @@ <affected-histogram name="PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint"/> <affected-histogram name="PageLoad.InteractiveTiming.FirstInputDelay"/> + <affected-histogram name="PageLoad.InteractiveTiming.FirstInputDelay2"/> <affected-histogram name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/> </histogram_suffixes> @@ -138090,6 +138268,7 @@ name="PageLoad.Experimental.AbortTiming.Stop.AfterPaint.BeforeInteraction"/> <affected-histogram name="PageLoad.Experimental.AbortTiming.Stop.BeforeCommit"/> + <affected-histogram name="PageLoad.InteractiveTiming.FirstInputDelay2"/> <affected-histogram name="PageLoad.PageTiming.ForegroundDuration"/> <affected-histogram name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/> @@ -138383,6 +138562,7 @@ <affected-histogram name="PageLoad.Experimental.PaintTiming.ParseStartToFirstMeaningfulPaint"/> <affected-histogram name="PageLoad.InteractiveTiming.FirstInputDelay"/> + <affected-histogram name="PageLoad.InteractiveTiming.FirstInputDelay2"/> <affected-histogram name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/> <affected-histogram name="PageLoad.PaintTiming.NavigationToFirstPaint"/> @@ -138583,6 +138763,7 @@ <affected-histogram name="PageLoad.Experimental.PaintTiming.ParseStartToFirstMeaningfulPaint"/> <affected-histogram name="PageLoad.InteractiveTiming.FirstInputDelay"/> + <affected-histogram name="PageLoad.InteractiveTiming.FirstInputDelay2"/> <affected-histogram name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/> <affected-histogram name="PageLoad.PaintTiming.NavigationToFirstPaint"/> @@ -139945,6 +140126,8 @@ </histogram_suffixes> <histogram_suffixes name="ReferrerAttribution" separator="."> + <suffix name="ApkDownloadTelemetry" + label="APK downloads referrer attribution."/> <suffix name="DownloadAttribution" label="Download referrer attribution."/> <suffix name="MalwareInterstitialAttribution" label="Malware interstitial referrer attribution."/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index b08a157..79230c4c 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -3436,6 +3436,26 @@ </summary> </metric> <metric name="InteractiveTiming.FirstInputDelay"> + <obsolete> + Deprecated on January 2019 in favor of InteractiveTiming.FirstInputDelay2, + which correctly excludes some scrolling cases that were previously not + excluded from this metric. + </obsolete> + <summary> + Measures First Input Delay, the duration between the hardware timestamp + and the start of event processing on the main thread for the first + meaningful input per navigation. See https://goo.gl/tr1oTZ for a detailed + explanation. In ms. + </summary> + <aggregation> + <history> + <statistics> + <quantiles type="std-percentiles"/> + </statistics> + </history> + </aggregation> + </metric> + <metric name="InteractiveTiming.FirstInputDelay2"> <summary> Measures First Input Delay, the duration between the hardware timestamp and the start of event processing on the main thread for the first @@ -3451,6 +3471,18 @@ </aggregation> </metric> <metric name="InteractiveTiming.FirstInputTimestamp"> + <obsolete> + Deprecated on January 2019 in favor of + InteractiveTiming.FirstInputTimestamp2, which correctly excludes some + scrolling cases that were previously not excluded from this metric. + </obsolete> + <summary> + The duration between navigation start and the hardware timestamp of the + first meaningful input per navigation. See https://goo.gl/tr1oTZ for a + detailed explanation. In ms. + </summary> + </metric> + <metric name="InteractiveTiming.FirstInputTimestamp2"> <summary> The duration between navigation start and the hardware timestamp of the first meaningful input per navigation. See https://goo.gl/tr1oTZ for a @@ -3458,6 +3490,18 @@ </summary> </metric> <metric name="InteractiveTiming.LongestInputDelay"> + <obsolete> + Deprecated on January 2019 in favor of + InteractiveTiming.LongestInputDelay2, which correctly excludes some + scrolling cases that were previously not excluded from this metric. + </obsolete> + <summary> + Measures longest Input Delay, the longest duration between the hardware + timestamp and the start of event processing on the main thread for the + meaningful input per navigation. In ms. + </summary> + </metric> + <metric name="InteractiveTiming.LongestInputDelay2"> <summary> Measures longest Input Delay, the longest duration between the hardware timestamp and the start of event processing on the main thread for the @@ -3465,6 +3509,17 @@ </summary> </metric> <metric name="InteractiveTiming.LongestInputTimestamp"> + <obsolete> + Deprecated on January 2019 in favor of + InteractiveTiming.LongestInputTimestamp2, which correctly excludes some + scrolling cases that were previously not excluded from this metric. + </obsolete> + <summary> + The duration between navigation start and the hardware timestamp of the + meaningful input with longest queuing delay per navigation. In ms. + </summary> + </metric> + <metric name="InteractiveTiming.LongestInputTimestamp2"> <summary> The duration between navigation start and the hardware timestamp of the meaningful input with longest queuing delay per navigation. In ms.
diff --git a/tools/nocompile_driver.py b/tools/nocompile_driver.py index 33bb4efa..fedb351 100755 --- a/tools/nocompile_driver.py +++ b/tools/nocompile_driver.py
@@ -20,6 +20,7 @@ import select import subprocess import sys +import tempfile import time @@ -89,7 +90,7 @@ assert type(sourcefile_path) is str assert type(cflags) is list for flag in cflags: - assert(type(flag) is str) + assert type(flag) is str assert type(resultfile_path) is str @@ -180,11 +181,12 @@ return test_configs -def StartTest(compiler, sourcefile_path, cflags, config): +def StartTest(compiler, sourcefile_path, tempfile_dir, cflags, config): """Start one negative compile test. Args: sourcefile_path: The path to the source file. + tempfile_dir: A directory to store temporary data from tests. cflags: An array of strings with all the CFLAGS to give to gcc. config: A dictionary describing the test. See ExtractTestConfigs for a description of the config format. @@ -221,12 +223,15 @@ cmdline.append('-D%s' % name) cmdline.extend(['-o', '/dev/null', '-c', '-x', 'c++', sourcefile_path]) + test_stdout = tempfile.TemporaryFile(dir=tempfile_dir) + test_stderr = tempfile.TemporaryFile(dir=tempfile_dir) - process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + process = subprocess.Popen(cmdline, stdout=test_stdout, stderr=test_stderr) now = time.time() return {'proc': process, 'cmdline': ' '.join(cmdline), + 'stdout': test_stdout, + 'stderr': test_stderr, 'name': name, 'suite_name': config['suite_name'], 'terminate_timeout': now + NCTEST_TERMINATE_TIMEOUT_SEC, @@ -301,6 +306,18 @@ suite_name, timings['started'], timings['results_processed'], total_secs, extract_secs, compile_secs, process_secs)) +def ExtractTestOutputAndCleanup(test): + """Test output is in temp files. Read those and delete them. + Returns: A tuple (stderr, stdout). + """ + outputs = [None, None] + for i, stream_name in ((0, "stdout"), (1, "stderr")): + stream = test[stream_name] + stream.seek(0) + outputs[i] = stream.read() + stream.close() + + return outputs def ProcessTestResult(resultfile, resultlog, test): """Interprets and logs the result of a test started by StartTest() @@ -310,11 +327,9 @@ resultlog: File object for the log file. test: The dictionary from StartTest() to process. """ - # Snap a copy of stdout and stderr into the test dictionary immediately - # cause we can only call this once on the Popen object, and lots of stuff - # below will want access to it. proc = test['proc'] - (stdout, stderr) = proc.communicate() + proc.wait() + (stdout, stderr) = ExtractTestOutputAndCleanup(test) if test['aborted_at'] != 0: FailTest(resultfile, test, "Compile timed out. Started %f ended %f." % @@ -369,10 +384,12 @@ # If we don't make progress for too long, assume the code is just dead. assert busy_loop_timeout > time.time() - # Select on the output pipes. + # Select on the output files to block until we have something to + # do. We ignore the return value from select and just poll all + # processes. read_set = [] for test in executing_tests.values(): - read_set.extend([test['proc'].stderr, test['proc'].stdout]) + read_set.extend([test['stdout'], test['stderr']]) select.select(read_set, [], read_set, NCTEST_TERMINATE_TIMEOUT_SEC) # Now attempt to process results. @@ -389,6 +406,12 @@ proc.kill() test['aborted_at'] = now + if len(finished_tests) == 0: + # We had output from some process but no process had + # finished. To avoid busy looping while waiting for a process to + # finish, insert a small 100 ms delay here. + time.sleep(0.1) + for test in finished_tests: del executing_tests[test['name']] return finished_tests @@ -438,6 +461,7 @@ test = StartTest( compiler, sourcefile_path, + os.path.dirname(resultfile_path), cflags, { 'name': 'NCTEST_SANITY', 'suite_name': suite_name, @@ -455,7 +479,8 @@ if config['name'].startswith('DISABLED_'): PassTest(resultfile, resultlog, config) else: - test = StartTest(compiler, sourcefile_path, cflags, config) + test = StartTest(compiler, sourcefile_path, + os.path.dirname(resultfile_path), cflags, config) assert test['name'] not in executing_tests executing_tests[test['name']] = test @@ -468,8 +493,9 @@ finished_tests = sorted(finished_tests, key=lambda test: test['name']) for test in finished_tests: if test['name'] == 'NCTEST_SANITY': - stdout, stderr = test['proc'].communicate() - return_code = test['proc'].poll() + test['proc'].wait() + (stdout, stderr) = ExtractTestOutputAndCleanup(test) + return_code = test['proc'].returncode if return_code != 0: sys.stdout.write(stdout) sys.stderr.write(stderr)
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn index 69a6c950..8870c51 100644 --- a/ui/accessibility/BUILD.gn +++ b/ui/accessibility/BUILD.gn
@@ -17,16 +17,13 @@ import("//build/config/android/rules.gni") } -mojom("ax_enums_mojo") { +mojom_component("ax_enums_mojo") { sources = [ "ax_enums.mojom", ] - public_deps = [ - "//mojo/public/mojom/base", - "//ui/gfx/geometry/mojo", - "//ui/gfx/mojo", - ] + macro_prefix = "UI_ACCESSIBILITY_AX_MOJOM" + output_prefix = "ui_accessibility_ax_mojom" } jumbo_component("accessibility") {
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc index b55785e..8f30c5b 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -10,7 +10,6 @@ #include <memory> #include <set> #include <string> -#include <unordered_map> #include <utility> #include <vector> @@ -743,7 +742,8 @@ return nullptr; int32_t id = ax_hypertext.hyperlinks[index]; - auto* link = AXPlatformNodeAuraLinux::GetFromUniqueId(id); + auto* link = static_cast<AXPlatformNodeAuraLinux*>( + AXPlatformNodeBase::GetFromUniqueId(id)); if (!link) return nullptr; @@ -1470,22 +1470,6 @@ return AtkObjectToAXPlatformNodeAuraLinux(accessible); } -using UniqueIdMap = std::unordered_map<int32_t, AXPlatformNodeAuraLinux*>; -// Map from each AXPlatformNode's unique id to its instance. -base::LazyInstance<UniqueIdMap>::Leaky g_unique_id_map = - LAZY_INSTANCE_INITIALIZER; - -// static -AXPlatformNodeAuraLinux* AXPlatformNodeAuraLinux::GetFromUniqueId( - int32_t unique_id) { - UniqueIdMap* unique_ids = g_unique_id_map.Pointer(); - auto iter = unique_ids->find(unique_id); - if (iter != unique_ids->end()) - return iter->second; - - return nullptr; -} - // // AXPlatformNodeAuraLinux implementation. // @@ -2105,8 +2089,6 @@ } void AXPlatformNodeAuraLinux::Destroy() { - g_unique_id_map.Get().erase(GetUniqueId()); - DestroyAtkObjects(); AXPlatformNodeBase::Destroy(); } @@ -2114,7 +2096,6 @@ void AXPlatformNodeAuraLinux::Init(AXPlatformNodeDelegate* delegate) { // Initialize ATK. AXPlatformNodeBase::Init(delegate); - g_unique_id_map.Get()[GetUniqueId()] = this; DataChanged(); }
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.h b/ui/accessibility/platform/ax_platform_node_auralinux.h index 429ec727..af70b46 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.h +++ b/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -65,8 +65,6 @@ gint* x, gint* y, gint* width, gint* height, AtkCoordType coord_type); - static AXPlatformNodeAuraLinux* GetFromUniqueId(int32_t unique_id); - // AtkDocument helpers const gchar* GetDocumentAttributeValue(const gchar* attribute) const; AtkAttributeSet* GetDocumentAttributes() const;
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc index 7d9ffb2..bbe67573 100644 --- a/ui/accessibility/platform/ax_platform_node_base.cc +++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -5,6 +5,7 @@ #include "ui/accessibility/platform/ax_platform_node_base.h" #include <string> +#include <unordered_map> #include <utility> #include <vector> @@ -24,6 +25,11 @@ const base::char16 AXPlatformNodeBase::kEmbeddedCharacter = L'\xfffc'; +// Map from each AXPlatformNode's unique id to its instance. +using UniqueIdMap = std::unordered_map<int32_t, AXPlatformNode*>; +base::LazyInstance<UniqueIdMap>::Leaky g_unique_id_map = + LAZY_INSTANCE_INITIALIZER; + #if !BUILDFLAG_INTERNAL_HAS_NATIVE_ACCESSIBILITY() // static AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) { @@ -33,12 +39,30 @@ } #endif +// static +AXPlatformNode* AXPlatformNodeBase::GetFromUniqueId(int32_t unique_id) { + UniqueIdMap* unique_ids = g_unique_id_map.Pointer(); + auto iter = unique_ids->find(unique_id); + if (iter != unique_ids->end()) + return iter->second; + + return nullptr; +} + +// static +size_t AXPlatformNodeBase::GetInstanceCountForTesting() { + return g_unique_id_map.Get().size(); +} + AXPlatformNodeBase::AXPlatformNodeBase() = default; AXPlatformNodeBase::~AXPlatformNodeBase() = default; void AXPlatformNodeBase::Init(AXPlatformNodeDelegate* delegate) { delegate_ = delegate; + + // This must be called after assigning our delegate. + g_unique_id_map.Get()[GetUniqueId()] = this; } const AXNodeData& AXPlatformNodeBase::GetData() const { @@ -79,7 +103,10 @@ // AXPlatformNode overrides. void AXPlatformNodeBase::Destroy() { + g_unique_id_map.Get().erase(GetUniqueId()); + AXPlatformNode::Destroy(); + delegate_ = nullptr; Dispose(); }
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h index 6f11108..0b89a8f8 100644 --- a/ui/accessibility/platform/ax_platform_node_base.h +++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -199,6 +199,12 @@ // child object appears. static const base::char16 kEmbeddedCharacter; + // Get a node given its unique id or null in the case that the id is unknown. + static AXPlatformNode* GetFromUniqueId(int32_t unique_id); + + // Return the number of instances of AXPlatformNodeBase, for leak testing. + static size_t GetInstanceCountForTesting(); + // // Delegate. This is a weak reference which owns |this|. //
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index 4a4bbf7b..0984d31 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -10,7 +10,6 @@ #include <map> #include <set> #include <string> -#include <unordered_map> #include <unordered_set> #include <utility> #include <vector> @@ -251,20 +250,6 @@ return ax_platform_node.Get(); } -using UniqueIdMap = std::unordered_map<int32_t, AXPlatformNode*>; -// Map from each AXPlatformNode's unique id to its instance. -base::LazyInstance<UniqueIdMap>::Leaky g_unique_id_map = - LAZY_INSTANCE_INITIALIZER; - -// static -AXPlatformNode* AXPlatformNodeWin::GetFromUniqueId(int32_t unique_id) { - UniqueIdMap* unique_ids = g_unique_id_map.Pointer(); - auto iter = unique_ids->find(unique_id); - if (iter != unique_ids->end()) - return iter->second; - - return nullptr; -} // // AXPlatformNodeWin // @@ -277,12 +262,6 @@ void AXPlatformNodeWin::Init(AXPlatformNodeDelegate* delegate) { AXPlatformNodeBase::Init(delegate); - g_unique_id_map.Get()[GetUniqueId()] = this; -} - -// static -size_t AXPlatformNodeWin::GetInstanceCountForTesting() { - return g_unique_id_map.Get().size(); } void AXPlatformNodeWin::ClearOwnRelations() { @@ -471,8 +450,6 @@ } void AXPlatformNodeWin::Destroy() { - g_unique_id_map.Get().erase(GetUniqueId()); - RemoveAlertTarget(); // This will end up calling Dispose() which may result in deleting this object
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h index aa5603e..130b5c8 100644 --- a/ui/accessibility/platform/ax_platform_node_win.h +++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -273,14 +273,10 @@ ~AXPlatformNodeWin() override; - // Return the number of instances of AXPlatformNodeWin, for leak testing. - static size_t GetInstanceCountForTesting(); - void Init(AXPlatformNodeDelegate* delegate) override; // Clear any AXPlatformRelationWin nodes owned by this node. void ClearOwnRelations(); - static AXPlatformNode* GetFromUniqueId(int32_t unique_id); // AXPlatformNode overrides. gfx::NativeViewAccessible GetNativeViewAccessible() override;
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc index 5f8d90a..ca1f0eb3 100644 --- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -15,6 +15,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/iaccessible2/ia2_api_all.h" #include "ui/accessibility/ax_node_data.h" +#include "ui/accessibility/platform/ax_platform_node_base.h" #include "ui/accessibility/platform/ax_platform_node_unittest.h" #include "ui/accessibility/platform/ax_platform_node_win.h" #include "ui/accessibility/platform/test_ax_node_wrapper.h" @@ -91,7 +92,7 @@ void TearDown() override { // Destroy the tree and make sure we're not leaking any objects. tree_.reset(nullptr); - ASSERT_EQ(0U, AXPlatformNodeWin::GetInstanceCountForTesting()); + ASSERT_EQ(0U, AXPlatformNodeBase::GetInstanceCountForTesting()); } protected:
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn index b9d88cf..c7ff98a 100644 --- a/ui/aura/BUILD.gn +++ b/ui/aura/BUILD.gn
@@ -38,6 +38,7 @@ "local/window_port_local.h", "mus/capture_synchronizer.h", "mus/capture_synchronizer_delegate.h", + "mus/client_side_window_move_handler.h", "mus/client_surface_embedder.h", "mus/drag_drop_controller_host.h", "mus/drag_drop_controller_mus.h", @@ -115,6 +116,7 @@ "mouse_location_manager.cc", "mouse_location_manager.h", "mus/capture_synchronizer.cc", + "mus/client_side_window_move_handler.cc", "mus/client_surface_embedder.cc", "mus/drag_drop_controller_mus.cc", "mus/embed_root.cc", @@ -124,6 +126,8 @@ "mus/in_flight_change.cc", "mus/input_method_mus.cc", "mus/mus_context_factory.cc", + "mus/mus_lsi_allocator.cc", + "mus/mus_lsi_allocator.h", "mus/mus_mouse_location_updater.cc", "mus/os_exchange_data_provider_mus.cc", "mus/property_converter.cc", @@ -161,6 +165,7 @@ friend = [ ":aura_interactive_ui_tests", ":aura_unittests", + ":test_support", ] defines = [ "AURA_IMPLEMENTATION" ]
diff --git a/ui/aura/client/aura_constants.cc b/ui/aura/client/aura_constants.cc index 87bafb77..afc117d 100644 --- a/ui/aura/client/aura_constants.cc +++ b/ui/aura/client/aura_constants.cc
@@ -52,6 +52,7 @@ DEFINE_UI_CLASS_PROPERTY_KEY(bool, kDrawAttentionKey, false); DEFINE_UI_CLASS_PROPERTY_KEY(FocusClient*, kFocusClientKey, nullptr); DEFINE_UI_CLASS_PROPERTY_KEY(Window*, kHostWindowKey, nullptr); +DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Size, kMaximumSize, nullptr); DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Size, kMinimumSize, nullptr); DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::vector<Window*>, kMirrorWindowList,
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h index 8334cb3f..b142ac2 100644 --- a/ui/aura/client/aura_constants.h +++ b/ui/aura/client/aura_constants.h
@@ -86,6 +86,9 @@ // WebContentsViews find the windows that should constrain NPAPI plugins. AURA_EXPORT extern const WindowProperty<Window*>* const kHostWindowKey; +// A property key to store the maximum size of the window. +AURA_EXPORT extern const WindowProperty<gfx::Size*>* const kMaximumSize; + // A property key to store the minimum size of the window. AURA_EXPORT extern const WindowProperty<gfx::Size*>* const kMinimumSize;
diff --git a/ui/aura/mus/client_side_window_move_handler.cc b/ui/aura/mus/client_side_window_move_handler.cc new file mode 100644 index 0000000..bc37be5 --- /dev/null +++ b/ui/aura/mus/client_side_window_move_handler.cc
@@ -0,0 +1,115 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura/mus/client_side_window_move_handler.h" + +#include "base/bind.h" +#include "ui/aura/client/screen_position_client.h" +#include "ui/aura/env.h" +#include "ui/aura/mus/window_tree_host_mus.h" +#include "ui/aura/window.h" +#include "ui/aura/window_delegate.h" +#include "ui/base/hit_test.h" +#include "ui/events/event.h" +#include "ui/events/gestures/gesture_recognizer.h" + +namespace aura { + +namespace { + +void WindowMoveEnded(Window* window, bool success) { + window->env()->gesture_recognizer()->CancelActiveTouches(window); +} + +} // namespace + +ClientSideWindowMoveHandler::ClientSideWindowMoveHandler(Env* env) : env_(env) { + env_->AddPreTargetHandler(this); +} + +ClientSideWindowMoveHandler::~ClientSideWindowMoveHandler() { + env_->RemovePreTargetHandler(this); +} + +void ClientSideWindowMoveHandler::MaybeSetupLastTarget( + ui::LocatedEvent* event) { + last_target_.RemoveAll(); + Window* window = static_cast<Window*>(event->target()); + if (!window || !window->delegate()) + return; + int component = window->delegate()->GetNonClientComponent(event->location()); + + // TODO(mukai): add the support of window resizing components like HTTOP. + if (component != HTCAPTION) + return; + + last_target_.Add(window); + last_location_ = event->location(); +} + +void ClientSideWindowMoveHandler::MaybePerformWindowMove( + ui::LocatedEvent* event, + ws::mojom::MoveLoopSource source) { + Window* target = static_cast<Window*>(event->target()); + if (!target || !last_target_.Contains(target) || !target->delegate()) + return; + + gfx::Point screen_location = last_location_; + aura::client::GetScreenPositionClient(target->GetRootWindow()) + ->ConvertPointToScreen(target, &screen_location); + WindowTreeHostMus::ForWindow(target)->PerformWindowMove( + target, source, screen_location, + base::BindOnce(&WindowMoveEnded, target)); + + // Clear |last_target_| so that event->target() won't match with + // |last_target_| anymore. + last_target_.RemoveAll(); + event->SetHandled(); +} + +void ClientSideWindowMoveHandler::OnMouseEvent(ui::MouseEvent* event) { + // The logic here should be aligned with ash::WmToplevelWindowEventHandler. + // TODO(mukai): create a common class in ash/public/cpp to share the logic. + if (event->handled()) + return; + if ((event->flags() & + (ui::EF_MIDDLE_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON)) != 0) { + return; + } + switch (event->type()) { + case ui::ET_MOUSE_PRESSED: + MaybeSetupLastTarget(event); + break; + + case ui::ET_MOUSE_DRAGGED: + MaybePerformWindowMove(event, ws::mojom::MoveLoopSource::MOUSE); + break; + + default: + // Do nothing. + break; + } +} + +void ClientSideWindowMoveHandler::OnGestureEvent(ui::GestureEvent* event) { + // The logic here should be aligned with ash::WmToplevelWindowEventHandler. + // TODO(mukai): create a common class in ash/public/cpp to share the logic. + if (event->handled()) + return; + switch (event->type()) { + case ui::ET_GESTURE_TAP_DOWN: + MaybeSetupLastTarget(event); + return; + + case ui::ET_GESTURE_SCROLL_UPDATE: + MaybePerformWindowMove(event, ws::mojom::MoveLoopSource::TOUCH); + break; + + default: + // Do nothing. + break; + } +} + +} // namespace aura
diff --git a/ui/aura/mus/client_side_window_move_handler.h b/ui/aura/mus/client_side_window_move_handler.h new file mode 100644 index 0000000..c1cbb41 --- /dev/null +++ b/ui/aura/mus/client_side_window_move_handler.h
@@ -0,0 +1,49 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_MUS_CLIENT_SIDE_WINDOW_MOVE_HANDLER_H_ +#define UI_AURA_MUS_CLIENT_SIDE_WINDOW_MOVE_HANDLER_H_ + +#include "services/ws/public/mojom/window_tree_constants.mojom.h" +#include "ui/aura/window_tracker.h" +#include "ui/events/event_handler.h" + +namespace ui { +class LocatedEvent; +} + +namespace aura { + +class Env; + +// ClientSideWindowMoveHandler handles mouse/gesture events and performs the +// window move session when the event is located on draggable area. +class ClientSideWindowMoveHandler : public ui::EventHandler { + public: + explicit ClientSideWindowMoveHandler(Env* env); + ~ClientSideWindowMoveHandler() override; + + private: + // Setup |last_target_| and |last_location_| for |event|, or clear them when + // the event will not involve window move. + void MaybeSetupLastTarget(ui::LocatedEvent* event); + + // Conduct the window move. + void MaybePerformWindowMove(ui::LocatedEvent* event, + ws::mojom::MoveLoopSource source); + + // ui::EventHandler: + void OnMouseEvent(ui::MouseEvent* event) override; + void OnGestureEvent(ui::GestureEvent* event) override; + + Env* env_; + WindowTracker last_target_; + gfx::Point last_location_; + + DISALLOW_COPY_AND_ASSIGN(ClientSideWindowMoveHandler); +}; + +} // namespace aura + +#endif // UI_AURA_MUS_CLIENT_SIDE_WINDOW_MOVE_HANDLER_H_
diff --git a/ui/aura/mus/mus_lsi_allocator.cc b/ui/aura/mus/mus_lsi_allocator.cc new file mode 100644 index 0000000..4c6da346 --- /dev/null +++ b/ui/aura/mus/mus_lsi_allocator.cc
@@ -0,0 +1,115 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura/mus/mus_lsi_allocator.h" + +#include <utility> + +#include "components/viz/common/surfaces/scoped_surface_id_allocator.h" +#include "components/viz/common/surfaces/surface_id.h" +#include "ui/aura/mus/client_surface_embedder.h" +#include "ui/aura/mus/window_port_mus.h" +#include "ui/aura/mus/window_tree_client.h" + +namespace aura { + +ParentAllocator::ParentAllocator(MusLsiAllocatorType type, + WindowPortMus* window, + WindowTreeClient* window_tree_client) + : MusLsiAllocator(type), + window_(window), + window_tree_client_(window_tree_client) { + DCHECK(window_); + DCHECK(window_tree_client_); + if (type == MusLsiAllocatorType::kEmbed) { + client_surface_embedder_ = std::make_unique<ClientSurfaceEmbedder>( + GetWindow(), /* inject_gutter */ false, gfx::Insets()); + } +} + +ParentAllocator::~ParentAllocator() = default; + +void ParentAllocator::AllocateLocalSurfaceId() { + last_surface_size_in_pixels_ = window_->GetSizeInPixels(); + parent_local_surface_id_allocator_.GenerateId(); + Update(/* send_bounds_change */ true); +} + +viz::ScopedSurfaceIdAllocator ParentAllocator::GetSurfaceIdAllocator( + base::OnceClosure allocation_task) { + return viz::ScopedSurfaceIdAllocator(&parent_local_surface_id_allocator_, + std::move(allocation_task)); +} + +void ParentAllocator::InvalidateLocalSurfaceId() { + parent_local_surface_id_allocator_.Invalidate(); +} + +void ParentAllocator::UpdateLocalSurfaceIdFromEmbeddedClient( + const viz::LocalSurfaceIdAllocation& + embedded_client_local_surface_id_allocation) { + parent_local_surface_id_allocator_.UpdateFromChild( + embedded_client_local_surface_id_allocation); + // Ensure there is a valid value. + if (!GetLocalSurfaceIdAllocation().IsValid()) + parent_local_surface_id_allocator_.GenerateId(); + Update(/* send_bounds_change */ true); +} + +void ParentAllocator::OnDeviceScaleFactorChanged() { + parent_local_surface_id_allocator_.GenerateId(); + Update(/* send_bounds_change */ true); +} + +void ParentAllocator::OnDidChangeBounds(const gfx::Size& size_in_pixels, + bool from_server) { + if (last_surface_size_in_pixels_ == size_in_pixels && + parent_local_surface_id_allocator_.HasValidLocalSurfaceIdAllocation()) { + return; + } + + last_surface_size_in_pixels_ = size_in_pixels; + parent_local_surface_id_allocator_.GenerateId(); + // If |from_server| is true, then WindowPortMus sends a bound change. + Update(/* send_bounds_change */ from_server); +} + +const viz::LocalSurfaceIdAllocation& +ParentAllocator::GetLocalSurfaceIdAllocation() { + return parent_local_surface_id_allocator_ + .GetCurrentLocalSurfaceIdAllocation(); +} + +aura::Window* ParentAllocator::GetWindow() { + return static_cast<WindowMus*>(window_)->GetWindow(); +} + +void ParentAllocator::Update(bool send_bounds_change) { + // If not in a bounds change, then need to update server of new + // LocalSurfaceId. + if (send_bounds_change) { + const gfx::Rect& bounds = GetWindow()->bounds(); + window_tree_client_->OnWindowMusBoundsChanged(window_, bounds, bounds); + } + if (GetWindow()->IsEmbeddingClient() && client_surface_embedder_) { + viz::SurfaceId surface_id(GetWindow()->GetFrameSinkId(), + GetLocalSurfaceIdAllocation().local_surface_id()); + client_surface_embedder_->SetSurfaceId(surface_id); + client_surface_embedder_->UpdateSizeAndGutters(); + } +} + +void ParentAllocator::OnFrameSinkIdChanged() { + Update(/* send_bounds_change */ false); +} + +// static +std::unique_ptr<MusLsiAllocator> MusLsiAllocator::CreateAllocator( + MusLsiAllocatorType type, + WindowPortMus* window, + WindowTreeClient* window_tree_client) { + return std::make_unique<ParentAllocator>(type, window, window_tree_client); +} + +} // namespace aura
diff --git a/ui/aura/mus/mus_lsi_allocator.h b/ui/aura/mus/mus_lsi_allocator.h new file mode 100644 index 0000000..73dc6e5 --- /dev/null +++ b/ui/aura/mus/mus_lsi_allocator.h
@@ -0,0 +1,119 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_MUS_MUS_LSI_ALLOCATOR_H_ +#define UI_AURA_MUS_MUS_LSI_ALLOCATOR_H_ + +#include <memory> + +#include "base/callback_forward.h" +#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" +#include "ui/gfx/geometry/size.h" + +namespace gfx { +class Size; +} + +namespace viz { +class LocalSurfaceIdAllocation; +class ScopedSurfaceIdAllocator; +} // namespace viz + +namespace aura { + +class ClientSurfaceEmbedder; +class Window; +class WindowPortMus; +class WindowTreeClient; + +enum class MusLsiAllocatorType { + // The allocator was created by a window that has an embedding in it. This + // is the embedder side, *not* the embedding side. + kEmbed, + + // A local window that has a FrameSinkId associated with it. + kLocal, +}; + +// MusLsiAllocator is used by WindowPortMus to handle management of +// LocalSurfaceIdAllocation, and associated data. +class MusLsiAllocator { + public: + virtual ~MusLsiAllocator() {} + + static std::unique_ptr<MusLsiAllocator> CreateAllocator( + MusLsiAllocatorType type, + WindowPortMus* window, + WindowTreeClient* window_tree_client); + + MusLsiAllocatorType type() const { return type_; } + + virtual void AllocateLocalSurfaceId() = 0; + virtual viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator( + base::OnceClosure allocation_task) = 0; + virtual void InvalidateLocalSurfaceId() = 0; + virtual void UpdateLocalSurfaceIdFromEmbeddedClient( + const viz::LocalSurfaceIdAllocation& + embedded_client_local_surface_id_allocation) = 0; + virtual void OnDeviceScaleFactorChanged() = 0; + virtual void OnDidChangeBounds(const gfx::Size& size_in_pixels, + bool from_server) = 0; + virtual const viz::LocalSurfaceIdAllocation& + GetLocalSurfaceIdAllocation() = 0; + virtual void OnFrameSinkIdChanged() = 0; + + protected: + explicit MusLsiAllocator(MusLsiAllocatorType type) : type_(type) {} + + private: + const MusLsiAllocatorType type_; +}; + +// ParentAllocator is used for kEmbed and kLocal types of allocators. It uses +// a ParentLocalSurfaceIdAllocator to generate a LocalSurfaceIdAllocation. +// Additionally ParenAllocator may creates a ClientSurfaceEmbedder| to handle +// associating the FrameSinkId with Viz. +// +// This is an implementation detail and only public for tests to poke at. +class ParentAllocator : public MusLsiAllocator { + public: + ParentAllocator(MusLsiAllocatorType type, + WindowPortMus* window, + WindowTreeClient* window_tree_client); + ~ParentAllocator() override; + + // MusLsiAllocator: + void AllocateLocalSurfaceId() override; + viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator( + base::OnceClosure allocation_task) override; + void InvalidateLocalSurfaceId() override; + void UpdateLocalSurfaceIdFromEmbeddedClient( + const viz::LocalSurfaceIdAllocation& + embedded_client_local_surface_id_allocation) override; + void OnDeviceScaleFactorChanged() override; + void OnDidChangeBounds(const gfx::Size& size_in_pixels, + bool from_server) override; + const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation() override; + void OnFrameSinkIdChanged() override; + + private: + friend class WindowPortMusTestHelper; + + Window* GetWindow(); + + void Update(bool in_bounds_change); + + WindowPortMus* window_; + WindowTreeClient* window_tree_client_; + viz::ParentLocalSurfaceIdAllocator parent_local_surface_id_allocator_; + std::unique_ptr<ClientSurfaceEmbedder> client_surface_embedder_; + + // Last size (in pixels) that a LocalSurfaceId was generated for. + gfx::Size last_surface_size_in_pixels_; + + DISALLOW_COPY_AND_ASSIGN(ParentAllocator); +}; +} // namespace aura + +#endif // UI_AURA_MUS_MUS_LSI_ALLOCATOR_H_
diff --git a/ui/aura/mus/property_converter.cc b/ui/aura/mus/property_converter.cc index 86b43b0..0f1422424 100644 --- a/ui/aura/mus/property_converter.cc +++ b/ui/aura/mus/property_converter.cc
@@ -91,12 +91,16 @@ ws::mojom::WindowManager::kRestoreBounds_Property); RegisterSizeProperty(client::kPreferredSize, ws::mojom::WindowManager::kPreferredSize_Property); + RegisterSizeProperty(client::kMaximumSize, + ws::mojom::WindowManager::kMaximumSize_Property); RegisterSizeProperty(client::kMinimumSize, ws::mojom::WindowManager::kMinimumSize_Property); RegisterStringProperty(client::kNameKey, ws::mojom::WindowManager::kName_Property); RegisterString16Property(client::kTitleKey, ws::mojom::WindowManager::kWindowTitle_Property); + RegisterSizeFProperty(client::kAspectRatio, + ws::mojom::WindowManager::kAspectRatio_Property); RegisterPrimitiveProperty( client::kWindowCornerRadiusKey, ws::mojom::WindowManager::kWindowCornerRadius_Property, @@ -138,6 +142,11 @@ return size_property.first->name; } + for (const auto& size_f_property : size_f_properties_) { + if (size_f_property.second == transport_name) + return size_f_property.first->name; + } + for (const auto& string_property : string_properties_) { if (string_property.second == transport_name) return string_property.first->name; @@ -201,6 +210,12 @@ return true; } + auto* size_f_key = static_cast<const WindowProperty<gfx::SizeF*>*>(key); + if (size_f_properties_.count(size_f_key) > 0) { + *transport_value = GetArray(window, size_f_key); + return true; + } + auto* string_key = static_cast<const WindowProperty<std::string*>*>(key); if (string_properties_.count(string_key) > 0) { *transport_value = GetArray(window, string_key); @@ -254,6 +269,10 @@ if (size_properties_.count(size_key) > 0) return size_properties_[size_key]; + auto* size_f_key = static_cast<const WindowProperty<gfx::SizeF*>*>(key); + if (size_f_properties_.count(size_f_key) > 0) + return size_f_properties_[size_f_key]; + auto* string_key = static_cast<const WindowProperty<std::string*>*>(key); if (string_properties_.count(string_key) > 0) return string_properties_[string_key]; @@ -335,6 +354,18 @@ } } + for (const auto& size_f_property : size_f_properties_) { + if (size_f_property.second == transport_name) { + if (data->size() != 8u) { + DVLOG(2) << "Property size mismatch (gfx::Size): " << transport_name; + return; + } + const gfx::SizeF value = mojo::ConvertTo<gfx::SizeF>(*data); + window->SetProperty(size_f_property.first, new gfx::SizeF(value)); + return; + } + } + for (const auto& string_property : string_properties_) { if (string_property.second == transport_name) { // TODO(msw): Validate the data somehow, before trying to convert? @@ -436,6 +467,15 @@ transport_names_.insert(transport_name); } +void PropertyConverter::RegisterSizeFProperty( + const WindowProperty<gfx::SizeF*>* property, + const char* transport_name) { + DCHECK(!IsTransportNameRegistered(transport_name)) + << "Property already registered: " << transport_name; + size_f_properties_[property] = transport_name; + transport_names_.insert(transport_name); +} + void PropertyConverter::RegisterStringProperty( const WindowProperty<std::string*>* property, const char* transport_name) {
diff --git a/ui/aura/mus/property_converter.h b/ui/aura/mus/property_converter.h index 82650db1..099feea 100644 --- a/ui/aura/mus/property_converter.h +++ b/ui/aura/mus/property_converter.h
@@ -112,6 +112,8 @@ const char* transport_name); void RegisterSizeProperty(const WindowProperty<gfx::Size*>* property, const char* transport_name); + void RegisterSizeFProperty(const WindowProperty<gfx::SizeF*>* property, + const char* transport_name); void RegisterStringProperty(const WindowProperty<std::string*>* property, const char* transport_name); void RegisterString16Property(const WindowProperty<base::string16*>* property, @@ -165,6 +167,7 @@ image_properties_; std::map<const WindowProperty<gfx::Rect*>*, const char*> rect_properties_; std::map<const WindowProperty<gfx::Size*>*, const char*> size_properties_; + std::map<const WindowProperty<gfx::SizeF*>*, const char*> size_f_properties_; std::map<const WindowProperty<std::string*>*, const char*> string_properties_; std::map<const WindowProperty<base::string16*>*, const char*> string16_properties_;
diff --git a/ui/aura/mus/window_mus.h b/ui/aura/mus/window_mus.h index 817fceb..9562f0ff 100644 --- a/ui/aura/mus/window_mus.h +++ b/ui/aura/mus/window_mus.h
@@ -28,7 +28,6 @@ namespace viz { class FrameSinkId; -class LocalSurfaceId; } namespace aura { @@ -82,9 +81,7 @@ virtual void ReorderFromServer(WindowMus* child, WindowMus* relative, ws::mojom::OrderDirection) = 0; - virtual void SetBoundsFromServer( - const gfx::Rect& bounds, - const base::Optional<viz::LocalSurfaceId>& local_surface_id) = 0; + virtual void SetBoundsFromServer(const gfx::Rect& bounds) = 0; virtual void SetTransformFromServer(const gfx::Transform& transform) = 0; virtual void SetVisibleFromServer(bool visible) = 0; virtual void SetOpacityFromServer(float opacity) = 0; @@ -93,8 +90,6 @@ const std::vector<uint8_t>* data) = 0; virtual void SetFrameSinkIdFromServer( const viz::FrameSinkId& frame_sink_id) = 0; - virtual const viz::LocalSurfaceId& GetOrAllocateLocalSurfaceId( - const gfx::Size& new_size) = 0; // The window was deleted on the server side. DestroyFromServer() should // result in deleting |this|. virtual void DestroyFromServer() = 0; @@ -110,6 +105,9 @@ virtual const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation() = 0; + // Returns true if the window has a LocalSurfaceId. + virtual bool HasLocalSurfaceId() = 0; + // Called in the rare case when WindowTreeClient needs to change state and // can't go through one of the SetFooFromServer() functions above. Generally // because it needs to call another function that as a side effect changes the @@ -127,8 +125,6 @@ virtual void NotifyEmbeddedAppDisconnected() = 0; - virtual bool HasLocalLayerTreeFrameSink() = 0; - virtual float GetDeviceScaleFactor() = 0; private:
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc index 77fce249..88fd879d 100644 --- a/ui/aura/mus/window_port_mus.cc +++ b/ui/aura/mus/window_port_mus.cc
@@ -9,18 +9,20 @@ #include "base/auto_reset.h" #include "base/bind.h" #include "base/callback.h" +#include "base/no_destructor.h" #include "cc/mojo_embedder/async_layer_tree_frame_sink.h" #include "components/viz/client/hit_test_data_provider_draw_quad.h" #include "components/viz/client/local_surface_id_provider.h" #include "components/viz/common/features.h" #include "components/viz/common/surfaces/local_surface_id_allocation.h" +#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/host/host_frame_sink_manager.h" #include "services/ws/public/mojom/window_tree_constants.mojom.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/drag_drop_delegate.h" #include "ui/aura/client/transient_window_client.h" #include "ui/aura/env.h" -#include "ui/aura/mus/client_surface_embedder.h" +#include "ui/aura/mus/mus_lsi_allocator.h" #include "ui/aura/mus/property_converter.h" #include "ui/aura/mus/property_utils.h" #include "ui/aura/mus/window_tree_client.h" @@ -97,7 +99,7 @@ weak_ptr_factory_(this) {} WindowPortMus::~WindowPortMus() { - client_surface_embedder_.reset(); + allocator_.reset(); // DESTROY is only scheduled from DestroyFromServer(), meaning if DESTROY is // present then the server originated the change. @@ -223,6 +225,22 @@ return viz::FrameSinkId(kClientSelfId, server_id()); } +gfx::Size WindowPortMus::GetSizeInPixels() { + return GetSizeInPixels(window_->bounds().size()); +} + +gfx::Size WindowPortMus::GetSizeInPixels(const gfx::Size& size) { + return gfx::ScaleToCeiledSize(size, GetDeviceScaleFactor()); +} + +void WindowPortMus::SetAllocator(std::unique_ptr<MusLsiAllocator> allocator) { + allocator_ = std::move(allocator); + // This triggers allocating a LocalSurfaceId *and* notifying the server. + // TODO: investigate making allocation match that of WindowPortLocal, this may + // be called earlier than WindowPortLocal allocates the id. + allocator_->AllocateLocalSurfaceId(); +} + WindowPortMus::ServerChangeIdType WindowPortMus::ScheduleChange( const ServerChangeType type, const ServerChangeData& data) { @@ -318,12 +336,9 @@ return false; has_embedding_ = true; - if (!client_surface_embedder_) { - client_surface_embedder_ = std::make_unique<ClientSurfaceEmbedder>( - window_, /* inject_gutter */ false, gfx::Insets()); - } - // Triggers updating |client_surface_embedder_|. - GetOrAllocateLocalSurfaceIdForCurrentSize(); + DCHECK(!allocator_.get()); + SetAllocator(MusLsiAllocator::CreateAllocator(MusLsiAllocatorType::kEmbed, + this, window_tree_client_)); return true; } @@ -334,7 +349,7 @@ bool result) { if (window && !result) { window->has_embedding_ = false; - window->client_surface_embedder_.reset(); + window->allocator_.reset(); } std::move(real_callback).Run(window && result); } @@ -343,12 +358,6 @@ return window_tree_client_->delegate_->GetPropertyConverter(); } -void WindowPortMus::GetOrAllocateLocalSurfaceIdForCurrentSize() { - const gfx::Size size_in_pixels = - gfx::ScaleToCeiledSize(window_->bounds().size(), GetDeviceScaleFactor()); - GetOrAllocateLocalSurfaceId(size_in_pixels); -} - Window* WindowPortMus::GetWindow() { return window_; } @@ -383,18 +392,15 @@ window_->StackChildAbove(child->GetWindow(), relative->GetWindow()); } -void WindowPortMus::SetBoundsFromServer( - const gfx::Rect& bounds, - const base::Optional<viz::LocalSurfaceId>& local_surface_id) { +void WindowPortMus::SetBoundsFromServer(const gfx::Rect& bounds) { + // Changes to TOP_LEVEL and EMBED are routed through WindowTreeHostMus. + DCHECK(window_mus_type() != WindowMusType::TOP_LEVEL && + window_mus_type() != WindowMusType::EMBED); ServerChangeData data; data.bounds_in_dip = bounds; ScopedServerChange change(this, ServerChangeType::BOUNDS, data); - last_surface_size_in_pixels_ = - gfx::ConvertSizeToPixel(GetDeviceScaleFactor(), bounds.size()); - if (local_surface_id) - parent_local_surface_id_allocator_.Reset(*local_surface_id); - else - parent_local_surface_id_allocator_.Invalidate(); + // XXX this seems like the wrong place to cache size. + last_surface_size_in_pixels_ = GetSizeInPixels(bounds.size()); window_->SetBounds(bounds); } @@ -437,37 +443,11 @@ void WindowPortMus::SetFrameSinkIdFromServer( const viz::FrameSinkId& frame_sink_id) { + // Only called if this window is embedding another window. + DCHECK(has_embedding_); embed_frame_sink_id_ = frame_sink_id; window_->SetEmbedFrameSinkId(embed_frame_sink_id_); - // We may not have allocated a LocalSurfaceId. Call OnWindowMusBoundsChanged() - // to trigger updating the LocalSurfaceId *and* notifying the server. - window_tree_client_->OnWindowMusBoundsChanged(this, window_->bounds(), - window_->bounds()); -} - -const viz::LocalSurfaceId& WindowPortMus::GetOrAllocateLocalSurfaceId( - const gfx::Size& surface_size_in_pixels) { - if (last_surface_size_in_pixels_ != surface_size_in_pixels || - !GetLocalSurfaceIdAllocation().IsValid()) { - parent_local_surface_id_allocator_.GenerateId(); - last_surface_size_in_pixels_ = surface_size_in_pixels; - } - - const viz::LocalSurfaceId& current_local_surface_id = - parent_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() - .local_surface_id(); - - // If the FrameSinkId is available, then immediately embed the SurfaceId. - // The newly generated frame by the embedder will block in the display - // compositor until the child submits a corresponding CompositorFrame or a - // deadline hits. - if (window_->IsEmbeddingClient()) - UpdatePrimarySurfaceId(); - - if (local_layer_tree_frame_sink_) - local_layer_tree_frame_sink_->SetLocalSurfaceId(current_local_surface_id); - - return current_local_surface_id; + allocator_->OnFrameSinkIdChanged(); } void WindowPortMus::DestroyFromServer() { @@ -526,41 +506,52 @@ } void WindowPortMus::AllocateLocalSurfaceId() { - parent_local_surface_id_allocator_.GenerateId(); - UpdatePrimarySurfaceId(); - if (local_layer_tree_frame_sink_) { - local_layer_tree_frame_sink_->SetLocalSurfaceId( - GetLocalSurfaceIdAllocation().local_surface_id()); + // This API does not make sense for EMBED. + DCHECK_NE(window_mus_type(), WindowMusType::EMBED); + if (!allocator_ && window_mus_type() == WindowMusType::LOCAL) { + SetAllocator(MusLsiAllocator::CreateAllocator(MusLsiAllocatorType::kLocal, + this, window_tree_client_)); + } else if (allocator_) { + allocator_->AllocateLocalSurfaceId(); } } viz::ScopedSurfaceIdAllocator WindowPortMus::GetSurfaceIdAllocator( base::OnceCallback<void()> allocation_task) { - return viz::ScopedSurfaceIdAllocator(&parent_local_surface_id_allocator_, - std::move(allocation_task)); + // This API does not make sense for EMBED. + DCHECK_NE(window_mus_type(), WindowMusType::EMBED); + return allocator_ + ? allocator_->GetSurfaceIdAllocator(std::move(allocation_task)) + : viz::ScopedSurfaceIdAllocator(std::move(allocation_task)); } void WindowPortMus::InvalidateLocalSurfaceId() { - parent_local_surface_id_allocator_.Invalidate(); + // This API does not make sense for EMBED. + DCHECK_NE(window_mus_type(), WindowMusType::EMBED); + if (allocator_) + allocator_->InvalidateLocalSurfaceId(); } void WindowPortMus::UpdateLocalSurfaceIdFromEmbeddedClient( const viz::LocalSurfaceIdAllocation& embedded_client_local_surface_id_allocation) { - parent_local_surface_id_allocator_.UpdateFromChild( - embedded_client_local_surface_id_allocation); - UpdatePrimarySurfaceId(); - - // OnWindowMusBoundsChanged() triggers notifying the server of the new - // LocalSurfaceId. - window_tree_client_->OnWindowMusBoundsChanged(this, window_->bounds(), - window_->bounds()); + // This API does not make sense for EMBED. + DCHECK_NE(window_mus_type(), WindowMusType::EMBED); + if (allocator_) { + allocator_->UpdateLocalSurfaceIdFromEmbeddedClient( + embedded_client_local_surface_id_allocation); + } } const viz::LocalSurfaceIdAllocation& WindowPortMus::GetLocalSurfaceIdAllocation() { - return parent_local_surface_id_allocator_ - .GetCurrentLocalSurfaceIdAllocation(); + static base::NoDestructor<viz::LocalSurfaceIdAllocation> empty_allocation; + return allocator_ ? allocator_->GetLocalSurfaceIdAllocation() + : *empty_allocation; +} + +bool WindowPortMus::HasLocalSurfaceId() { + return allocator_.get() != nullptr; } std::unique_ptr<WindowMusChangeData> @@ -591,15 +582,11 @@ void WindowPortMus::NotifyEmbeddedAppDisconnected() { has_embedding_ = false; - client_surface_embedder_.reset(); + allocator_ = nullptr; for (WindowObserver& observer : *GetObservers(window_)) observer.OnEmbeddedAppDisconnected(window_); } -bool WindowPortMus::HasLocalLayerTreeFrameSink() { - return !!local_layer_tree_frame_sink_; -} - float WindowPortMus::GetDeviceScaleFactor() { return window_->layer()->device_scale_factor(); } @@ -611,13 +598,8 @@ void WindowPortMus::OnDeviceScaleFactorChanged(float old_device_scale_factor, float new_device_scale_factor) { - if (!window_->IsRootWindow() && GetLocalSurfaceIdAllocation().IsValid() && - local_layer_tree_frame_sink_) { - parent_local_surface_id_allocator_.GenerateId(); - local_layer_tree_frame_sink_->SetLocalSurfaceId( - parent_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() - .local_surface_id()); - } + if (allocator_) + allocator_->OnDeviceScaleFactorChanged(); if (window_->delegate()) { window_->delegate()->OnDeviceScaleFactorChanged(old_device_scale_factor, @@ -659,10 +641,12 @@ const gfx::Rect& new_bounds) { ServerChangeData change_data; change_data.bounds_in_dip = new_bounds; - if (!RemoveChangeByTypeAndData(ServerChangeType::BOUNDS, change_data)) + const bool from_server = + RemoveChangeByTypeAndData(ServerChangeType::BOUNDS, change_data); + if (allocator_) + allocator_->OnDidChangeBounds(GetSizeInPixels(), from_server); + if (!from_server) window_tree_client_->OnWindowMusBoundsChanged(this, old_bounds, new_bounds); - if (client_surface_embedder_) - client_surface_embedder_->UpdateSizeAndGutters(); } void WindowPortMus::OnDidChangeTransform(const gfx::Transform& old_transform, @@ -712,21 +696,9 @@ std::unique_ptr<cc::LayerTreeFrameSink> WindowPortMus::CreateLayerTreeFrameSink() { - DCHECK_EQ(window_mus_type(), WindowMusType::LOCAL); - DCHECK(!local_layer_tree_frame_sink_); - - // TODO(sky): this needs to supply a RasterContextProvider. - auto client_layer_tree_frame_sink = RequestLayerTreeFrameSink( - nullptr, nullptr, - window_->env()->context_factory()->GetGpuMemoryBufferManager()); - local_layer_tree_frame_sink_ = client_layer_tree_frame_sink->GetWeakPtr(); - embed_frame_sink_id_ = GenerateFrameSinkIdFromServerId(); - window_->SetEmbedFrameSinkId(embed_frame_sink_id_); - - // Make sure |local_surface_id_| and |last_surface_size_in_pixels_| are - // correct for the new created |local_layer_tree_frame_sink_|. - GetOrAllocateLocalSurfaceIdForCurrentSize(); - return client_layer_tree_frame_sink; + // This function should not be called for WindowPortMus. + NOTIMPLEMENTED(); + return nullptr; } void WindowPortMus::OnEventTargetingPolicyChanged() { @@ -742,6 +714,14 @@ return; window_tree_client_->RegisterFrameSinkId(this, frame_sink_id); + // This api only makes sense for local windows. + DCHECK_EQ(window_mus_type(), WindowMusType::LOCAL); + if (allocator_) { + DCHECK_EQ(MusLsiAllocatorType::kLocal, allocator_->type()); + } else { + SetAllocator(MusLsiAllocator::CreateAllocator(MusLsiAllocatorType::kLocal, + this, window_tree_client_)); + } } void WindowPortMus::UnregisterFrameSinkId( @@ -761,25 +741,6 @@ window_tree_client_->TrackOcclusionState(this); } -void WindowPortMus::UpdatePrimarySurfaceId() { - if (window_mus_type() != WindowMusType::LOCAL) - return; - - if (!window_->IsEmbeddingClient() || !GetLocalSurfaceIdAllocation().IsValid()) - return; - - primary_surface_id_ = - viz::SurfaceId(window_->GetFrameSinkId(), - GetLocalSurfaceIdAllocation().local_surface_id()); - - // ClientSurfaceEmbedder is only applicable if we have an actual embedding. - if (!has_embedding_) - return; - - client_surface_embedder_->SetSurfaceId(primary_surface_id_); - client_surface_embedder_->UpdateSizeAndGutters(); -} - void WindowPortMus::SetOcclusionStateFromServer( ws::mojom::OcclusionState occlusion_state) { const Window::OcclusionState new_state =
diff --git a/ui/aura/mus/window_port_mus.h b/ui/aura/mus/window_port_mus.h index d168ae7..adf7804 100644 --- a/ui/aura/mus/window_port_mus.h +++ b/ui/aura/mus/window_port_mus.h
@@ -15,7 +15,6 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/time/time.h" -#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/common/surfaces/surface_info.h" #include "services/ws/public/mojom/window_tree.mojom.h" #include "services/ws/public/mojom/window_tree_constants.mojom.h" @@ -45,7 +44,7 @@ namespace aura { -class ClientSurfaceEmbedder; +class MusLsiAllocator; class PropertyConverter; class WindowTreeClient; class WindowTreeClientTestApi; @@ -67,10 +66,6 @@ Window* window() { return window_; } const Window* window() const { return window_; } - ClientSurfaceEmbedder* client_surface_embedder() const { - return client_surface_embedder_.get(); - } - const viz::SurfaceId& PrimarySurfaceIdForTesting() const { return primary_surface_id_; } @@ -107,6 +102,9 @@ viz::FrameSinkId GenerateFrameSinkIdFromServerId() const; + gfx::Size GetSizeInPixels(); + gfx::Size GetSizeInPixels(const gfx::Size& size); + private: friend class WindowPortMusTestHelper; friend class WindowTreeClient; @@ -212,6 +210,8 @@ // and needs to consider ancestors' visibility as well. class VisibilityTracker; + void SetAllocator(std::unique_ptr<MusLsiAllocator> allocator); + // Creates and adds a ServerChange to |server_changes_|. Returns the id // assigned to the ServerChange. ServerChangeIdType ScheduleChange(const ServerChangeType type, @@ -220,7 +220,7 @@ // Removes a ServerChange by id. void RemoveChangeById(ServerChangeIdType change_id); - // If there is a schedule change matching |type| and |data| it is removed and + // If there is a scheduled change matching |type| and |data| it is removed and // true is returned. If no matching change is scheduled returns false. bool RemoveChangeByTypeAndData(const ServerChangeType type, const ServerChangeData& data); @@ -240,9 +240,6 @@ PropertyConverter* GetPropertyConverter(); - // Calls GetOrAllocateLocalSurfaceId() with the current size. - void GetOrAllocateLocalSurfaceIdForCurrentSize(); - // WindowMus: Window* GetWindow() override; void AddChildFromServer(WindowMus* window) override; @@ -250,9 +247,7 @@ void ReorderFromServer(WindowMus* child, WindowMus* relative, ws::mojom::OrderDirection) override; - void SetBoundsFromServer( - const gfx::Rect& bounds, - const base::Optional<viz::LocalSurfaceId>& local_surface_id) override; + void SetBoundsFromServer(const gfx::Rect& bounds) override; void SetTransformFromServer(const gfx::Transform& transform) override; void SetVisibleFromServer(bool visible) override; void SetOpacityFromServer(float opacity) override; @@ -261,8 +256,6 @@ const std::string& property_name, const std::vector<uint8_t>* property_data) override; void SetFrameSinkIdFromServer(const viz::FrameSinkId& frame_sink_id) override; - const viz::LocalSurfaceId& GetOrAllocateLocalSurfaceId( - const gfx::Size& surface_size_in_pixels) override; void UpdateLocalSurfaceIdFromEmbeddedClient( const viz::LocalSurfaceIdAllocation& embedded_client_local_surface_id_allocation) override; @@ -271,13 +264,13 @@ void RemoveTransientChildFromServer(WindowMus* child) override; ChangeSource OnTransientChildAdded(WindowMus* child) override; ChangeSource OnTransientChildRemoved(WindowMus* child) override; + bool HasLocalSurfaceId() override; std::unique_ptr<WindowMusChangeData> PrepareForServerBoundsChange( const gfx::Rect& bounds) override; std::unique_ptr<WindowMusChangeData> PrepareForServerVisibilityChange( bool value) override; void PrepareForDestroy() override; void NotifyEmbeddedAppDisconnected() override; - bool HasLocalLayerTreeFrameSink() override; float GetDeviceScaleFactor() override; // WindowPort: @@ -309,8 +302,6 @@ void UnregisterFrameSinkId(const viz::FrameSinkId& frame_sink_id) override; void TrackOcclusionState() override; - void UpdatePrimarySurfaceId(); - // Called by WindowTreeClient to update window occlusion state. void SetOcclusionStateFromServer(ws::mojom::OcclusionState occlusion_state); @@ -326,19 +317,17 @@ Window* window_ = nullptr; - // Used when this window is embedding a client. - std::unique_ptr<ClientSurfaceEmbedder> client_surface_embedder_; - ServerChangeIdType next_server_change_id_ = 0; ServerChanges server_changes_; viz::SurfaceId primary_surface_id_; - // TODO(sad, fsamuel): For 'mash' mode, where the embedder is responsible for - // allocating the LocalSurfaceIds, this should use a - // ChildLocalSurfaceIdAllocator instead. - viz::ParentLocalSurfaceIdAllocator parent_local_surface_id_allocator_; - gfx::Size last_surface_size_in_pixels_; + // Manages allocation of LocalSurfaceIds. Only created if this window needs + // allocated LocalSurfaceIds. + std::unique_ptr<MusLsiAllocator> allocator_; + + // This is set the first time an id is generated. + base::Optional<gfx::Size> last_surface_size_in_pixels_; ui::Cursor cursor_;
diff --git a/ui/aura/mus/window_port_mus_unittest.cc b/ui/aura/mus/window_port_mus_unittest.cc index 0b610c9..649a715d 100644 --- a/ui/aura/mus/window_port_mus_unittest.cc +++ b/ui/aura/mus/window_port_mus_unittest.cc
@@ -7,6 +7,7 @@ #include "base/optional.h" #include "base/run_loop.h" #include "cc/mojo_embedder/async_layer_tree_frame_sink.h" +#include "components/viz/common/surfaces/child_local_surface_id_allocator.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/client/drag_drop_delegate.h" #include "ui/aura/mus/client_surface_embedder.h" @@ -96,11 +97,13 @@ // Allocate a new LocalSurfaceId. The ui::Layer should be updated. window.AllocateLocalSurfaceId(); - auto* window_mus = WindowPortMus::Get(&window); viz::LocalSurfaceId local_surface_id = window.GetLocalSurfaceIdAllocation().local_surface_id(); + ClientSurfaceEmbedder* client_surface_embedder = + WindowPortMusTestHelper(&window).GetClientSurfaceEmbedder(); + ASSERT_TRUE(client_surface_embedder); viz::SurfaceId primary_surface_id = - window_mus->client_surface_embedder()->GetSurfaceIdForTesting(); + client_surface_embedder->GetSurfaceIdForTesting(); EXPECT_EQ(local_surface_id, primary_surface_id.local_surface_id()); } @@ -133,18 +136,20 @@ parent_allocator->GetCurrentLocalSurfaceIdAllocation()); // Updating the LocalSurfaceId should propagate to the ClientSurfaceEmbedder. - auto* window_mus = WindowPortMus::Get(&window); - ASSERT_TRUE(window_mus); - ASSERT_TRUE(window_mus->client_surface_embedder()); - EXPECT_EQ(updated_id, window_mus->client_surface_embedder() - ->GetSurfaceIdForTesting() - .local_surface_id()); + ClientSurfaceEmbedder* client_surface_embedder = + WindowPortMusTestHelper(&window).GetClientSurfaceEmbedder(); + ASSERT_TRUE(client_surface_embedder); + EXPECT_EQ( + updated_id, + client_surface_embedder->GetSurfaceIdForTesting().local_surface_id()); // The server is notified of a bounds change, so that it sees the new // LocalSurfaceId. ASSERT_EQ(1u, window_tree()->GetChangeCountForType(WindowTreeChangeType::BOUNDS)); ASSERT_TRUE(window_tree()->last_local_surface_id()); + auto* window_mus = WindowPortMus::Get(&window); + ASSERT_TRUE(window_mus); EXPECT_EQ(window_mus->server_id(), window_tree()->window_id()); EXPECT_EQ(updated_id, *(window_tree()->last_local_surface_id())); } @@ -210,9 +215,10 @@ WindowPortMusTestHelper helper(&window); helper.SimulateEmbedding(); - auto* window_mus = WindowPortMus::Get(&window); - ASSERT_TRUE(window_mus->client_surface_embedder()); - EXPECT_TRUE(window_mus->client_surface_embedder()->HasPrimarySurfaceId()); + ClientSurfaceEmbedder* client_surface_embedder = + WindowPortMusTestHelper(&window).GetClientSurfaceEmbedder(); + ASSERT_TRUE(client_surface_embedder); + EXPECT_TRUE(client_surface_embedder->HasPrimarySurfaceId()); } class TestDragDropDelegate : public client::DragDropDelegate { @@ -253,4 +259,35 @@ EXPECT_FALSE(window_tree()->last_accepts_drops()); } +TEST_F(WindowPortMusTest, RegisterFrameSinkId) { + Window window(nullptr); + window.Init(ui::LAYER_NOT_DRAWN); + window.set_owned_by_parent(false); + window.SetBounds(gfx::Rect(400, 300)); + + root_window()->AddChild(&window); + window_tree()->AckAllChanges(); + window.SetEmbedFrameSinkId(viz::FrameSinkId(0, 1)); + + // Setting a FrameSinkId should trigger generating LocalSurfaceIds. + ASSERT_EQ(1u, + window_tree()->GetChangeCountForType(WindowTreeChangeType::BOUNDS)); + ASSERT_TRUE(window_tree()->last_local_surface_id()); + EXPECT_EQ(window_tree()->last_local_surface_id(), + window.GetLocalSurfaceIdAllocation().local_surface_id()); + auto local_surface_id = + window.GetLocalSurfaceIdAllocation().local_surface_id(); + window_tree()->AckAllChanges(); + + // Changing the bounds should trigger a new LocalSurfaceId. + window.SetBounds(gfx::Rect(400, 310)); + ASSERT_EQ(1u, + window_tree()->GetChangeCountForType(WindowTreeChangeType::BOUNDS)); + ASSERT_TRUE(window_tree()->last_local_surface_id()); + EXPECT_EQ(window_tree()->last_local_surface_id(), + window.GetLocalSurfaceIdAllocation().local_surface_id()); + EXPECT_NE(local_surface_id, + window.GetLocalSurfaceIdAllocation().local_surface_id()); +} + } // namespace aura
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc index a5676c55..47c1a76 100644 --- a/ui/aura/mus/window_tree_client.cc +++ b/ui/aura/mus/window_tree_client.cc
@@ -34,6 +34,7 @@ #include "ui/aura/env.h" #include "ui/aura/env_input_state_controller.h" #include "ui/aura/mus/capture_synchronizer.h" +#include "ui/aura/mus/client_side_window_move_handler.h" #include "ui/aura/mus/drag_drop_controller_mus.h" #include "ui/aura/mus/embed_root.h" #include "ui/aura/mus/embed_root_delegate.h" @@ -283,11 +284,6 @@ WindowMus* window, const viz::FrameSinkId& frame_sink_id) { tree_->AttachFrameSinkId(window->server_id(), frame_sink_id); - - // Call OnWindowMusBoundsChanged() to force allocation of a LocalSurfaceId as - // well as notifying the server of the LocalSurfaceId. - const gfx::Rect bounds = window->GetWindow()->bounds(); - OnWindowMusBoundsChanged(window, bounds, bounds); } void WindowTreeClient::UnregisterFrameSinkId(WindowMus* window) { @@ -527,7 +523,7 @@ SetWindowType(window, GetWindowTypeFromProperties(properties)); window->Init(ui::LAYER_NOT_DRAWN); SetLocalPropertiesFromServerProperties(window_mus, window_data); - window_mus->SetBoundsFromServer(window_data.bounds, base::nullopt); + window_mus->SetBoundsFromServer(window_data.bounds); if (parent) parent->AddChildFromServer(window_port_mus_ptr); if (window_data.visible) @@ -557,6 +553,8 @@ Env::GetInstance()->SetGestureRecognizer( std::make_unique<GestureRecognizerImplMus>(this)); gesture_synchronizer_ = std::make_unique<GestureSynchronizer>(tree_); + client_side_window_move_handler_ = + std::make_unique<ClientSideWindowMoveHandler>(Env::GetInstance()); } void WindowTreeClient::OnConnectionLost() { @@ -640,7 +638,7 @@ return; } - window->SetBoundsFromServer(revert_bounds, local_surface_id); + window->SetBoundsFromServer(revert_bounds); } void WindowTreeClient::SetWindowTransformFromServer( @@ -681,12 +679,10 @@ this, window, old_bounds, window->GetLocalSurfaceIdAllocation().local_surface_id())); base::Optional<viz::LocalSurfaceId> local_surface_id; - if (window->GetWindow()->IsEmbeddingClient() || - window->HasLocalLayerTreeFrameSink()) { - // Do not use ConvertRectToPixel, enclosing rects cause problems. - const gfx::Size size = gfx::ScaleToCeiledSize( - new_bounds.size(), window->GetDeviceScaleFactor()); - local_surface_id = window->GetOrAllocateLocalSurfaceId(size); + if (window->HasLocalSurfaceId()) { + local_surface_id = window->GetLocalSurfaceIdAllocation().local_surface_id(); + DCHECK(local_surface_id); + DCHECK(local_surface_id->is_valid()); // |window_tree_host| may be null if this is called during creation of // the window associated with the WindowTreeHostMus, or if there is an // embedding. @@ -1474,8 +1470,7 @@ // is deleted, but still we want to invoke the finished callback. if (change_id == current_move_loop_change_) { current_move_loop_change_ = 0; - on_current_move_finished_.Run(success); - on_current_move_finished_.Reset(); + std::move(on_current_move_finished_).Run(success); for (auto& observer : observers_) observer.OnWindowMoveEnded(success); } @@ -1542,6 +1537,11 @@ void WindowTreeClient::OnWindowTreeHostBoundsWillChange( WindowTreeHostMus* window_tree_host, const gfx::Rect& bounds_in_pixels) { + // The only other type of window that may hit this code path is EMBED. Clients + // are not allowed to change the bounds of EMBED windows (only the server). + // LOCAL and OTHER types don't have a WindowTreeHost. + DCHECK_EQ(WindowMusType::TOP_LEVEL, + WindowMus::Get(window_tree_host->window())->window_mus_type()); gfx::Rect old_bounds = window_tree_host->GetBoundsInPixels(); gfx::Rect new_bounds = bounds_in_pixels; const float device_scale_factor = window_tree_host->device_scale_factor(); @@ -1598,9 +1598,9 @@ WindowTreeHostMus* window_tree_host, ws::mojom::MoveLoopSource source, const gfx::Point& cursor_location, - const base::Callback<void(bool)>& callback) { + base::OnceCallback<void(bool)> callback) { DCHECK(on_current_move_finished_.is_null()); - on_current_move_finished_ = callback; + on_current_move_finished_ = std::move(callback); WindowMus* window_mus = WindowMus::Get(window_tree_host->window()); current_move_loop_change_ = ScheduleInFlightChange(
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h index f9f9ec4..c25d30f3 100644 --- a/ui/aura/mus/window_tree_client.h +++ b/ui/aura/mus/window_tree_client.h
@@ -58,6 +58,7 @@ namespace aura { class CaptureSynchronizer; +class ClientSideWindowMoveHandler; class DragDropControllerMus; class EmbedRoot; class EmbedRootDelegate; @@ -220,6 +221,7 @@ friend class InFlightPropertyChange; friend class InFlightTransformChange; friend class InFlightVisibleChange; + friend class ParentAllocator; // For OnWindowMusBoundsChanged(). friend class TopmostWindowTracker; friend class WindowPortMus; friend class WindowTreeClientTestApi; @@ -491,7 +493,7 @@ WindowTreeHostMus* window_tree_host, ws::mojom::MoveLoopSource mus_source, const gfx::Point& cursor_location, - const base::Callback<void(bool)>& callback) override; + base::OnceCallback<void(bool)> callback) override; void OnWindowTreeHostCancelWindowMove( WindowTreeHostMus* window_tree_host) override; std::unique_ptr<WindowPortMus> CreateWindowPortForTopLevel( @@ -544,6 +546,8 @@ std::unique_ptr<GestureSynchronizer> gesture_synchronizer_; + std::unique_ptr<ClientSideWindowMoveHandler> client_side_window_move_handler_; + mojo::Binding<ws::mojom::WindowTreeClient> binding_; ws::mojom::WindowTreePtr tree_ptr_; // Typically this is the value contained in |tree_ptr_|, but tests may @@ -571,7 +575,7 @@ // Callback executed when a move loop initiated by PerformWindowMove() is // completed. - base::Callback<void(bool)> on_current_move_finished_; + base::OnceCallback<void(bool)> on_current_move_finished_; std::unique_ptr<DragDropControllerMus> drag_drop_controller_;
diff --git a/ui/aura/mus/window_tree_client_unittest.cc b/ui/aura/mus/window_tree_client_unittest.cc index dc9a291..e120e067 100644 --- a/ui/aura/mus/window_tree_client_unittest.cc +++ b/ui/aura/mus/window_tree_client_unittest.cc
@@ -255,6 +255,9 @@ Window window(nullptr); window.Init(ui::LAYER_NOT_DRAWN); WindowPortMusTestHelper(&window).SimulateEmbedding(); + // SimulateEmbedding() generates a bounds change. + ASSERT_TRUE( + window_tree()->AckSingleChangeOfType(WindowTreeChangeType::BOUNDS, true)); const gfx::Rect original_bounds(window.bounds()); const viz::LocalSurfaceId original_local_surface_id( @@ -265,14 +268,19 @@ EXPECT_EQ(new_bounds, window.bounds()); WindowMus* window_mus = WindowMus::Get(&window); ASSERT_NE(nullptr, window_mus); - EXPECT_TRUE(window_mus->GetLocalSurfaceIdAllocation().IsValid()); + ASSERT_TRUE(window_mus->GetLocalSurfaceIdAllocation().IsValid()); + const viz::LocalSurfaceId new_surface_id = + window_mus->GetLocalSurfaceIdAllocation().local_surface_id(); // Reverting the change should also revert the viz::LocalSurfaceId. ASSERT_TRUE(window_tree()->AckSingleChangeOfType(WindowTreeChangeType::BOUNDS, false)); EXPECT_EQ(original_bounds, window.bounds()); - EXPECT_EQ(original_local_surface_id, + // Whenever the bounds changes a new LocalSurfaceId needs to be allocated. + EXPECT_NE(new_surface_id, window.GetLocalSurfaceIdAllocation().local_surface_id()); + EXPECT_EQ(1u, + window_tree()->GetChangeCountForType(WindowTreeChangeType::BOUNDS)); } INSTANTIATE_TEST_CASE_P(/* no prefix */, @@ -284,12 +292,13 @@ Window window(nullptr); window.Init(ui::LAYER_NOT_DRAWN); - WindowPortMus* window_port_mus = WindowPortMus::Get(&window); - ASSERT_TRUE(window_port_mus); + WindowPortMusTestHelper window_test_helper(&window); // A ClientSurfaceEmbedder is only created once there is an embedding. - EXPECT_EQ(nullptr, window_port_mus->client_surface_embedder()); - WindowPortMusTestHelper(&window).SimulateEmbedding(); + ClientSurfaceEmbedder* client_surface_embedder = + window_test_helper.GetClientSurfaceEmbedder(); + EXPECT_EQ(nullptr, client_surface_embedder); + window_test_helper.SimulateEmbedding(); gfx::Rect new_bounds(gfx::Rect(0, 0, 100, 100)); ASSERT_NE(new_bounds, window.bounds()); @@ -298,8 +307,7 @@ EXPECT_TRUE(WindowMus::Get(&window)->GetLocalSurfaceIdAllocation().IsValid()); // Once the bounds have been set, the ClientSurfaceEmbedder should be created. - ClientSurfaceEmbedder* client_surface_embedder = - window_port_mus->client_surface_embedder(); + client_surface_embedder = window_test_helper.GetClientSurfaceEmbedder(); ASSERT_NE(nullptr, client_surface_embedder); EXPECT_EQ(nullptr, client_surface_embedder->BottomGutterForTesting()); @@ -462,8 +470,7 @@ // Simulates a bounds change, and while the bounds change is in flight the // server replies with a new bounds and the original bounds change fails. -// The server bounds change takes hold along with the associated -// viz::LocalSurfaceId. +// The server bounds change takes hold. TEST_F(WindowTreeClientTest, SetBoundsFailedWithPendingChange) { aura::Window root_window(nullptr); root_window.Init(ui::LAYER_NOT_DRAWN); @@ -492,15 +499,12 @@ ASSERT_TRUE(window_tree()->AckSingleChangeOfType(WindowTreeChangeType::BOUNDS, false)); EXPECT_EQ(server_changed_bounds, root_window.bounds()); - EXPECT_EQ(server_changed_local_surface_id, - root_window_mus->GetLocalSurfaceIdAllocation().local_surface_id()); // Simulate server changing back to original bounds. Should take immediately. window_tree_client()->OnWindowBoundsChanged(server_id(&root_window), server_changed_bounds, original_bounds, base::nullopt); EXPECT_EQ(original_bounds, root_window.bounds()); - EXPECT_FALSE(root_window_mus->GetLocalSurfaceIdAllocation().IsValid()); } TEST_F(WindowTreeClientTest, TwoInFlightBoundsChangesBothCanceled) { @@ -2585,8 +2589,8 @@ WindowTreeHostMus* host_mus = static_cast<WindowTreeHostMus*>(host()); host_mus->PerformWindowMove( - ws::mojom::MoveLoopSource::MOUSE, gfx::Point(), - base::Bind(&OnWindowMoveDone, &call_count, &last_result)); + host_mus->window(), ws::mojom::MoveLoopSource::MOUSE, gfx::Point(), + base::BindOnce(&OnWindowMoveDone, &call_count, &last_result)); EXPECT_EQ(0, call_count); window_tree()->AckAllChanges(); @@ -2594,8 +2598,8 @@ EXPECT_TRUE(last_result); host_mus->PerformWindowMove( - ws::mojom::MoveLoopSource::MOUSE, gfx::Point(), - base::Bind(&OnWindowMoveDone, &call_count, &last_result)); + host_mus->window(), ws::mojom::MoveLoopSource::MOUSE, gfx::Point(), + base::BindOnce(&OnWindowMoveDone, &call_count, &last_result)); window_tree()->AckAllChangesOfType(WindowTreeChangeType::OTHER, false); EXPECT_EQ(2, call_count); EXPECT_FALSE(last_result); @@ -2611,8 +2615,8 @@ window_tree()->AckAllChanges(); host_mus->PerformWindowMove( - ws::mojom::MoveLoopSource::MOUSE, gfx::Point(), - base::Bind(&OnWindowMoveDone, &call_count, &last_result)); + host_mus->window(), ws::mojom::MoveLoopSource::MOUSE, gfx::Point(), + base::BindOnce(&OnWindowMoveDone, &call_count, &last_result)); EXPECT_EQ(0, call_count); host_mus.reset(); @@ -2622,6 +2626,32 @@ EXPECT_TRUE(last_result); } +TEST_F(WindowTreeClientTest, PerformWindowMoveTransferEvents) { + int call_count = 0; + bool last_result = false; + + aura::Window* window = CreateNormalWindow(10, host()->window(), nullptr); + WindowTreeHostMus* host_mus = static_cast<WindowTreeHostMus*>(host()); + window->SetCapture(); + host_mus->PerformWindowMove( + window, ws::mojom::MoveLoopSource::TOUCH, gfx::Point(), + base::BindOnce(&OnWindowMoveDone, &call_count, &last_result)); + EXPECT_EQ(0, call_count); + EXPECT_EQ(WindowPortMus::Get(window)->server_id(), + window_tree()->last_transfer_current()); + EXPECT_EQ(WindowPortMus::Get(host_mus->window())->server_id(), + window_tree()->last_transfer_new()); + EXPECT_FALSE(window->HasCapture()); + + window_tree()->AckAllChanges(); + EXPECT_EQ(1, call_count); + EXPECT_TRUE(last_result); + EXPECT_EQ(WindowPortMus::Get(host_mus->window())->server_id(), + window_tree()->last_transfer_current()); + EXPECT_EQ(WindowPortMus::Get(window)->server_id(), + window_tree()->last_transfer_new()); +} + // Verifies occlusion state from server is applied to underlying window. TEST_F(WindowTreeClientTest, OcclusionStateFromServer) { struct {
diff --git a/ui/aura/mus/window_tree_host_mus.cc b/ui/aura/mus/window_tree_host_mus.cc index be1b2ca..527e13e 100644 --- a/ui/aura/mus/window_tree_host_mus.cc +++ b/ui/aura/mus/window_tree_host_mus.cc
@@ -14,13 +14,17 @@ #include "ui/aura/mus/window_tree_host_mus_init_params.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" +#include "ui/aura/window_tracker.h" #include "ui/aura/window_tree_host_observer.h" #include "ui/base/class_property.h" +#include "ui/base/hit_test.h" #include "ui/base/ui_base_features.h" #include "ui/base/ui_base_switches_util.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/events/event.h" +#include "ui/events/gestures/gesture_recognizer.h" +#include "ui/events/gestures/gesture_recognizer_observer.h" #include "ui/platform_window/stub/stub_window.h" DEFINE_UI_CLASS_PROPERTY_TYPE(aura::WindowTreeHostMus*); @@ -37,6 +41,62 @@ // and increases). uint32_t next_accelerated_widget_id = std::numeric_limits<uint32_t>::max(); +// ScopedTouchTransferController controls the transfer of touch events for +// window move loop. It transfers touches before the window move starts, and +// then transfers them back to the original window when the window move ends. +// However this transferring back to the original shouldn't happen if the client +// wants to continue the dragging on another window (like attaching the dragged +// tab to another window). +class ScopedTouchTransferController : public ui::GestureRecognizerObserver { + public: + ScopedTouchTransferController(Window* source, Window* dest) + : tracker_({source, dest}), + gesture_recognizer_(source->env()->gesture_recognizer()) { + gesture_recognizer_->TransferEventsTo( + source, dest, ui::TransferTouchesBehavior::kDontCancel); + gesture_recognizer_->AddObserver(this); + } + ~ScopedTouchTransferController() override { + gesture_recognizer_->RemoveObserver(this); + if (tracker_.windows().size() == 2) { + Window* source = tracker_.Pop(); + Window* dest = tracker_.Pop(); + gesture_recognizer_->TransferEventsTo( + dest, source, ui::TransferTouchesBehavior::kDontCancel); + } + } + + private: + // ui::GestureRecognizerObserver: + void OnActiveTouchesCanceledExcept( + ui::GestureConsumer* not_cancelled) override {} + void OnEventsTransferred( + ui::GestureConsumer* current_consumer, + ui::GestureConsumer* new_consumer, + ui::TransferTouchesBehavior transfer_touches_behavior) override { + if (tracker_.windows().size() <= 1) + return; + Window* dest = tracker_.windows()[1]; + if (current_consumer == dest) + tracker_.Remove(dest); + } + void OnActiveTouchesCanceled(ui::GestureConsumer* consumer) override {} + + WindowTracker tracker_; + + ui::GestureRecognizer* gesture_recognizer_; + + DISALLOW_COPY_AND_ASSIGN(ScopedTouchTransferController); +}; + +void OnPerformWindowMoveDone( + std::unique_ptr<ScopedTouchTransferController> controller, + base::OnceCallback<void(bool)> callback, + bool success) { + controller.reset(); + std::move(callback).Run(success); +} + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -155,11 +215,21 @@ } void WindowTreeHostMus::PerformWindowMove( + Window* content_window, ws::mojom::MoveLoopSource mus_source, const gfx::Point& cursor_location, - const base::Callback<void(bool)>& callback) { + base::OnceCallback<void(bool)> callback) { + DCHECK(window()->Contains(content_window)); + std::unique_ptr<ScopedTouchTransferController> scoped_controller; + if (content_window != window()) { + scoped_controller = std::make_unique<ScopedTouchTransferController>( + content_window, window()); + } + content_window->ReleaseCapture(); delegate_->OnWindowTreeHostPerformWindowMove( - this, mus_source, cursor_location, callback); + this, mus_source, cursor_location, + base::BindOnce(&OnPerformWindowMoveDone, std::move(scoped_controller), + std::move(callback))); } void WindowTreeHostMus::CancelWindowMove() {
diff --git a/ui/aura/mus/window_tree_host_mus.h b/ui/aura/mus/window_tree_host_mus.h index c8c9b9f..8a6d6959 100644 --- a/ui/aura/mus/window_tree_host_mus.h +++ b/ui/aura/mus/window_tree_host_mus.h
@@ -70,9 +70,10 @@ // Tells the window manager to take control of moving the window. Returns // true if the move wasn't canceled. - void PerformWindowMove(ws::mojom::MoveLoopSource mus_source, + void PerformWindowMove(Window* window, + ws::mojom::MoveLoopSource mus_source, const gfx::Point& cursor_location, - const base::Callback<void(bool)>& callback); + base::OnceCallback<void(bool)> callback); // Tells the window manager to abort any current move initiated by // PerformWindowMove().
diff --git a/ui/aura/mus/window_tree_host_mus_delegate.h b/ui/aura/mus/window_tree_host_mus_delegate.h index 0c17643..399f55e 100644 --- a/ui/aura/mus/window_tree_host_mus_delegate.h +++ b/ui/aura/mus/window_tree_host_mus_delegate.h
@@ -60,7 +60,7 @@ WindowTreeHostMus* window_tree_host, ws::mojom::MoveLoopSource mus_source, const gfx::Point& cursor_location, - const base::Callback<void(bool)>& callback) = 0; + base::OnceCallback<void(bool)> callback) = 0; // Called to cancel a move loop. virtual void OnWindowTreeHostCancelWindowMove(
diff --git a/ui/aura/test/mus/window_port_mus_test_helper.cc b/ui/aura/test/mus/window_port_mus_test_helper.cc index 18e053dd..69097a72 100644 --- a/ui/aura/test/mus/window_port_mus_test_helper.cc +++ b/ui/aura/test/mus/window_port_mus_test_helper.cc
@@ -4,6 +4,7 @@ #include "ui/aura/test/mus/window_port_mus_test_helper.h" +#include "ui/aura/mus/mus_lsi_allocator.h" #include "ui/aura/mus/window_port_mus.h" #include "ui/aura/window.h" @@ -21,18 +22,32 @@ WindowPortMusTestHelper::~WindowPortMusTestHelper() = default; void WindowPortMusTestHelper::SimulateEmbedding() { - window_port_mus_->GetWindow()->SetEmbedFrameSinkId( - viz::FrameSinkId(next_client_id_++, 1)); window_port_mus_->PrepareForEmbed(); + window_port_mus_->SetFrameSinkIdFromServer( + viz::FrameSinkId(next_client_id_++, 1)); } base::WeakPtr<cc::LayerTreeFrameSink> WindowPortMusTestHelper::GetFrameSink() { return window_port_mus_->local_layer_tree_frame_sink_; } +ClientSurfaceEmbedder* WindowPortMusTestHelper::GetClientSurfaceEmbedder() { + return GetParentAllocator() + ? GetParentAllocator()->client_surface_embedder_.get() + : nullptr; +} + viz::ParentLocalSurfaceIdAllocator* WindowPortMusTestHelper::GetParentLocalSurfaceIdAllocator() { - return &(window_port_mus_->parent_local_surface_id_allocator_); + return GetParentAllocator() + ? &(GetParentAllocator()->parent_local_surface_id_allocator_) + : nullptr; +} + +ParentAllocator* WindowPortMusTestHelper::GetParentAllocator() { + return window_port_mus_->allocator_ + ? static_cast<ParentAllocator*>(window_port_mus_->allocator_.get()) + : nullptr; } } // namespace aura
diff --git a/ui/aura/test/mus/window_port_mus_test_helper.h b/ui/aura/test/mus/window_port_mus_test_helper.h index 5076c80..efba3462 100644 --- a/ui/aura/test/mus/window_port_mus_test_helper.h +++ b/ui/aura/test/mus/window_port_mus_test_helper.h
@@ -20,6 +20,8 @@ namespace aura { +class ClientSurfaceEmbedder; +class ParentAllocator; class Window; class WindowPortMus; @@ -32,9 +34,13 @@ base::WeakPtr<cc::LayerTreeFrameSink> GetFrameSink(); + ClientSurfaceEmbedder* GetClientSurfaceEmbedder(); + viz::ParentLocalSurfaceIdAllocator* GetParentLocalSurfaceIdAllocator(); private: + ParentAllocator* GetParentAllocator(); + static uint32_t next_client_id_; WindowPortMus* window_port_mus_;
diff --git a/ui/aura/window_event_dispatcher_unittest.cc b/ui/aura/window_event_dispatcher_unittest.cc index 1e468048..9475308 100644 --- a/ui/aura/window_event_dispatcher_unittest.cc +++ b/ui/aura/window_event_dispatcher_unittest.cc
@@ -139,8 +139,11 @@ ui::EF_LEFT_MOUSE_BUTTON); DispatchEventUsingWindowDispatcher(&event1); - // Event was tested for non-client area for the target window. - EXPECT_EQ(1, delegate1->non_client_count()); + // Event was tested for non-client area for the target window. The expected + // value is 2 when mode is MUS, since ClientSideWindowMoveHandler also invokes + // it. + EXPECT_EQ((Env::GetInstance()->mode() == Env::Mode::MUS) ? 2 : 1, + delegate1->non_client_count()); EXPECT_EQ(0, delegate2->non_client_count()); // The non-client component test was in local coordinates. EXPECT_EQ(gfx::Point(1, 1), delegate1->non_client_location());
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc index a1143fc3..08ffa5e 100644 --- a/ui/aura/window_tree_host.cc +++ b/ui/aura/window_tree_host.cc
@@ -548,11 +548,6 @@ base::TimeTicks::Now() - synchronization_start_time_); } -void WindowTreeHost::OnCompositingStarted(ui::Compositor* compositor, - base::TimeTicks start_time) {} - -void WindowTreeHost::OnCompositingEnded(ui::Compositor* compositor) {} - void WindowTreeHost::OnCompositingChildResizing(ui::Compositor* compositor) { if (!window()->env()->throttle_input_on_resize() || holding_pointer_moves_) return;
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h index 0f9d461..7730ef6a 100644 --- a/ui/aura/window_tree_host.h +++ b/ui/aura/window_tree_host.h
@@ -336,9 +336,6 @@ // Overrided from CompositorObserver: void OnCompositingDidCommit(ui::Compositor* compositor) override; - void OnCompositingStarted(ui::Compositor* compositor, - base::TimeTicks start_time) override; - void OnCompositingEnded(ui::Compositor* compositor) override; void OnCompositingChildResizing(ui::Compositor* compositor) override; void OnCompositingShuttingDown(ui::Compositor* compositor) override;
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc index c5cfcd4..a7c1506 100644 --- a/ui/aura/window_unittest.cc +++ b/ui/aura/window_unittest.cc
@@ -3255,6 +3255,11 @@ } TEST_P(WindowTest, LocalSurfaceIdChanges) { + // This uses Window::CreateLayerTreeFrameSink(), which is not wired up in + // Mus. At this time it is only used for LOCAL, so it's not wired up for MUS. + if (GetParam() == Env::Mode::MUS) + return; + Window window(nullptr); window.Init(ui::LAYER_NOT_DRAWN); window.SetBounds(gfx::Rect(300, 300));
diff --git a/ui/base/accelerators/global_media_keys_listener_win.cc b/ui/base/accelerators/global_media_keys_listener_win.cc index 3dfa964a..824462ad 100644 --- a/ui/base/accelerators/global_media_keys_listener_win.cc +++ b/ui/base/accelerators/global_media_keys_listener_win.cc
@@ -27,12 +27,12 @@ has_instance_ = false; } -void GlobalMediaKeysListenerWin::StartWatchingMediaKey(KeyboardCode key_code) { +bool GlobalMediaKeysListenerWin::StartWatchingMediaKey(KeyboardCode key_code) { DCHECK(IsMediaKeycode(key_code)); // If the hotkey is already registered, do nothing. if (key_codes_hotkey_observers_.contains(key_code)) - return; + return true; // Create an observer that registers a hot key for |key_code|. std::unique_ptr<gfx::SingletonHwndHotKeyObserver> observer = @@ -48,6 +48,8 @@ UMA_HISTOGRAM_BOOLEAN("Media.MediaKeysListener.RegisterHotKeyResult", success); + + return success; } void GlobalMediaKeysListenerWin::StopWatchingMediaKey(KeyboardCode key_code) {
diff --git a/ui/base/accelerators/global_media_keys_listener_win.h b/ui/base/accelerators/global_media_keys_listener_win.h index 36faf39..4b95a20 100644 --- a/ui/base/accelerators/global_media_keys_listener_win.h +++ b/ui/base/accelerators/global_media_keys_listener_win.h
@@ -30,7 +30,7 @@ static bool has_instance() { return has_instance_; } // MediaKeysListener implementation. - void StartWatchingMediaKey(KeyboardCode key_code) override; + bool StartWatchingMediaKey(KeyboardCode key_code) override; void StopWatchingMediaKey(KeyboardCode key_code) override; private:
diff --git a/ui/base/accelerators/media_keys_listener.h b/ui/base/accelerators/media_keys_listener.h index 0b4d9a0..9072523c 100644 --- a/ui/base/accelerators/media_keys_listener.h +++ b/ui/base/accelerators/media_keys_listener.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/callback.h" +#include "base/observer_list_types.h" #include "ui/base/ui_base_export.h" #include "ui/events/keycodes/keyboard_codes.h" @@ -24,9 +25,9 @@ }; // Media keys accelerators receiver. - class UI_BASE_EXPORT Delegate { + class UI_BASE_EXPORT Delegate : public base::CheckedObserver { public: - virtual ~Delegate(); + ~Delegate() override; // Called on media key event. virtual void OnMediaKeysAccelerator(const Accelerator& accelerator) = 0; @@ -41,8 +42,11 @@ virtual ~MediaKeysListener(); - // Start listening for a given media key. - virtual void StartWatchingMediaKey(KeyboardCode key_code) = 0; + // Start listening for a given media key. Returns true if the listener + // successfully started listening for the key. Some implementations may not be + // able to register if another application is already listening to the media + // key. + virtual bool StartWatchingMediaKey(KeyboardCode key_code) = 0; // Stop listening for a given media key. virtual void StopWatchingMediaKey(KeyboardCode key_code) = 0; };
diff --git a/ui/base/accelerators/media_keys_listener_mac.mm b/ui/base/accelerators/media_keys_listener_mac.mm index 2320015..b48fa8e6 100644 --- a/ui/base/accelerators/media_keys_listener_mac.mm +++ b/ui/base/accelerators/media_keys_listener_mac.mm
@@ -42,7 +42,7 @@ ~MediaKeysListenerImpl() override; // MediaKeysListener: - void StartWatchingMediaKey(KeyboardCode key_code) override; + bool StartWatchingMediaKey(KeyboardCode key_code) override; void StopWatchingMediaKey(KeyboardCode key_code) override; private: @@ -80,9 +80,10 @@ StopEventTapIfNecessary(); } -void MediaKeysListenerImpl::StartWatchingMediaKey(KeyboardCode key_code) { +bool MediaKeysListenerImpl::StartWatchingMediaKey(KeyboardCode key_code) { key_codes_.insert(key_code); StartEventTapIfNecessary(); + return true; } void MediaKeysListenerImpl::StopWatchingMediaKey(KeyboardCode key_code) {
diff --git a/ui/base/cocoa/views_hostable.h b/ui/base/cocoa/views_hostable.h index 68c5cc56..f8160f94 100644 --- a/ui/base/cocoa/views_hostable.h +++ b/ui/base/cocoa/views_hostable.h
@@ -41,28 +41,28 @@ virtual void OnHostableViewDestroying() = 0; }; - // Called when the content::WebContentsView's NSView is added as a subview of - // the views::View's NSView (note that these are the browser-side NSViews). - // This is responsible for: + // Called to add the content::WebContentsView's NSView as a subview of the + // views::View's NSView. This is responsible for: // - Adding the WebContentsView's ui::Layer to the parent's ui::Layer tree. // - Stitching together the accessibility tree between the views::View and // the WebContentsView. - // - Stitching together any app-shim-side NSViews. - virtual void OnViewsHostableAttached(Host* host) = 0; + // - Adding the WebContents browser-side and app-shim-side NSViews as children + // to the views::View's NSViews. + virtual void ViewsHostableAttach(Host* host) = 0; // Called when the WebContentsView's NSView has been removed from the // views::View's NSView. This is responsible for un-doing all of the actions // taken when attaching. - virtual void OnViewsHostableDetached() = 0; + virtual void ViewsHostableDetach() = 0; - // Called when the WebContentsView's NSView is to be shown or resized. - virtual void OnViewsHostableShow(const gfx::Rect& bounds_in_window) = 0; + // Resize the WebContentsView's NSView. + virtual void ViewsHostableSetBounds(const gfx::Rect& bounds_in_window) = 0; - // Called when the WebContentsView's NSView is to be hidden. - virtual void OnViewsHostableHide() = 0; + // Show or hide the WebContentsView's NSView. + virtual void ViewsHostableSetVisible(bool visible) = 0; - // Called when the WebContentsView's NSView is to be made a first responder. - virtual void OnViewsHostableMakeFirstResponder() = 0; + // Make the WebContentsView's NSView be a first responder. + virtual void ViewsHostableMakeFirstResponder() = 0; }; } // namespace ui
diff --git a/ui/base/ime/chromeos/public/interfaces/BUILD.gn b/ui/base/ime/chromeos/public/interfaces/BUILD.gn index 3f07e550..02d27d6 100644 --- a/ui/base/ime/chromeos/public/interfaces/BUILD.gn +++ b/ui/base/ime/chromeos/public/interfaces/BUILD.gn
@@ -6,8 +6,11 @@ assert(is_chromeos) -mojom("interfaces") { +mojom_component("interfaces") { sources = [ "ime_keyset.mojom", ] + + macro_prefix = "UI_BASE_IME_MOJOM" + output_prefix = "ui_base_ime_mojom" }
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index 69be32bd..74e8d5b78 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -179,6 +179,20 @@ #endif settings.memory_policy.bytes_limit_when_visible = 512 * 1024 * 1024; + + // Used to configure ui compositor memory limit for chromeos devices. + // See crbug.com/923141. + if (command_line->HasSwitch( + switches::kUiCompositorMemoryLimitWhenVisibleMB)) { + std::string value_str = command_line->GetSwitchValueASCII( + switches::kUiCompositorMemoryLimitWhenVisibleMB); + unsigned value_in_mb; + if (base::StringToUint(value_str, &value_in_mb)) { + settings.memory_policy.bytes_limit_when_visible = + 1024 * 1024 * value_in_mb; + } + } + settings.memory_policy.priority_cutoff_when_visible = gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE; @@ -590,6 +604,12 @@ trace_environment_name_); } +void Compositor::DidGenerateLocalSurfaceIdAllocation( + const viz::LocalSurfaceIdAllocation& allocation) { + for (auto& observer : observer_list_) + observer.DidGenerateLocalSurfaceIdAllocation(this, allocation); +} + void Compositor::DidSubmitCompositorFrame() { base::TimeTicks start_time = base::TimeTicks::Now(); for (auto& observer : observer_list_)
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index a445b56..313431f 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -392,6 +392,8 @@ uint32_t frame_token, const gfx::PresentationFeedback& feedback) override; void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override {} + void DidGenerateLocalSurfaceIdAllocation( + const viz::LocalSurfaceIdAllocation& allocation) override; // cc::LayerTreeHostSingleThreadClient implementation. void DidSubmitCompositorFrame() override;
diff --git a/ui/compositor/compositor_observer.h b/ui/compositor/compositor_observer.h index 4225c8a..5745c3cb 100644 --- a/ui/compositor/compositor_observer.h +++ b/ui/compositor/compositor_observer.h
@@ -8,6 +8,10 @@ #include "base/time/time.h" #include "ui/compositor/compositor_export.h" +namespace viz { +class LocalSurfaceIdAllocation; +} + namespace ui { class Compositor; @@ -24,22 +28,30 @@ // between two composites (just before the composite as part of the // composite cycle). If the compositor is locked, it will not send this // this signal. - virtual void OnCompositingDidCommit(Compositor* compositor) = 0; + virtual void OnCompositingDidCommit(Compositor* compositor) {} // Called when compositing started: it has taken all the layer changes into // account and has issued the graphics commands. virtual void OnCompositingStarted(Compositor* compositor, - base::TimeTicks start_time) = 0; + base::TimeTicks start_time) {} // Called when compositing completes: the present to screen has completed. - virtual void OnCompositingEnded(Compositor* compositor) = 0; + virtual void OnCompositingEnded(Compositor* compositor) {} // Called when a child of the compositor is resizing. - virtual void OnCompositingChildResizing(Compositor* compositor) = 0; + virtual void OnCompositingChildResizing(Compositor* compositor) {} // Called at the top of the compositor's destructor, to give observers a // chance to remove themselves. - virtual void OnCompositingShuttingDown(Compositor* compositor) = 0; + virtual void OnCompositingShuttingDown(Compositor* compositor) {} + + // Called (asynchronously) when the compositor generates a new + // LocalSurfaceIdAllocation. For example, if + // LayerTreeHost::RequestNewLocalSurfaceId() is called, then this function + // is called once the compositor generates the new LocalSurfaceIdAllocation. + virtual void DidGenerateLocalSurfaceIdAllocation( + Compositor* compositor, + const viz::LocalSurfaceIdAllocation& allocation) {} }; } // namespace ui
diff --git a/ui/compositor/compositor_switches.cc b/ui/compositor/compositor_switches.cc index a61a7ba..842a3dc 100644 --- a/ui/compositor/compositor_switches.cc +++ b/ui/compositor/compositor_switches.cc
@@ -29,6 +29,9 @@ const char kDisableVsyncForTests[] = "disable-vsync-for-tests"; +const char kUiCompositorMemoryLimitWhenVisibleMB[] = + "ui-compositor-memory-limit-when-visible-mb"; + } // namespace switches namespace features {
diff --git a/ui/compositor/compositor_switches.h b/ui/compositor/compositor_switches.h index 8757e22e..d1abbfe 100644 --- a/ui/compositor/compositor_switches.h +++ b/ui/compositor/compositor_switches.h
@@ -18,6 +18,7 @@ COMPOSITOR_EXPORT extern const char kUIShowPaintRects[]; COMPOSITOR_EXPORT extern const char kUISlowAnimations[]; COMPOSITOR_EXPORT extern const char kDisableVsyncForTests[]; +COMPOSITOR_EXPORT extern const char kUiCompositorMemoryLimitWhenVisibleMB[]; } // namespace switches
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc index b1c724f..14be637e 100644 --- a/ui/compositor/layer.cc +++ b/ui/compositor/layer.cc
@@ -166,6 +166,9 @@ for (auto* child : children_) child->parent_ = nullptr; + if (content_layer_) + content_layer_->ClearClient(); + cc_layer_->SetLayerClient(nullptr); cc_layer_->RemoveFromParent(); if (transfer_release_callback_) transfer_release_callback_->Run(gpu::SyncToken(), false); @@ -638,7 +641,10 @@ new_layer->SetTrilinearFiltering(cc_layer_->trilinear_filtering()); cc_layer_ = new_layer.get(); - content_layer_ = nullptr; + if (content_layer_) { + content_layer_->ClearClient(); + content_layer_ = nullptr; + } solid_color_layer_ = nullptr; texture_layer_ = nullptr; surface_layer_ = nullptr;
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc index 492c6995..c710f7a 100644 --- a/ui/compositor/layer_unittest.cc +++ b/ui/compositor/layer_unittest.cc
@@ -413,10 +413,6 @@ void OnCompositingEnded(Compositor* compositor) override { ended_ = true; } - void OnCompositingChildResizing(Compositor* compositor) override {} - - void OnCompositingShuttingDown(Compositor* compositor) override {} - bool committed_ = false; bool started_ = false; bool ended_ = false;
diff --git a/ui/compositor/recyclable_compositor_mac.h b/ui/compositor/recyclable_compositor_mac.h index adbb2d49..d9991af 100644 --- a/ui/compositor/recyclable_compositor_mac.h +++ b/ui/compositor/recyclable_compositor_mac.h
@@ -56,11 +56,6 @@ // ui::CompositorObserver implementation: void OnCompositingDidCommit(ui::Compositor* compositor) override; - void OnCompositingStarted(ui::Compositor* compositor, - base::TimeTicks start_time) override {} - void OnCompositingEnded(ui::Compositor* compositor) override {} - void OnCompositingChildResizing(ui::Compositor* compositor) override {} - void OnCompositingShuttingDown(ui::Compositor* compositor) override {} std::unique_ptr<ui::AcceleratedWidgetMac> accelerated_widget_mac_; ui::Compositor compositor_;
diff --git a/ui/compositor/test/draw_waiter_for_test.cc b/ui/compositor/test/draw_waiter_for_test.cc index de34190..01787fd 100644 --- a/ui/compositor/test/draw_waiter_for_test.cc +++ b/ui/compositor/test/draw_waiter_for_test.cc
@@ -54,8 +54,4 @@ wait_run_loop_->Quit(); } -void DrawWaiterForTest::OnCompositingChildResizing(Compositor* compositor) {} - -void DrawWaiterForTest::OnCompositingShuttingDown(Compositor* compositor) {} - } // namespace ui
diff --git a/ui/compositor/test/draw_waiter_for_test.h b/ui/compositor/test/draw_waiter_for_test.h index bab832ce..0633560 100644 --- a/ui/compositor/test/draw_waiter_for_test.h +++ b/ui/compositor/test/draw_waiter_for_test.h
@@ -47,8 +47,6 @@ void OnCompositingStarted(Compositor* compositor, base::TimeTicks start_time) override; void OnCompositingEnded(Compositor* compositor) override; - void OnCompositingChildResizing(Compositor* compositor) override; - void OnCompositingShuttingDown(Compositor* compositor) override; std::unique_ptr<base::RunLoop> wait_run_loop_;
diff --git a/ui/file_manager/file_manager/background/js/mock_volume_manager.js b/ui/file_manager/file_manager/background/js/mock_volume_manager.js index ef9f7ee0..e02d30a 100644 --- a/ui/file_manager/file_manager/background/js/mock_volume_manager.js +++ b/ui/file_manager/file_manager/background/js/mock_volume_manager.js
@@ -167,7 +167,8 @@ false, // watchable VolumeManagerCommon.Source.NETWORK, // source VolumeManagerCommon.FileSystemType.UNKNOWN, // diskFileSystemType - {}); // iconSet + {}, // iconSet + ''); // driveLabel return volumeInfo; };
diff --git a/ui/file_manager/file_manager/background/js/volume_info_impl.js b/ui/file_manager/file_manager/background/js/volume_info_impl.js index 2c5a56b..157307d5 100644 --- a/ui/file_manager/file_manager/background/js/volume_info_impl.js +++ b/ui/file_manager/file_manager/background/js/volume_info_impl.js
@@ -36,11 +36,13 @@ * type indentifier. * @param {!chrome.fileManagerPrivate.IconSet} iconSet Set of icons for this * volume. + * @param {(string|undefined)} driveLabel Drive label of the volume. Removable + * partitions belonging to the same device will share the same drive label. */ function VolumeInfoImpl( volumeType, volumeId, fileSystem, error, deviceType, devicePath, isReadOnly, isReadOnlyRemovableDevice, profile, label, providerId, hasMedia, - configurable, watchable, source, diskFileSystemType, iconSet) { + configurable, watchable, source, diskFileSystemType, iconSet, driveLabel) { this.volumeType_ = volumeType; this.volumeId_ = volumeId; this.fileSystem_ = fileSystem; @@ -87,6 +89,7 @@ this.source_ = source; this.diskFileSystemType_ = diskFileSystemType; this.iconSet_ = iconSet; + this.driveLabel_ = driveLabel; /** @type {Promise<!DirectoryEntry>} */ this.displayRootPromise_ = this.resolveDisplayRootImpl_(); @@ -225,6 +228,14 @@ return this.iconSet_; }, /** + * @return {(string|undefined)} Drive label for the volume. Removable + * partitions belonging to the same physical media device will share the + * same drive label. + */ + get driveLabel() { + return this.driveLabel_; + }, + /** * @type {FilesAppEntry} an entry to be used as prefix of this volume on * breadcrumbs, e.g. "My Files > Downloads", "My Files" is a prefixEntry * on "Downloads" VolumeInfo.
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js b/ui/file_manager/file_manager/background/js/volume_manager_unittest.js index 13ba396..8f79539 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js +++ b/ui/file_manager/file_manager/background/js/volume_manager_unittest.js
@@ -376,7 +376,8 @@ /* watchable */ true, /* source */ VolumeManagerCommon.Source.FILE, /* diskFileSystemType */ VolumeManagerCommon.FileSystemType.UNKNOWN, - /* iconSet*/ {}); + /* iconSet*/ {}, + /* driveLabel*/ 'TEST_DRIVE_LABEL'); volumeManager.volumeInfoList.add(volumeInfo); const promiseAfterAdd = volumeManager.whenVolumeInfoReady('volumeId'); reportPromise(
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_util.js b/ui/file_manager/file_manager/background/js/volume_manager_util.js index ebf3090..d654b6ae 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager_util.js +++ b/ui/file_manager/file_manager/background/js/volume_manager_util.js
@@ -173,7 +173,8 @@ /** @type {VolumeManagerCommon.Source} */ (volumeMetadata.source), /** @type {VolumeManagerCommon.FileSystemType} */ - (volumeMetadata.diskFileSystemType), volumeMetadata.iconSet); + (volumeMetadata.diskFileSystemType), volumeMetadata.iconSet, + (volumeMetadata.driveLabel)); }) .catch( /** @param {*} error */ @@ -197,6 +198,7 @@ /** @type {VolumeManagerCommon.Source} */ (volumeMetadata.source), /** @type {VolumeManagerCommon.FileSystemType} */ - (volumeMetadata.diskFileSystemType), volumeMetadata.iconSet); + (volumeMetadata.diskFileSystemType), volumeMetadata.iconSet, + (volumeMetadata.driveLabel)); }); };
diff --git a/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html b/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html index 0adfc3d..fc759ca 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html +++ b/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html
@@ -50,27 +50,27 @@ } </style> <div id="box"> - <div class="category" i18n-content="METADATA_BOX_GENERAL_INFO"></div> - <files-metadata-entry i18n-values="key:METADATA_BOX_FILE_SIZE" value="[[size]]" loading="[[isSizeLoading]]"></files-metadata-entry> - <files-metadata-entry i18n-values="key:METADATA_BOX_MODIFICATION_TIME" value="[[modificationTime]]"></files-metadata-entry> + <div class="category">$i18n{METADATA_BOX_GENERAL_INFO}</div> + <files-metadata-entry key="$i18n{METADATA_BOX_FILE_SIZE}" value="[[size]]" loading="[[isSizeLoading]]"></files-metadata-entry> + <files-metadata-entry key="$i18n{METADATA_BOX_MODIFICATION_TIME}" value="[[modificationTime]]"></files-metadata-entry> <files-metadata-entry key="$i18n{METADATA_BOX_MEDIA_MIME_TYPE}" value="[[mediaMimeType]]"></files-metadata-entry> <div hidden="[[!hasFileSpecificInfo_]]"> <hr> - <div class="category" hidden="[[!isImage_(type)]]" i18n-content="METADATA_BOX_IMAGE_INFO"></div> - <div class="category" hidden="[[!isAudio_(type)]]" i18n-content="METADATA_BOX_AUDIO_INFO"></div> - <div class="category" hidden="[[!isVideo_(type)]]" i18n-content="METADATA_BOX_VIDEO_INFO"></div> - <files-metadata-entry i18n-values="key:METADATA_BOX_DIMENSION" value="[[dimension_(imageWidth, imageHeight)]]"></files-metadata-entry> - <files-metadata-entry i18n-values="key:METADATA_BOX_ALBUM_TITLE" value="[[mediaAlbum]]"></files-metadata-entry> - <files-metadata-entry i18n-values="key:METADATA_BOX_MEDIA_TITLE" value="[[mediaTitle]]"></files-metadata-entry> - <files-metadata-entry i18n-values="key:METADATA_BOX_MEDIA_ARTIST" value="[[mediaArtist]]"></files-metadata-entry> - <files-metadata-entry i18n-values="key:METADATA_BOX_DURATION" value="[[time2string_(mediaDuration)]]"></files-metadata-entry> - <files-metadata-entry i18n-values="key:METADATA_BOX_GENRE" value="[[mediaGenre]]"></files-metadata-entry> - <files-metadata-entry i18n-values="key:METADATA_BOX_TRACK" value="[[mediaTrack]]"></files-metadata-entry> - <files-metadata-entry i18n-values="key:METADATA_BOX_EXIF_DEVICE_MODEL" value="[[deviceModel_(ifd)]]"></files-metadata-entry> - <files-metadata-entry i18n-values="key:METADATA_BOX_EXIF_DEVICE_SETTINGS" value="[[deviceSettings_(ifd)]]"></files-metadata-entry> - <files-metadata-entry i18n-values="key:METADATA_BOX_EXIF_GEOGRAPHY" value="[[geography_(ifd)]]"></files-metadata-entry> - <files-metadata-entry i18n-values="key:METADATA_BOX_YEAR_RECORDED" value="[[mediaYearRecorded]]"></files-metadata-entry> + <div class="category" hidden="[[!isImage_(type)]]">$i18n{METADATA_BOX_IMAGE_INFO}</div> + <div class="category" hidden="[[!isAudio_(type)]]">$i18n{METADATA_BOX_AUDIO_INFO}</div> + <div class="category" hidden="[[!isVideo_(type)]]">$i18n{METADATA_BOX_VIDEO_INFO}</div> + <files-metadata-entry key="$i18n{METADATA_BOX_DIMENSION}" value="[[dimension_(imageWidth, imageHeight)]]"></files-metadata-entry> + <files-metadata-entry key="$i18n{METADATA_BOX_ALBUM_TITLE}" value="[[mediaAlbum]]"></files-metadata-entry> + <files-metadata-entry key="$i18n{METADATA_BOX_MEDIA_TITLE}" value="[[mediaTitle]]"></files-metadata-entry> + <files-metadata-entry key="$i18n{METADATA_BOX_MEDIA_ARTIST}" value="[[mediaArtist]]"></files-metadata-entry> + <files-metadata-entry key="$i18n{METADATA_BOX_DURATION}" value="[[time2string_(mediaDuration)]]"></files-metadata-entry> + <files-metadata-entry key="$i18n{METADATA_BOX_GENRE}" value="[[mediaGenre]]"></files-metadata-entry> + <files-metadata-entry key="$i18n{METADATA_BOX_TRACK}" value="[[mediaTrack]]"></files-metadata-entry> + <files-metadata-entry key="$i18n{METADATA_BOX_EXIF_DEVICE_MODEL}" value="[[deviceModel_(ifd)]]"></files-metadata-entry> + <files-metadata-entry key="$i18n{METADATA_BOX_EXIF_DEVICE_SETTINGS}" value="[[deviceSettings_(ifd)]]"></files-metadata-entry> + <files-metadata-entry key="$i18n{METADATA_BOX_EXIF_GEOGRAPHY}" value="[[geography_(ifd)]]"></files-metadata-entry> + <files-metadata-entry key="$i18n{METADATA_BOX_YEAR_RECORDED}" value="[[mediaYearRecorded]]"></files-metadata-entry> </div> </div> </template>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html index b581a8224..d9f2c89 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html
@@ -18,16 +18,16 @@ <dialog id="dialog"> <div id="toolbar"> <div class="buttons-group"> - <paper-button on-tap="close" i18n-values="aria-label:QUICK_VIEW_CLOSE_BUTTON_LABEL" tabindex="0" has-tooltip> + <paper-button on-tap="close" aria-label="$i18n{QUICK_VIEW_CLOSE_BUTTON_LABEL}" tabindex="0" has-tooltip> <iron-icon icon="files:arrow-back"></iron-icon> </paper-button> </div> <div id="file-path">[[filePath]]</div> <div class="buttons-group"> - <paper-button id="open-button" on-tap="onOpenInNewButtonTap" hidden$="[[!hasTask]]" i18n-values="aria-label:QUICK_VIEW_OPEN_IN_NEW_BUTTON_LABEL" tabindex="0" has-tooltip> + <paper-button id="open-button" on-tap="onOpenInNewButtonTap" hidden$="[[!hasTask]]" aria-label="$i18n{QUICK_VIEW_OPEN_IN_NEW_BUTTON_LABEL}" tabindex="0" has-tooltip> <iron-icon icon="files:open-in-new"></iron-icon> </paper-button> - <files-icon-button toggles id="metadata-button" on-tap="onMetadataButtonTap_" active="{{metadataBoxActive}}" i18n-values="aria-label:QUICK_VIEW_TOGGLE_METADATA_BOX_BUTTON_LABEL" tabindex="0" has-tooltip> + <files-icon-button toggles id="metadata-button" on-tap="onMetadataButtonTap_" active="{{metadataBoxActive}}" aria-label="$i18n{QUICK_VIEW_TOGGLE_METADATA_BOX_BUTTON_LABEL}" tabindex="0" has-tooltip> </files-icon-button> </div> </div>
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js index 9a50971..3f972c4 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -999,9 +999,6 @@ util.addIsFocusedMethod(); - // Populate the static localized strings. - i18nTemplate.process(this.document_, loadTimeData); - // The cwd is not known at this point. Hide the import status column before // redrawing, to avoid ugly flashing in the UI, caused when the first redraw // has a visible status column, and then the cwd is later discovered to be
diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js index 60990b54..b61f869b 100644 --- a/ui/file_manager/file_manager/foreground/js/main_scripts.js +++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -37,7 +37,6 @@ // <include src="../../../../webui/resources/js/action_link.js"> // <include src="../../../../webui/resources/js/cr.js"> // <include src="../../../../webui/resources/js/util.js"> -// <include src="../../../../webui/resources/js/i18n_template_no_process.js"> // // <include src="../../../../webui/resources/js/event_tracker.js"> // <include src="../../../../webui/resources/js/cr/ui.js">
diff --git a/ui/file_manager/file_manager/foreground/js/providers_model_unittest.js b/ui/file_manager/file_manager/foreground/js/providers_model_unittest.js index cb142d6..e25e567 100644 --- a/ui/file_manager/file_manager/foreground/js/providers_model_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/providers_model_unittest.js
@@ -122,7 +122,8 @@ false, // watchable VolumeManagerCommon.Source.NETWORK, // source VolumeManagerCommon.FileSystemType.UNKNOWN, // diskFileSystemType - {}); // iconSet + {}, // iconSet + ''); // driveLabel volumeManager.volumeInfoList.add(volumeInfo); }
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js index aa16948..a4926ed 100644 --- a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js +++ b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
@@ -179,7 +179,6 @@ return new Promise(function(resolve, reject) { Polymer.Base.importHref(constants.FILES_QUICK_VIEW_HTML, function() { var quickView = document.querySelector('#quick-view'); - i18nTemplate.process(quickView, loadTimeData); resolve(quickView); }, reject); });
diff --git a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn index 55e9285..a943c32 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn +++ b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
@@ -254,7 +254,6 @@ "//ui/file_manager/file_manager/foreground/elements:files_tooltip", "//ui/file_manager/file_manager/foreground/js:launch_param", "//ui/file_manager/file_manager/foreground/js:providers_model", - "//ui/webui/resources/js:i18n_template_no_process", "//ui/webui/resources/js:util", "//ui/webui/resources/js/cr/ui:context_menu_button", "//ui/webui/resources/js/cr/ui:dialogs",
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners.js b/ui/file_manager/file_manager/foreground/js/ui/banners.js index 07045e9..771c894 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/banners.js +++ b/ui/file_manager/file_manager/foreground/js/ui/banners.js
@@ -22,7 +22,6 @@ this.showWelcome_ = showWelcome; this.driveEnabled_ = false; - this.usePromoWelcomeBanner_ = true; this.privateOnDirectoryChangedBound_ = this.privateOnDirectoryChanged_.bind(this); @@ -239,34 +238,15 @@ var links = util.createChild(message, 'drive-welcome-links'); - var more; - if (this.usePromoWelcomeBanner_) { - var welcomeTitle = str('DRIVE_WELCOME_TITLE_ALTERNATIVE'); - title.textContent = welcomeTitle; - more = util.createChild(links, '', 'a'); - more.href = str('GOOGLE_DRIVE_REDEEM_URL'); - var moreInnerButton = util.createChild( - more, 'imitate-paper-button primary', 'button'); - moreInnerButton.tabIndex = -1; - moreInnerButton.textContent = str('DRIVE_WELCOME_CHECK_ELIGIBILITY'); - } else { - title.textContent = str('DRIVE_WELCOME_TITLE'); - more = util.createChild(links, 'plain-link', 'a'); - more.textContent = str('DRIVE_LEARN_MORE'); - more.href = str('GOOGLE_DRIVE_OVERVIEW_URL'); - } + title.textContent = str('DRIVE_WELCOME_TITLE'); + const more = util.createChild(links, 'plain-link', 'a'); + more.textContent = str('DRIVE_LEARN_MORE'); + more.href = str('GOOGLE_DRIVE_OVERVIEW_URL'); more.tabIndex = 21; // See: go/filesapp-tabindex. more.id = 'drive-welcome-link'; more.target = '_blank'; - var dismiss; - if (this.usePromoWelcomeBanner_) { - dismiss = util.createChild( - links, 'imitate-paper-button secondary', 'button'); - } else { - dismiss = util.createChild(links, 'plain-link'); - } - + const dismiss = util.createChild(links, 'plain-link'); dismiss.classList.add('drive-welcome-dismiss'); dismiss.textContent = str('DRIVE_WELCOME_DISMISS'); dismiss.addEventListener('click', this.closeWelcomeBanner_.bind(this)); @@ -379,53 +359,7 @@ return; } - if (!this.showOffers_ || !this.showWelcome_) { - // Because it is not necessary to show the offer, set - // |usePromoWelcomeBanner_| false here. Note that it probably should be - // able to do this in the constructor, but there remains non-trivial path, - // which may be causes |usePromoWelcomeBanner_| == true's behavior even - // if |showOffers_| is false. - // TODO(hidehiko): Make sure if it is expected or not, and simplify - // |showOffers_| if possible. - this.usePromoWelcomeBanner_ = false; - } - - var offerSize = 100; // In GB. - var offerServiceId = 'drive.cros.echo.1'; - - // Perform asynchronous tasks in parallel. - var group = new AsyncUtil.Group(); - - // If the offer has been checked, then do not show the promo anymore. - group.add(function(onCompleted) { - chrome.echoPrivate.getOfferInfo(offerServiceId, function(offerInfo) { - // If the offer has not been checked, then an error is raised. - if (!chrome.runtime.lastError) { - this.usePromoWelcomeBanner_ = false; - } - onCompleted(); - }.bind(this)); - }.bind(this)); - - group.add(function(onCompleted) { - if (this.usePromoWelcomeBanner_) { - // getSizeStats for Drive file system accesses to the server, so we - // should minimize the invocation. - - // Current directory must be set, since this code is called after - // scanning is completed. However, the volumeInfo may be gone. - chrome.fileManagerPrivate.getSizeStats( - driveVolume.volumeId, function(result) { - if (result && - result.totalSize >= offerSize * 1024 * 1024 * 1024) { - this.usePromoWelcomeBanner_ = false; - } - onCompleted(); - }.bind(this)); - } - }.bind(this)); - - group.run(this.maybeShowWelcomeBanner_.bind(this)); + this.maybeShowWelcomeBanner_(); }.bind(this)); };
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js index 5716b99..80642ca16 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js +++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -900,6 +900,7 @@ if (window.IN_TEST) { item.setAttribute('volume-type-for-testing', item.volumeInfo_.volumeType); item.setAttribute('dir-type', 'VolumeItem'); + item.setAttribute('drive-label', item.volumeInfo_.driveLabel); } item.setupIcon_(item.querySelector('.icon'), item.volumeInfo_);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js index f929527..4258c2f4 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -12,9 +12,6 @@ * @struct */ function FileManagerUI(providersModel, element, launchParam) { - // Pre-populate the static localized strings. - i18nTemplate.process(element.ownerDocument, loadTimeData); - // Initialize the dialog label. This should be done before constructing dialog // instances. cr.ui.dialogs.BaseDialog.OK_LABEL = str('OK_LABEL');
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html index d13ce14..558abedf 100644 --- a/ui/file_manager/file_manager/main.html +++ b/ui/file_manager/file_manager/main.html
@@ -4,7 +4,7 @@ -- Use of this source code is governed by a BSD-style license that can be -- found in the LICENSE file. --> -<html i18n-values="dir:textdirection;lang:language"> +<html dir="$i18n{textdirection}" lang="$i18n{language}"> <head> <title></title> @@ -89,40 +89,40 @@ </custom-style> <commands> - <command id="cut" i18n-values="label:CUT_BUTTON_LABEL" + <command id="cut" label="$i18n{CUT_BUTTON_LABEL}" shortcut="x|Ctrl"> - <command id="copy" i18n-values="label:COPY_BUTTON_LABEL" + <command id="copy" label="$i18n{COPY_BUTTON_LABEL}" shortcut="c|Ctrl"> - <command id="paste" i18n-values="label:PASTE_BUTTON_LABEL" + <command id="paste" label="$i18n{PASTE_BUTTON_LABEL}" shortcut="v|Ctrl"> - <command id="paste-into-current-folder" i18n-values="label:PASTE_BUTTON_LABEL" + <command id="paste-into-current-folder" label="$i18n{PASTE_BUTTON_LABEL}" shortcut="v|Ctrl"> <command id="paste-into-folder" - i18n-values="label:PASTE_INTO_FOLDER_BUTTON_LABEL"> - <command id="get-info" i18n-values="label:GET_INFO_BUTTON_LABEL" + label="$i18n{PASTE_INTO_FOLDER_BUTTON_LABEL}"> + <command id="get-info" label="$i18n{GET_INFO_BUTTON_LABEL}" shortcut="Space"> - <command id="rename" i18n-values="label:RENAME_BUTTON_LABEL" + <command id="rename" label="$i18n{RENAME_BUTTON_LABEL}" shortcut="Enter|Ctrl"> <command id="delete" shortcut="Backspace|Alt Delete"> - <command id="refresh" i18n-values="label:REFRESH_BUTTON_LABEL" + <command id="refresh" label="$i18n{REFRESH_BUTTON_LABEL}" shortcut="b|Ctrl" hidden> <command id="create-folder-shortcut" - i18n-values="label:CREATE_FOLDER_SHORTCUT_BUTTON_LABEL"> + label="$i18n{CREATE_FOLDER_SHORTCUT_BUTTON_LABEL}"> <command id="remove-folder-shortcut" - i18n-values="label:REMOVE_FOLDER_SHORTCUT_BUTTON_LABEL"> - <command id="new-folder" i18n-values="label:NEW_FOLDER_BUTTON_LABEL" + label="$i18n{REMOVE_FOLDER_SHORTCUT_BUTTON_LABEL}"> + <command id="new-folder" label="$i18n{NEW_FOLDER_BUTTON_LABEL}" shortcut="e|Ctrl"> - <command id="new-window" i18n-values="label:NEW_WINDOW_BUTTON_LABEL" + <command id="new-window" label="$i18n{NEW_WINDOW_BUTTON_LABEL}" shortcut="n|Ctrl"> - <command id="new-service" i18n-values="label:INSTALL_NEW_EXTENSION_LABEL"> + <command id="new-service" label="$i18n{INSTALL_NEW_EXTENSION_LABEL}"> </command> <!-- Note that actual shortcut Ctrl/Meta+A is handled in ListSelectionController.handleKeyDown --> <command id="select-all" - i18n-values="label:SELECT_ALL_COMMAND_LABEL" + label="$i18n{SELECT_ALL_COMMAND_LABEL}" shortcut="a|Ctrl"> <command id="drive-sync-settings" - i18n-values="label:DRIVE_MOBILE_CONNECTION_OPTION"> + label="$i18n{DRIVE_MOBILE_CONNECTION_OPTION}"> <command id="search" shortcut="f|Ctrl /"> <!-- Shortcuts for toggling between volumes (CTRL-1..CTRL-9). --> @@ -136,49 +136,49 @@ <command id="volume-switch-8" shortcut="8|Ctrl"> <command id="volume-switch-9" shortcut="9|Ctrl"> - <command id="unmount" i18n-values="label:UNMOUNT_DEVICE_BUTTON_LABEL" + <command id="unmount" label="$i18n{UNMOUNT_DEVICE_BUTTON_LABEL}" shortcut="E|Shift|Ctrl"> - <command id="format" i18n-values="label:FORMAT_DEVICE_BUTTON_LABEL"> - <command id="configure" i18n-values="label:CONFIGURE_VOLUME_BUTTON_LABEL"> + <command id="format" label="$i18n{FORMAT_DEVICE_BUTTON_LABEL}"> + <command id="configure" label="$i18n{CONFIGURE_VOLUME_BUTTON_LABEL}"> - <command id="volume-help" i18n-values="label:DRIVE_MENU_HELP"> + <command id="volume-help" label="$i18n{DRIVE_MENU_HELP}"> <command id="volume-storage"> <command id="drive-buy-more-space" - i18n-values="label:DRIVE_BUY_MORE_SPACE"> + label="$i18n{DRIVE_BUY_MORE_SPACE}"> <command id="drive-go-to-drive" - i18n-values="label:DRIVE_VISIT_DRIVE_GOOGLE_COM"> + label="$i18n{DRIVE_VISIT_DRIVE_GOOGLE_COM}"> - <command id="toggle-pinned" i18n-values="label:OFFLINE_COLUMN_LABEL"> + <command id="toggle-pinned" label="$i18n{OFFLINE_COLUMN_LABEL}"> <command id="toggle-hidden-files" - i18n-values="label:TOGGLE_HIDDEN_FILES_COMMAND_LABEL" + label="$i18n{TOGGLE_HIDDEN_FILES_COMMAND_LABEL}" shortcut=".|Ctrl" hide-shortcut-text> <command id="toggle-hidden-android-folders" - i18n-values="label:SHOW_ALL_ANDROID_FOLDERS_OPTION"> + label="$i18n{SHOW_ALL_ANDROID_FOLDERS_OPTION}"> <command id="default-task"> - <command id="open-with" i18n-values="label:OPEN_WITH_BUTTON_LABEL"> - <command id="more-actions" i18n-values="label:MORE_ACTIONS_BUTTON_LABEL"> - <command id="show-submenu" i18n-values="label:MORE_ACTIONS_BUTTON_LABEL"> + <command id="open-with" label="$i18n{OPEN_WITH_BUTTON_LABEL}"> + <command id="more-actions" label="$i18n{MORE_ACTIONS_BUTTON_LABEL}"> + <command id="show-submenu" label="$i18n{MORE_ACTIONS_BUTTON_LABEL}"> <command id="zip-selection" - i18n-values="label:ZIP_SELECTION_BUTTON_LABEL"> + label="$i18n{ZIP_SELECTION_BUTTON_LABEL}"> <command id="set-wallpaper" - i18n-values="label:SET_WALLPAPER_BUTTON_LABEL"> + label="$i18n{SET_WALLPAPER_BUTTON_LABEL}"> - <command id="share" i18n-values="label:SHARE_BUTTON_LABEL" disabled hidden + <command id="share" label="$i18n{SHARE_BUTTON_LABEL}" disabled hidden shortcut="." hide-shortcut-text> <command id="manage-in-drive" - i18n-values="label:MANAGE_IN_DRIVE_BUTTON_LABEL" disabled hidden> - <command id="share-with-linux" i18n-values="label:SHARE_WITH_LINUX_BUTTON_LABEL" disabled hidden> - <command id="manage-linux-sharing" i18n-values="label:MANAGE_LINUX_SHARING_BUTTON_LABEL" disabled hidden> + label="$i18n{MANAGE_IN_DRIVE_BUTTON_LABEL}" disabled hidden> + <command id="share-with-linux" label="$i18n{SHARE_WITH_LINUX_BUTTON_LABEL}" disabled hidden> + <command id="manage-linux-sharing" label="$i18n{MANAGE_LINUX_SHARING_BUTTON_LABEL}" disabled hidden> <command id="zoom-in" shortcut="=|Ctrl"> <command id="zoom-out" shortcut="-|Ctrl"> <command id="zoom-reset" shortcut="0|Ctrl"> - <command id="sort-by-name" i18n-values="label:NAME_COLUMN_LABEL"> - <command id="sort-by-size" i18n-values="label:SIZE_COLUMN_LABEL"> - <command id="sort-by-type" i18n-values="label:TYPE_COLUMN_LABEL"> - <command id="sort-by-date" i18n-values="label:DATE_COLUMN_LABEL"> + <command id="sort-by-name" label="$i18n{NAME_COLUMN_LABEL}"> + <command id="sort-by-size" label="$i18n{SIZE_COLUMN_LABEL}"> + <command id="sort-by-type" label="$i18n{TYPE_COLUMN_LABEL}"> + <command id="sort-by-date" label="$i18n{DATE_COLUMN_LABEL}"> <!-- Shortcuts to open inspector. (Ctrl+Shift+I/J/C/B) --> <command id="inspect-normal" shortcut="I|Shift|Ctrl"> @@ -187,7 +187,7 @@ <command id="inspect-background" shortcut="B|Shift|Ctrl"> <command id="install-new-extension" - i18n-values="label:INSTALL_NEW_EXTENSION_LABEL"> + label="$i18n{INSTALL_NEW_EXTENSION_LABEL}"> <command id="open-gear-menu" shortcut="e|Alt f|Alt"> <command id="browser-back" shortcut="BrowserBack"> <command id="focus-action-bar" shortcut="a|Alt"> @@ -211,8 +211,7 @@ <cr-menu-item command="#get-info"></cr-menu-item> <cr-menu-item command="#rename"></cr-menu-item> <cr-menu-item command="#create-folder-shortcut"></cr-menu-item> - <cr-menu-item command="#delete" i18n-content="DELETE_BUTTON_LABEL" - class="hide-on-toolbar"></cr-menu-item> + <cr-menu-item command="#delete" class="hide-on-toolbar">$i18n{DELETE_BUTTON_LABEL}</cr-menu-item> <cr-menu-item command="#zip-selection"></cr-menu-item> <cr-menu-item command="#share-with-linux"></cr-menu-item> <cr-menu-item command="#set-wallpaper"></cr-menu-item> @@ -240,7 +239,7 @@ <hr visibleif="full-page"> <cr-menu-item command="#rename"></cr-menu-item> <cr-menu-item command="#create-folder-shortcut"></cr-menu-item> - <cr-menu-item command="#delete" i18n-content="DELETE_BUTTON_LABEL"></cr-menu-item> + <cr-menu-item command="#delete">$i18n{DELETE_BUTTON_LABEL}</cr-menu-item> <hr visibleif="saveas-file full-page"> <cr-menu-item command="#new-folder" visibleif="saveas-file full-page"></cr-menu-item> </cr-menu> @@ -320,7 +319,7 @@ <cr-menu-item command="#cut"></cr-menu-item> <cr-menu-item command="#copy"></cr-menu-item> <cr-menu-item command="#paste"></cr-menu-item> - <cr-menu-item command="#delete" i18n-content="DELETE_BUTTON_LABEL"></cr-menu-item> + <cr-menu-item command="#delete">$i18n{DELETE_BUTTON_LABEL}</cr-menu-item> </cr-menu> <cr-menu id="share-sub-menu" class="chrome-menu files-menu" @@ -331,9 +330,9 @@ <div id="location-breadcrumbs" class="breadcrumbs"></div> <div id="cancel-selection-button-wrapper"> <paper-button id="cancel-selection-button" class="menu-button" tabindex="8" - i18n-values="aria-label:CANCEL_SELECTION_BUTTON_LABEL"> + aria-label="$i18n{CANCEL_SELECTION_BUTTON_LABEL}"> <span class="icon-arrow-back"></span> - <span id="cancel-selection-label" i18n-content="CANCEL_SELECTION_BUTTON_LABEL"></span> + <span id="cancel-selection-label">$i18n{CANCEL_SELECTION_BUTTON_LABEL}</span> </paper-button> </div> <div id="files-selected-label"></div> @@ -341,38 +340,38 @@ <div id="action-bar"> <button id="tasks" class="combobutton menu-button" menu="#tasks-menu" tabindex="10" hidden - i18n-values="aria-label:TASKS_BUTTON_LABEL"> + aria-label="$i18n{TASKS_BUTTON_LABEL}"> </button> <button id="share-menu-button" class="icon-button menu-button" tabindex="11" hidden menu="#share-menu" - i18n-values="aria-label:SHARE_BUTTON_TOOLTIP" + aria-label="$i18n{SHARE_BUTTON_TOOLTIP}" aria-activedescendant="share-menu" has-tooltip> <files-toggle-ripple></files-toggle-ripple> <div class="icon"></div> </button> <button id="delete-button" class="icon-button menu-button" tabindex="12" hidden - i18n-values="aria-label:DELETE_BUTTON_LABEL" + aria-label="$i18n{DELETE_BUTTON_LABEL}" visibleif="full-page" has-tooltip> <files-ripple></files-ripple> <div class="icon"></div> </button> <button id="search-button" class="icon-button menu-button" tabindex="13" - i18n-values="aria-label:SEARCH_TEXT_LABEL" + aria-label="$i18n{SEARCH_TEXT_LABEL}" has-tooltip> <files-toggle-ripple></files-toggle-ripple> <div class="icon"></div> </button> <div id="search-box"> <cr-input type="search" tabindex="14" hidden - i18n-values="aria-label:SEARCH_TEXT_LABEL;placeholder:SEARCH_TEXT_LABEL"> + aria-label="$i18n{SEARCH_TEXT_LABEL}" placeholder="$i18n{SEARCH_TEXT_LABEL}"> <span class="clear" slot="suffix" tabindex="14" - i18n-values="aria-label:SEARCH_CLEAR_LABEL" has-tooltip></span> + aria-label="$i18n{SEARCH_CLEAR_LABEL}" has-tooltip></span> </cr-input> </div> <button id="refresh-button" class="icon-button menu-button" tabindex="15" hidden - i18n-values="aria-label:REFRESH_BUTTON_LABEL" + aria-label="$i18n{REFRESH_BUTTON_LABEL}" command="#refresh" has-tooltip> <files-ripple></files-ripple> <div class="icon"></div> @@ -384,14 +383,14 @@ <button id="cloud-import-button" class="icon-button menu-button" tabindex="16" - i18n-values="aria-label:CLOUD_IMPORT_COMMAND" + aria-label="$i18n{CLOUD_IMPORT_COMMAND}" has-tooltip> <iron-icon icon="files:cloud-queue"></iron-icon> </button> <button id="cloud-import-details-button" class="icon-button menu-button" tabindex="16" - i18n-values="aria-label:CLOUD_IMPORT_SHOW_DETAILS" + aria-label="$i18n{CLOUD_IMPORT_SHOW_DETAILS}" has-tooltip> <iron-icon icon="files:arrow-drop-down"></iron-icon> </button> @@ -402,14 +401,14 @@ </div> </div> <button id="view-button" class="icon-button menu-button" tabindex="17" - i18n-values="aria-label:CHANGE_TO_THUMBNAILVIEW_BUTTON_LABEL" + aria-label="$i18n{CHANGE_TO_THUMBNAILVIEW_BUTTON_LABEL}" has-tooltip> <files-ripple></files-ripple> <div class="icon"></div> </button> <button id="sort-button" class="icon-button menu-button" tabindex="18" menu="#sort-menu" - i18n-values="aria-label:SORT_BUTTON_TOOLTIP" + aria-label="$i18n{SORT_BUTTON_TOOLTIP}" aria-activedescendant="sort-menu" has-tooltip> <files-toggle-ripple></files-toggle-ripple> @@ -417,7 +416,7 @@ </button> <button id="gear-button" class="icon-button menu-button" tabindex="19" menu="#gear-menu" - i18n-values="aria-label:GEAR_BUTTON_TOOLTIP" + aria-label="$i18n{GEAR_BUTTON_TOOLTIP}" aria-activedescendant="gear-menu" has-tooltip> <files-toggle-ripple></files-toggle-ripple> @@ -425,7 +424,7 @@ </button> <button id="selection-menu-button" class="icon-button menu-button" tabindex="19" menu="#file-context-menu" - i18n-values="aria-label:SELECTION_MENU_BUTTON_TOOLTIP" + aria-label="$i18n{SELECTION_MENU_BUTTON_TOOLTIP}" aria-activedescendant="file-context-menu" has-tooltip hidden> <files-toggle-ripple></files-toggle-ripple> @@ -436,8 +435,8 @@ <div id="cloud-import-details" class="hidden" hidden> <div class="banner"> - <div class="title" i18n-content="CLOUD_IMPORT_TITLE"></div> - <div class="description" i18n-content="CLOUD_IMPORT_DESCRIPTION"></div> + <div class="title">$i18n{CLOUD_IMPORT_TITLE}</div> + <div class="description">$i18n{CLOUD_IMPORT_DESCRIPTION}</div> </div> <div class="main"> <div class="status"> @@ -446,10 +445,10 @@ </div> <div class="progress"><div class="value"></div></div> <paper-button class="import" tabindex="16"> - <span i18n-content="CLOUD_IMPORT_COMMAND"></span> + <span>$i18n{CLOUD_IMPORT_COMMAND}</span> </paper-button> <paper-button class="cancel" tabindex="16"> - <span i18n-content="CLOUD_IMPORT_CANCEL_COMMAND"></span> + <span>$i18n{CLOUD_IMPORT_CANCEL_COMMAND}</span> </paper-button> </div> </div> @@ -494,10 +493,10 @@ </div> <div class="downloads-warning" hidden></div> <div id="list-container"> - <div id="more-actions-info" i18n-content="SEE_MENU_FOR_ACTIONS" hidden></div> + <div id="more-actions-info" hidden>$i18n{SEE_MENU_FOR_ACTIONS}</div> <div id="empty-folder" hidden> <div class="image"></div> - <span id="empty-folder-label" class="label" i18n-content="EMPTY_FOLDER"></span> + <span id="empty-folder-label" class="label">$i18n{EMPTY_FOLDER}</span> </div> <div class="detail-table" id="detail-table" tabindex="1" autofocus> </div> @@ -522,21 +521,21 @@ <button id="new-folder-button" class="primary" visibleif="saveas-file folder" tabindex="3" disabled> <paper-ripple fit></paper-ripple> - <span i18n-content="NEW_FOLDER_BUTTON_LABEL"></span> + <span>$i18n{NEW_FOLDER_BUTTON_LABEL}</span> </button> <select class="file-type" hidden tabindex="4"></select> <div id="filename-input-box" visibleif="saveas-file"> <cr-input id="filename-input-textbox" tabindex="5" class="entry-name" type="text" spellcheck="false" - i18n-values="placeholder:FILENAME_LABEL"></cr-input> + placeholder="$i18n{FILENAME_LABEL}"></cr-input> </div> - <div class="preparing-label" i18n-content="PREPARING_LABEL"></div> + <div class="preparing-label">$i18n{PREPARING_LABEL}</div> <div class="progress-bar"><div class="progress-track"></div></div> </div> <div class="right buttonbar"> <button id="cancel-button" class="cancel secondary" tabindex="6"> <paper-ripple fit></paper-ripple> - <span i18n-content="CANCEL_LABEL"></span> + <span>$i18n{CANCEL_LABEL}</span> </button> <button id="ok-button" class="ok primary" disabled tabindex="7"> <paper-ripple fit></paper-ripple> @@ -547,7 +546,7 @@ <div id="drag-container"></div> <files-tooltip></files-tooltip> <files-quick-view tabindex="-1" id="quick-view" - i18n-values="no-playback-text:QUICK_VIEW_NO_PLAYBACK_AVAILABLE;no-preview-text:QUICK_VIEW_NO_PREVIEW_AVAILABLE"> + no-playback-text="$i18n{QUICK_VIEW_NO_PLAYBACK_AVAILABLE}" no-preview-text="$i18n{QUICK_VIEW_NO_PREVIEW_AVAILABLE}"> </files-quick-view> <iframe id="command-dispatcher" hidden aria-hidden="true"></iframe> <div id="drop-label"></div>
diff --git a/ui/file_manager/integration_tests/file_manager/file_display.js b/ui/file_manager/integration_tests/file_manager/file_display.js index 57e41a1..d772dd1 100644 --- a/ui/file_manager/integration_tests/file_manager/file_display.js +++ b/ui/file_manager/integration_tests/file_manager/file_display.js
@@ -206,6 +206,14 @@ appId, '#directory-tree [entry-label="singleUSB"]'); chrome.test.assertEq( 'removable', singleUSB.attributes['volume-type-for-testing']); + + // Check whether the drive label is shared by the partitions. + chrome.test.assertEq( + 'PARTITION_DRIVE_LABEL', partitionOne.attributes['drive-label']); + chrome.test.assertEq( + 'PARTITION_DRIVE_LABEL', partitionTwo.attributes['drive-label']); + chrome.test.assertEq( + 'SINGLE_DRIVE_LABEL', singleUSB.attributes['drive-label']); }; /**
diff --git a/ui/gfx/animation/animation.cc b/ui/gfx/animation/animation.cc index 90342df..c651217 100644 --- a/ui/gfx/animation/animation.cc +++ b/ui/gfx/animation/animation.cc
@@ -113,6 +113,12 @@ // Defined in platform specific files for Windows and OSX. return true; } + +bool Animation::PrefersReducedMotion() { + // By default, we assume that animations are enabled, to avoid impacting the + // experience for users on systems that don't have APIs for reduced motion. + return false; +} #endif bool Animation::ShouldSendCanceledFromStop() {
diff --git a/ui/gfx/animation/animation.h b/ui/gfx/animation/animation.h index bb826e2..c2062a1 100644 --- a/ui/gfx/animation/animation.h +++ b/ui/gfx/animation/animation.h
@@ -79,6 +79,10 @@ // process. static bool ScrollAnimationsEnabledBySystem(); + // Determines whether the user desires reduced motion based on platform APIs. + // Should only be called from the browser process. + static bool PrefersReducedMotion(); + protected: // Invoked from Start to allow subclasses to prepare for the animation. virtual void AnimationStarted() {}
diff --git a/ui/gfx/animation/animation_mac.mm b/ui/gfx/animation/animation_mac.mm index 99a841c..814c406 100644 --- a/ui/gfx/animation/animation_mac.mm +++ b/ui/gfx/animation/animation_mac.mm
@@ -4,11 +4,16 @@ #include "ui/gfx/animation/animation.h" -#import <Foundation/Foundation.h> +#import <Cocoa/Cocoa.h> #include "base/mac/mac_util.h" #include "base/message_loop/message_loop.h" +// Only available since 10.12. +@interface NSWorkspace (AvailableSinceSierra) +@property(readonly) BOOL accessibilityDisplayShouldReduceMotion; +@end + namespace gfx { // static @@ -27,4 +32,22 @@ return enabled; } +// static +bool Animation::PrefersReducedMotion() { + // Because of sandboxing, OS settings should only be queried from the browser + // process. + DCHECK(base::MessageLoopCurrentForUI::IsSet() || + base::MessageLoopCurrentForIO::IsSet()); + + // We default to assuming that animations are enabled, to avoid impacting the + // experience for users on pre-10.12 systems. + bool prefers_reduced_motion = false; + SEL sel = @selector(accessibilityDisplayShouldReduceMotion); + if ([[NSWorkspace sharedWorkspace] respondsToSelector:sel]) { + prefers_reduced_motion = + [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceMotion]; + } + return prefers_reduced_motion; +} + } // namespace gfx
diff --git a/ui/gfx/animation/animation_win.cc b/ui/gfx/animation/animation_win.cc index 90b64af8..d7627ad 100644 --- a/ui/gfx/animation/animation_win.cc +++ b/ui/gfx/animation/animation_win.cc
@@ -23,4 +23,13 @@ return ShouldRenderRichAnimation(); } +// static +bool Animation::PrefersReducedMotion() { + // We default to assuming that animations are enabled, to avoid impacting the + // experience for users on systems that don't have SPI_GETCLIENTAREAANIMATION. + BOOL win_anim_enabled = true; + SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &win_anim_enabled, 0); + return !win_anim_enabled; +} + } // namespace gfx
diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc index 3711f05..59b48db8 100644 --- a/ui/gfx/canvas_skia.cc +++ b/ui/gfx/canvas_skia.cc
@@ -88,8 +88,9 @@ render_text->SetColor(color); const int font_style = font_list.GetFontStyle(); - render_text->SetStyle(ITALIC, (font_style & Font::ITALIC) != 0); - render_text->SetStyle(UNDERLINE, (font_style & Font::UNDERLINE) != 0); + render_text->SetStyle(TEXT_STYLE_ITALIC, (font_style & Font::ITALIC) != 0); + render_text->SetStyle(TEXT_STYLE_UNDERLINE, + (font_style & Font::UNDERLINE) != 0); render_text->SetWeight(font_list.GetFontWeight()); } @@ -198,7 +199,7 @@ rect.set_height(line_height - line_padding); if (range.IsValid()) - render_text->ApplyStyle(UNDERLINE, true, range); + render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, range); render_text->SetDisplayRect(rect); render_text->Draw(this); rect += Vector2d(0, line_height); @@ -229,7 +230,7 @@ UpdateRenderText(rect, adjusted_text, font_list, flags, color, render_text.get()); if (range.IsValid()) - render_text->ApplyStyle(UNDERLINE, true, range); + render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, range); render_text->Draw(this); }
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index 1b7f2cf..68b99d49 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc
@@ -292,7 +292,7 @@ range = range.Intersect(baselines_.GetRange(baseline_)); range = range.Intersect(font_size_overrides_.GetRange(font_size_override_)); range = range.Intersect(weights_.GetRange(weight_)); - for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) + for (size_t i = 0; i < TEXT_STYLE_COUNT; ++i) range = range.Intersect(styles_[i].GetRange(style_[i])); return range; } @@ -302,7 +302,7 @@ baseline_ = baselines_.GetBreak(position); font_size_override_ = font_size_overrides_.GetBreak(position); weight_ = weights_.GetBreak(position); - for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) + for (size_t i = 0; i < TEXT_STYLE_COUNT; ++i) style_[i] = styles_[i].GetBreak(position); } @@ -393,7 +393,7 @@ baselines_.SetValue(baselines_.breaks().begin()->second); font_size_overrides_.SetValue(font_size_overrides_.breaks().begin()->second); weights_.SetValue(weights_.breaks().begin()->second); - for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) + for (size_t style = 0; style < TEXT_STYLE_COUNT; ++style) styles_[style].SetValue(styles_[style].breaks().begin()->second); cached_bounds_and_offset_valid_ = false; @@ -429,9 +429,9 @@ font_list_ = font_list; const int font_style = font_list.GetFontStyle(); weights_.SetValue(font_list.GetFontWeight()); - styles_[ITALIC].SetValue((font_style & Font::ITALIC) != 0); - styles_[UNDERLINE].SetValue((font_style & Font::UNDERLINE) != 0); - styles_[HEAVY_UNDERLINE].SetValue(false); + styles_[TEXT_STYLE_ITALIC].SetValue((font_style & Font::ITALIC) != 0); + styles_[TEXT_STYLE_UNDERLINE].SetValue((font_style & Font::UNDERLINE) != 0); + styles_[TEXT_STYLE_HEAVY_UNDERLINE].SetValue(false); baseline_ = kInvalidBaseline; cached_bounds_and_offset_valid_ = false; OnLayoutTextAttributeChanged(false); @@ -751,7 +751,7 @@ bool RenderText::GetStyle(TextStyle style) const { return (styles_[style].breaks().size() == 1) && - styles_[style].breaks().front().second; + styles_[style].breaks().front().second; } void RenderText::SetDirectionalityMode(DirectionalityMode mode) { @@ -1043,7 +1043,7 @@ baselines_(NORMAL_BASELINE), font_size_overrides_(0), weights_(Font::Weight::NORMAL), - styles_(NUM_TEXT_STYLES), + styles_(TEXT_STYLE_COUNT), composition_and_selection_styles_applied_(false), obscured_(false), obscured_reveal_index_(-1), @@ -1066,7 +1066,7 @@ font_size_overrides().breaks().size() > 1 || weights().breaks().size() > 1) return false; - for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) { + for (size_t style = 0; style < TEXT_STYLE_COUNT; ++style) { if (styles()[style].breaks().size() > 1) return false; } @@ -1205,11 +1205,11 @@ // Save the underline and color breaks to undo the temporary styles later. DCHECK(!composition_and_selection_styles_applied_); saved_colors_ = colors_; - saved_underlines_ = styles_[HEAVY_UNDERLINE]; + saved_underlines_ = styles_[TEXT_STYLE_HEAVY_UNDERLINE]; // Apply an underline to the composition range in |underlines|. if (composition_range_.IsValid() && !composition_range_.is_empty()) - styles_[HEAVY_UNDERLINE].ApplyValue(true, composition_range_); + styles_[TEXT_STYLE_HEAVY_UNDERLINE].ApplyValue(true, composition_range_); // Apply the selected text color to the [un-reversed] selection range. if (!selection().is_empty() && focused()) { @@ -1223,7 +1223,7 @@ // Restore the underline and color breaks to undo the temporary styles. DCHECK(composition_and_selection_styles_applied_); colors_ = saved_colors_; - styles_[HEAVY_UNDERLINE] = saved_underlines_; + styles_[TEXT_STYLE_HEAVY_UNDERLINE] = saved_underlines_; composition_and_selection_styles_applied_ = false; } @@ -1387,7 +1387,7 @@ baselines_.SetMax(text_length); font_size_overrides_.SetMax(text_length); weights_.SetMax(text_length); - for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) + for (size_t style = 0; style < TEXT_STYLE_COUNT; ++style) styles_[style].SetMax(text_length); } @@ -1605,7 +1605,7 @@ // Restore styles and baselines without breaking multi-character graphemes. render_text->styles_ = styles_; - for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) + for (size_t style = 0; style < TEXT_STYLE_COUNT; ++style) RestoreBreakList(render_text.get(), &render_text->styles_[style]); RestoreBreakList(render_text.get(), &render_text->baselines_); RestoreBreakList(render_text.get(), &render_text->font_size_overrides_);
diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h index 18e57f9..94db79c 100644 --- a/ui/gfx/render_text.h +++ b/ui/gfx/render_text.h
@@ -100,7 +100,7 @@ SkColor color() const { return color_->second; } BaselineStyle baseline() const { return baseline_->second; } int font_size_override() const { return font_size_override_->second; } - bool style(TextStyle s) const { return style_[s]->second; } + bool style(TextStyle s) const { return style_[static_cast<int>(s)]->second; } Font::Weight weight() const { return weight_->second; } // Get the intersecting range of the current iterator set.
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc index 927b1ddf..b25844a4 100644 --- a/ui/gfx/render_text_harfbuzz.cc +++ b/ui/gfx/render_text_harfbuzz.cc
@@ -1736,12 +1736,12 @@ Range run_range; internal::TextRunHarfBuzz::FontParams font_params(primary_font); run_range.set_start(run_break); - font_params.italic = style.style(ITALIC); + font_params.italic = style.style(TEXT_STYLE_ITALIC); font_params.baseline_type = style.baseline(); font_params.font_size = style.font_size_override(); - font_params.strike = style.style(STRIKE); - font_params.underline = style.style(UNDERLINE); - font_params.heavy_underline = style.style(HEAVY_UNDERLINE); + font_params.strike = style.style(TEXT_STYLE_STRIKE); + font_params.underline = style.style(TEXT_STYLE_UNDERLINE); + font_params.heavy_underline = style.style(TEXT_STYLE_HEAVY_UNDERLINE); font_params.weight = style.weight(); int32_t script_item_break = 0; bidi_iterator.GetLogicalRun(run_break, &script_item_break,
diff --git a/ui/gfx/render_text_mac.mm b/ui/gfx/render_text_mac.mm index 5d804727..bdfb609a 100644 --- a/ui/gfx/render_text_mac.mm +++ b/ui/gfx/render_text_mac.mm
@@ -362,8 +362,9 @@ kCTForegroundColorAttributeName, foreground); CFArrayAppendValue(attributes, foreground); - if (style.style(UNDERLINE) || style.style(HEAVY_UNDERLINE)) { - CTUnderlineStyle value = style.style(HEAVY_UNDERLINE) + if (style.style(TEXT_STYLE_UNDERLINE) || + style.style(TEXT_STYLE_HEAVY_UNDERLINE)) { + CTUnderlineStyle value = style.style(TEXT_STYLE_HEAVY_UNDERLINE) ? kCTUnderlineStyleThick : kCTUnderlineStyleSingle; base::ScopedCFTypeRef<CFNumberRef> underline_value( @@ -375,7 +376,7 @@ // TODO(mboc): Apply font weights other than bold below. const int traits = - (style.style(ITALIC) ? kCTFontItalicTrait : 0) | + (style.style(TEXT_STYLE_ITALIC) ? kCTFontItalicTrait : 0) | (style.weight() >= Font::Weight::BOLD ? kCTFontBoldTrait : 0); if (traits != 0) { base::ScopedCFTypeRef<CTFontRef> styled_font =
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc index b01ff5f..c8957cf 100644 --- a/ui/gfx/render_text_unittest.cc +++ b/ui/gfx/render_text_unittest.cc
@@ -69,9 +69,9 @@ // Bitmasks based on gfx::TextStyle. enum { - ITALIC_MASK = 1 << ITALIC, - STRIKE_MASK = 1 << STRIKE, - UNDERLINE_MASK = 1 << UNDERLINE, + ITALIC_MASK = 1 << TEXT_STYLE_ITALIC, + STRIKE_MASK = 1 << TEXT_STYLE_STRIKE, + UNDERLINE_MASK = 1 << TEXT_STYLE_UNDERLINE, }; // Checks whether |range| contains |index|. This is not the same as calling @@ -508,7 +508,7 @@ EXPECT_TRUE(test_api()->colors().EqualsValueForTesting(SK_ColorBLACK)); EXPECT_TRUE(test_api()->baselines().EqualsValueForTesting(NORMAL_BASELINE)); EXPECT_TRUE(test_api()->font_size_overrides().EqualsValueForTesting(0)); - for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) + for (size_t style = 0; style < static_cast<int>(TEXT_STYLE_COUNT); ++style) EXPECT_TRUE(test_api()->styles()[style].EqualsValueForTesting(false)); render_text->SetText(UTF8ToUTF16(cases[i])); } @@ -521,21 +521,24 @@ render_text->SetColor(color); render_text->SetBaselineStyle(SUPERSCRIPT); render_text->SetWeight(Font::Weight::BOLD); - render_text->SetStyle(UNDERLINE, false); + render_text->SetStyle(TEXT_STYLE_UNDERLINE, false); const char* const cases[] = {kWeak, kLtr, "Hello", kRtl, "", ""}; for (size_t i = 0; i < base::size(cases); ++i) { EXPECT_TRUE(test_api()->colors().EqualsValueForTesting(color)); EXPECT_TRUE(test_api()->baselines().EqualsValueForTesting(SUPERSCRIPT)); EXPECT_TRUE( test_api()->weights().EqualsValueForTesting(Font::Weight::BOLD)); - EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsValueForTesting(false)); + EXPECT_TRUE( + test_api()->styles()[TEXT_STYLE_UNDERLINE].EqualsValueForTesting( + false)); render_text->SetText(UTF8ToUTF16(cases[i])); // Ensure custom default styles can be applied after text has been set. if (i == 1) - render_text->SetStyle(STRIKE, true); + render_text->SetStyle(TEXT_STYLE_STRIKE, true); if (i >= 1) - EXPECT_TRUE(test_api()->styles()[STRIKE].EqualsValueForTesting(true)); + EXPECT_TRUE( + test_api()->styles()[TEXT_STYLE_STRIKE].EqualsValueForTesting(true)); } } @@ -587,32 +590,37 @@ {{0, Font::Weight::NORMAL}, {2, Font::Weight::BOLD}})); // Ensure ranged values adjust to accommodate text length changes. - render_text->ApplyStyle(ITALIC, true, Range(0, 2)); - render_text->ApplyStyle(ITALIC, true, Range(3, 6)); - render_text->ApplyStyle(ITALIC, true, Range(7, text_length)); + render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(0, 2)); + render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(3, 6)); + render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(7, text_length)); std::vector<std::pair<size_t, bool>> expected_italic = { {0, true}, {2, false}, {3, true}, {6, false}, {7, true}}; - EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic)); + EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_ITALIC].EqualsForTesting( + expected_italic)); // Changing the text should clear any breaks except for the first one. render_text->SetText(UTF8ToUTF16("0123456")); expected_italic.resize(1); - EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic)); - render_text->ApplyStyle(ITALIC, false, Range(2, 4)); + EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_ITALIC].EqualsForTesting( + expected_italic)); + render_text->ApplyStyle(TEXT_STYLE_ITALIC, false, Range(2, 4)); render_text->SetText(UTF8ToUTF16("012345678")); - EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic)); - render_text->ApplyStyle(ITALIC, false, Range(0, 1)); + EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_ITALIC].EqualsForTesting( + expected_italic)); + render_text->ApplyStyle(TEXT_STYLE_ITALIC, false, Range(0, 1)); render_text->SetText(UTF8ToUTF16("0123456")); expected_italic.begin()->second = false; - EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic)); - render_text->ApplyStyle(ITALIC, true, Range(2, 4)); + EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_ITALIC].EqualsForTesting( + expected_italic)); + render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(2, 4)); render_text->SetText(UTF8ToUTF16("012345678")); - EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic)); + EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_ITALIC].EqualsForTesting( + expected_italic)); // Styles shouldn't be changed mid-grapheme. render_text->SetText(UTF8ToUTF16("0\u0915\u093f1\u0915\u093f2")); - render_text->ApplyStyle(UNDERLINE, true, Range(2, 5)); - EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting( + render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, Range(2, 5)); + EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_UNDERLINE].EqualsForTesting( {{0, false}, {1, true}, {6, false}})); } @@ -622,7 +630,7 @@ render_text->SetText(UTF8ToUTF16("abcd")); render_text->ApplyColor(SK_ColorRED, Range(0, 1)); render_text->ApplyBaselineStyle(SUPERSCRIPT, Range(1, 2)); - render_text->ApplyStyle(UNDERLINE, true, Range(2, 3)); + render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, Range(2, 3)); render_text->ApplyFontSizeOverride(20, Range(3, 4)); // Verify basic functionality. const std::vector<std::pair<size_t, SkColor>> expected_color = { @@ -633,7 +641,8 @@ EXPECT_TRUE(test_api()->baselines().EqualsForTesting(expected_baseline)); const std::vector<std::pair<size_t, bool>> expected_style = { {0, false}, {2, true}, {3, false}}; - EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting(expected_style)); + EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_UNDERLINE].EqualsForTesting( + expected_style)); const std::vector<std::pair<size_t, int>> expected_font_size = {{0, 0}, {3, 20}}; EXPECT_TRUE( @@ -644,7 +653,8 @@ EXPECT_EQ(render_text->GetDisplayText(), UTF8ToUTF16("abcdefg")); EXPECT_TRUE(test_api()->colors().EqualsForTesting(expected_color)); EXPECT_TRUE(test_api()->baselines().EqualsForTesting(expected_baseline)); - EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting(expected_style)); + EXPECT_TRUE(test_api()->styles()[TEXT_STYLE_UNDERLINE].EqualsForTesting( + expected_style)); EXPECT_TRUE( test_api()->font_size_overrides().EqualsForTesting(expected_font_size)); } @@ -961,7 +971,7 @@ // with these styles. This can expose a behavior in layout where text is // slightly different width. This must be done after |SetText()|. render_text->ApplyWeight(Font::Weight::BOLD, Range(1, 20)); - render_text->ApplyStyle(ITALIC, true, Range(1, 20)); + render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(1, 20)); render_text->SetMultiline(true); render_text->SetElideBehavior(ELIDE_TAIL); render_text->SetMaxLines(3); @@ -1010,7 +1020,7 @@ render_text->SetText(input_text); render_text->ApplyWeight(Font::Weight::BOLD, Range(1, 20)); - render_text->ApplyStyle(ITALIC, true, Range(1, 20)); + render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(1, 20)); render_text->SetMultiline(true); render_text->SetMaxLines(3); render_text->SetElideBehavior(ELIDE_TAIL); @@ -4470,7 +4480,7 @@ DrawVisualText(); EXPECT_EQ(SkFontStyle::Bold(), GetRendererFont().getTypeface()->fontStyle()); - render_text->SetStyle(TextStyle::ITALIC, true); + render_text->SetStyle(TEXT_STYLE_ITALIC, true); DrawVisualText(); EXPECT_EQ(SkFontStyle::BoldItalic(), GetRendererFont().getTypeface()->fontStyle()); @@ -4565,9 +4575,9 @@ render_text->SetDisplayRect(Rect(100, 30)); render_text->SetText(ltr); render_text->ApplyWeight(Font::Weight::SEMIBOLD, Range(0, 3)); - render_text->ApplyStyle(UNDERLINE, true, Range(1, 5)); - render_text->ApplyStyle(ITALIC, true, Range(3, 8)); - render_text->ApplyStyle(STRIKE, true, Range(1, 7)); + render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, Range(1, 5)); + render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(3, 8)); + render_text->ApplyStyle(TEXT_STYLE_STRIKE, true, Range(1, 7)); const int cursor_y = GetCursorYForTesting(); const std::vector<RenderText::FontSpan> font_spans = @@ -4645,9 +4655,9 @@ render_text->SetDisplayRect(Rect(100, 30)); render_text->SetText(rtl); render_text->ApplyWeight(Font::Weight::SEMIBOLD, Range(2, 3)); - render_text->ApplyStyle(UNDERLINE, true, Range(3, 6)); - render_text->ApplyStyle(ITALIC, true, Range(0, 3)); - render_text->ApplyStyle(STRIKE, true, Range(2, 5)); + render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, Range(3, 6)); + render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(0, 3)); + render_text->ApplyStyle(TEXT_STYLE_STRIKE, true, Range(2, 5)); const int cursor_y = GetCursorYForTesting(); const std::vector<RenderText::FontSpan> font_spans = @@ -4726,9 +4736,9 @@ render_text->SetDisplayRect(Rect(500, 500)); render_text->SetText(text); render_text->ApplyWeight(Font::Weight::SEMIBOLD, Range(0, 3)); - render_text->ApplyStyle(UNDERLINE, true, Range(1, 7)); - render_text->ApplyStyle(STRIKE, true, Range(1, 8)); - render_text->ApplyStyle(ITALIC, true, Range(5, 9)); + render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, Range(1, 7)); + render_text->ApplyStyle(TEXT_STYLE_STRIKE, true, Range(1, 8)); + render_text->ApplyStyle(TEXT_STYLE_ITALIC, true, Range(5, 9)); // Set up test expectations. const std::vector<RenderText::FontSpan> font_spans = @@ -4835,7 +4845,7 @@ render_text->SetDisplayRect(Rect(500, 500)); render_text->SetText(text); render_text->ApplyWeight(Font::Weight::SEMIBOLD, kWordOneRange); - render_text->ApplyStyle(UNDERLINE, true, kWordTwoRange); + render_text->ApplyStyle(TEXT_STYLE_UNDERLINE, true, kWordTwoRange); // Set up test expectations. const std::vector<RenderText::FontSpan> font_spans =
diff --git a/ui/gfx/text_constants.h b/ui/gfx/text_constants.h index 0ca89b1..fb1bab1 100644 --- a/ui/gfx/text_constants.h +++ b/ui/gfx/text_constants.h
@@ -78,11 +78,12 @@ // Text styles and adornments. // TODO(msw): Merge with gfx::Font::FontStyle. enum TextStyle { - ITALIC = 0, - STRIKE, - UNDERLINE, - HEAVY_UNDERLINE, - NUM_TEXT_STYLES, + TEXT_STYLE_ITALIC = 0, + TEXT_STYLE_STRIKE, + TEXT_STYLE_UNDERLINE, + TEXT_STYLE_HEAVY_UNDERLINE, + + TEXT_STYLE_COUNT, }; // Text baseline offset types.
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc index b3cfc934..87bca7b 100644 --- a/ui/keyboard/keyboard_controller.cc +++ b/ui/keyboard/keyboard_controller.cc
@@ -54,18 +54,22 @@ // Owned by ash::Shell. KeyboardController* g_keyboard_controller = nullptr; -constexpr int kHideKeyboardDelayMs = 100; +// How long the keyboard stays in WILL_HIDE state before moving to HIDDEN. +constexpr base::TimeDelta kHideKeyboardDelay = + base::TimeDelta::FromMilliseconds(100); // Reports an error histogram if the keyboard state is lingering in an // intermediate state for more than 5 seconds. -constexpr int kReportLingeringStateDelayMs = 5000; +constexpr base::TimeDelta kReportLingeringStateDelay = + base::TimeDelta::FromMilliseconds(5000); // Delay threshold after the keyboard enters the WILL_HIDE state. If text focus // is regained during this threshold, the keyboard will show again, even if it // is an asynchronous event. This is for the benefit of things like login flow // where the password field may get text focus after an animation that plays // after the user enters their username. -constexpr int kTransientBlurThresholdMs = 3500; +constexpr base::TimeDelta kTransientBlurThreshold = + base::TimeDelta::FromMilliseconds(3500); // State transition diagram (document linked from crbug.com/719905) bool IsAllowedStateTransition(KeyboardControllerState from, @@ -630,7 +634,7 @@ base::BindOnce(&KeyboardController::HideKeyboard, weak_factory_will_hide_.GetWeakPtr(), HIDE_REASON_SYSTEM_IMPLICIT), - base::TimeDelta::FromMilliseconds(kHideKeyboardDelayMs)); + kHideKeyboardDelay); } // private @@ -818,12 +822,7 @@ } void KeyboardController::ShowKeyboardIfWithinTransientBlurThreshold() { - static const base::TimeDelta kTransientBlurThreshold = - base::TimeDelta::FromMilliseconds(kTransientBlurThresholdMs); - - const base::Time now = base::Time::Now(); - const base::TimeDelta time_since_last_blur = now - time_of_last_blur_; - if (time_since_last_blur < kTransientBlurThreshold) + if (base::Time::Now() - time_of_last_blur_ < kTransientBlurThreshold) ShowKeyboard(false); } @@ -982,7 +981,7 @@ FROM_HERE, base::BindOnce(&KeyboardController::ReportLingeringState, weak_factory_report_lingering_state_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(kReportLingeringStateDelayMs)); + kReportLingeringStateDelay); break; default: // Do nothing
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc index aceb7232..bc7b496 100644 --- a/ui/native_theme/native_theme_win.cc +++ b/ui/native_theme/native_theme_win.cc
@@ -10,7 +10,9 @@ #include <vsstyle.h> #include <vssym32.h> +#include "base/bind.h" #include "base/command_line.h" +#include "base/feature_list.h" #include "base/logging.h" #include "base/stl_util.h" #include "base/win/scoped_gdi_object.h" @@ -28,6 +30,7 @@ #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkSurface.h" +#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_switches.h" #include "ui/display/win/screen_win.h" #include "ui/gfx/color_palette.h" @@ -253,6 +256,19 @@ close_theme_ = reinterpret_cast<CloseThemeDataPtr>( GetProcAddress(theme_dll_, "CloseThemeData")); } + if (base::FeatureList::IsEnabled(features::kDarkMode)) { + // Dark Mode currently targets UWP apps, which means Win32 apps need to use + // alternate, less reliable means of detecting the state. The following + // can break in future Windows versions. + bool key_open_succeeded = + hkcu_themes_regkey_.Open( + HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\CurrentVersion\\" + L"Themes\\Personalize", + KEY_READ | KEY_NOTIFY) == ERROR_SUCCESS; + if (key_open_succeeded) + RegisterThemeRegkeyObserver(); + } memset(theme_handles_, 0, sizeof(theme_handles_)); // Initialize the cached system colors. @@ -562,6 +578,17 @@ return force_enabled || IsUsingHighContrastThemeInternal(); } +bool NativeThemeWin::SystemDarkModeEnabled() const { + bool fDarkModeEnabled = false; + if (hkcu_themes_regkey_.Valid()) { + DWORD apps_use_light_theme = 1; + hkcu_themes_regkey_.ReadValueDW(L"AppsUseLightTheme", + &apps_use_light_theme); + fDarkModeEnabled = (apps_use_light_theme == 0); + } + return fDarkModeEnabled || NativeTheme::SystemDarkModeEnabled(); +} + void NativeThemeWin::PaintIndirect(cc::PaintCanvas* destination_canvas, Part part, State state, @@ -1890,4 +1917,16 @@ return handle; } +void NativeThemeWin::RegisterThemeRegkeyObserver() { + DCHECK(hkcu_themes_regkey_.Valid()); + hkcu_themes_regkey_.StartWatching(base::BindRepeating( + [](NativeThemeWin* native_theme) { + native_theme->NotifyObservers(); + // RegKey::StartWatching only provides one notification. Reregistration + // is required to get future notifications. + native_theme->RegisterThemeRegkeyObserver(); + }, + base::Unretained(this))); +} + } // namespace ui
diff --git a/ui/native_theme/native_theme_win.h b/ui/native_theme/native_theme_win.h index 9ee7350..cdc2157 100644 --- a/ui/native_theme/native_theme_win.h +++ b/ui/native_theme/native_theme_win.h
@@ -19,6 +19,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/no_destructor.h" +#include "base/win/registry.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/sys_color_change_listener.h" @@ -80,6 +81,7 @@ gfx::Size GetNinePatchCanvasSize(Part part) const override; gfx::Rect GetNinePatchAperture(Part part) const override; bool UsesHighContrastColors() const override; + bool SystemDarkModeEnabled() const override; protected: friend class NativeTheme; @@ -260,6 +262,8 @@ // Returns a handle to the theme data. HANDLE GetThemeHandle(ThemeName theme_name) const; + void RegisterThemeRegkeyObserver(); + typedef HRESULT (WINAPI* DrawThemeBackgroundPtr)(HANDLE theme, HDC hdc, int part_id, @@ -314,6 +318,9 @@ // Handle to uxtheme.dll. HMODULE theme_dll_; + // Dark Mode registry key. + base::win::RegKey hkcu_themes_regkey_; + // A cache of open theme handles. mutable HANDLE theme_handles_[LAST];
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.cc b/ui/views/accessibility/view_ax_platform_node_delegate.cc index e062960..19527726 100644 --- a/ui/views/accessibility/view_ax_platform_node_delegate.cc +++ b/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -13,6 +13,7 @@ #include "ui/accessibility/ax_role_properties.h" #include "ui/accessibility/ax_tree_data.h" #include "ui/accessibility/platform/ax_platform_node.h" +#include "ui/accessibility/platform/ax_platform_node_base.h" #include "ui/accessibility/platform/ax_unique_id.h" #include "ui/events/event_utils.h" #include "ui/views/accessibility/view_accessibility_utils.h" @@ -25,9 +26,6 @@ namespace { -base::LazyInstance<std::map<int32_t, ui::AXPlatformNode*>>::Leaky - g_unique_id_to_ax_platform_node = LAZY_INSTANCE_INITIALIZER; - // Information required to fire a delayed accessibility event. struct QueuedEvent { QueuedEvent(ax::mojom::Event type, int32_t node_id) @@ -82,12 +80,7 @@ ui::AXPlatformNode* PlatformNodeFromNodeID(int32_t id) { // Note: For Views, node IDs and unique IDs are the same - but that isn't // necessarily true for all AXPlatformNodes. - auto it = g_unique_id_to_ax_platform_node.Get().find(id); - - if (it == g_unique_id_to_ax_platform_node.Get().end()) - return nullptr; - - return it->second; + return ui::AXPlatformNodeBase::GetFromUniqueId(id); } void FireEvent(QueuedEvent event) { @@ -120,16 +113,11 @@ base::BindRepeating(&FromNativeWindow)); first_time = false; } - - g_unique_id_to_ax_platform_node.Get()[GetUniqueId().Get()] = - ax_platform_node_; } ViewAXPlatformNodeDelegate::~ViewAXPlatformNodeDelegate() { if (ui::AXPlatformNode::GetPopupFocusOverride() == GetNativeObject()) ui::AXPlatformNode::SetPopupFocusOverride(nullptr); - - g_unique_id_to_ax_platform_node.Get().erase(GetUniqueId().Get()); ax_platform_node_->Destroy(); }
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.h b/ui/views/cocoa/bridged_native_widget_host_impl.h index 383e924..2f82d8e9 100644 --- a/ui/views/cocoa/bridged_native_widget_host_impl.h +++ b/ui/views/cocoa/bridged_native_widget_host_impl.h
@@ -14,6 +14,7 @@ #include "ui/accelerated_widget_mac/accelerated_widget_mac.h" #include "ui/accelerated_widget_mac/display_link_mac.h" #include "ui/base/cocoa/accessibility_focus_overrider.h" +#include "ui/base/cocoa/ns_view_ids.h" #include "ui/base/ime/input_method_delegate.h" #include "ui/compositor/layer_owner.h" #include "ui/views/cocoa/bridge_factory_host.h" @@ -409,6 +410,9 @@ // Window that is guaranteed to exist in this process (see GetLocalNSWindow). base::scoped_nsobject<NativeWidgetMacNSWindow> local_window_; + // Id mapping for |local_window_|'s content NSView. + std::unique_ptr<ui::ScopedNSViewIdMapping> local_view_id_mapping_; + std::unique_ptr<TooltipManager> tooltip_manager_; std::unique_ptr<ui::InputMethod> input_method_; std::unique_ptr<TextInputHost> text_input_host_;
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.mm b/ui/views/cocoa/bridged_native_widget_host_impl.mm index dab14f6..a156f05d 100644 --- a/ui/views/cocoa/bridged_native_widget_host_impl.mm +++ b/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -328,6 +328,8 @@ local_window_create_params.get()); [local_window_ setBridgedNativeWidgetId:widget_id_]; [local_window_ setAlphaValue:0.0]; + local_view_id_mapping_ = std::make_unique<ui::ScopedNSViewIdMapping>( + root_view_id_, [local_window_ contentView]); } // Initialize |bridge_ptr_| to point to a bridge created by |factory|.
diff --git a/ui/views/controls/native/native_view_host_mac.mm b/ui/views/controls/native/native_view_host_mac.mm index 0ef6700..efd578d 100644 --- a/ui/views/controls/native/native_view_host_mac.mm +++ b/ui/views/controls/native/native_view_host_mac.mm
@@ -115,21 +115,23 @@ DCHECK(host_->native_view()); DCHECK(!native_view_); native_view_.reset([host_->native_view().GetNativeNSView() retain]); + if ([native_view_ conformsToProtocol:@protocol(ViewsHostable)]) { + id hostable = native_view_; + native_view_hostable_ = [hostable viewsHostableView]; + } EnsureNativeViewHasNoChildWidgets(native_view_); auto* bridge_host = GetBridgedNativeWidgetHost(); DCHECK(bridge_host); - NSView* superview = - bridge_host->native_widget_mac()->GetNativeView().GetNativeNSView(); - [superview addSubview:native_view_]; - bridge_host->SetAssociationForView(host_, native_view_); - if ([native_view_ conformsToProtocol:@protocol(ViewsHostable)]) { - id hostable = native_view_; - native_view_hostable_ = [hostable viewsHostableView]; - if (native_view_hostable_) - native_view_hostable_->OnViewsHostableAttached(this); + if (native_view_hostable_) { + native_view_hostable_->ViewsHostableAttach(this); + } else { + NSView* superview = + bridge_host->native_widget_mac()->GetNativeView().GetNativeNSView(); + [superview addSubview:native_view_]; } + bridge_host->SetAssociationForView(host_, native_view_); } void NativeViewHostMac::NativeViewDetaching(bool destroyed) { @@ -146,12 +148,12 @@ } DCHECK(native_view_ == host_native_view); - [native_view_ setHidden:YES]; - [native_view_ removeFromSuperview]; - if (native_view_hostable_) { - native_view_hostable_->OnViewsHostableDetached(); + native_view_hostable_->ViewsHostableDetach(); native_view_hostable_ = nullptr; + } else { + [native_view_ setHidden:YES]; + [native_view_ removeFromSuperview]; } EnsureNativeViewHasNoChildWidgets(native_view_); @@ -207,39 +209,40 @@ int native_h) { // TODO(https://crbug.com/415024): Implement host_->fast_resize(). - // Coordinates will be from the top left of the parent Widget. The NativeView - // is already in the same NSWindow, so just flip to get Cooca coordinates and - // then convert to the containing view. - NSRect window_rect = NSMakeRect( - x, - host_->GetWidget()->GetClientAreaBoundsInScreen().height() - y - h, - w, - h); + if (native_view_hostable_) { + native_view_hostable_->ViewsHostableSetBounds(gfx::Rect(x, y, w, h)); + native_view_hostable_->ViewsHostableSetVisible(true); + } else { + // Coordinates will be from the top left of the parent Widget. The + // NativeView is already in the same NSWindow, so just flip to get Cooca + // coordinates and then convert to the containing view. + NSRect window_rect = NSMakeRect( + x, host_->GetWidget()->GetClientAreaBoundsInScreen().height() - y - h, + w, h); - // Convert window coordinates to the hosted view's superview, since that's how - // coordinates of the hosted view's frame is based. - NSRect container_rect = - [[native_view_ superview] convertRect:window_rect fromView:nil]; - [native_view_ setFrame:container_rect]; - [native_view_ setHidden:NO]; - - if (native_view_hostable_) - native_view_hostable_->OnViewsHostableShow(gfx::Rect(x, y, w, h)); + // Convert window coordinates to the hosted view's superview, since that's + // how coordinates of the hosted view's frame is based. + NSRect container_rect = [[native_view_ superview] convertRect:window_rect + fromView:nil]; + [native_view_ setFrame:container_rect]; + [native_view_ setHidden:NO]; + } } void NativeViewHostMac::HideWidget() { - [native_view_ setHidden:YES]; - if (native_view_hostable_) - native_view_hostable_->OnViewsHostableHide(); + native_view_hostable_->ViewsHostableSetVisible(false); + else + [native_view_ setHidden:YES]; } void NativeViewHostMac::SetFocus() { - if ([native_view_ acceptsFirstResponder]) - [[native_view_ window] makeFirstResponder:native_view_]; - - if (native_view_hostable_) - native_view_hostable_->OnViewsHostableMakeFirstResponder(); + if (native_view_hostable_) { + native_view_hostable_->ViewsHostableMakeFirstResponder(); + } else { + if ([native_view_ acceptsFirstResponder]) + [[native_view_ window] makeFirstResponder:native_view_]; + } } gfx::NativeView NativeViewHostMac::GetNativeViewContainer() const { @@ -266,7 +269,10 @@ } void NativeViewHostMac::SetVisible(bool visible) { - [native_view_ setHidden:!visible]; + if (native_view_hostable_) + native_view_hostable_->ViewsHostableSetVisible(visible); + else + [native_view_ setHidden:!visible]; } void NativeViewHostMac::SetParentAccessible(gfx::NativeViewAccessible) {}
diff --git a/ui/views/controls/native/native_view_host_mac_unittest.mm b/ui/views/controls/native/native_view_host_mac_unittest.mm index 3de36c65..8ca1ec0 100644 --- a/ui/views/controls/native/native_view_host_mac_unittest.mm +++ b/ui/views/controls/native/native_view_host_mac_unittest.mm
@@ -26,15 +26,13 @@ private: // ui::ViewsHostableView: - void OnViewsHostableAttached(ui::ViewsHostableView::Host* host) override { + void ViewsHostableAttach(ui::ViewsHostableView::Host* host) override { parent_accessibility_element_ = host->GetAccessibilityElement(); } - void OnViewsHostableDetached() override { - parent_accessibility_element_ = nil; - } - void OnViewsHostableShow(const gfx::Rect& bounds_in_window) override {} - void OnViewsHostableHide() override {} - void OnViewsHostableMakeFirstResponder() override {} + void ViewsHostableDetach() override { parent_accessibility_element_ = nil; } + void ViewsHostableSetBounds(const gfx::Rect& bounds_in_window) override {} + void ViewsHostableSetVisible(bool visible) override {} + void ViewsHostableMakeFirstResponder() override {} id parent_accessibility_element_ = nil; };
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc index cb3a4c9..439d674 100644 --- a/ui/views/controls/scroll_view_unittest.cc +++ b/ui/views/controls/scroll_view_unittest.cc
@@ -318,11 +318,6 @@ quit_closure_.Run(); quit_closure_.Reset(); } - void OnCompositingStarted(ui::Compositor* compositor, - base::TimeTicks start_time) override {} - void OnCompositingEnded(ui::Compositor* compositor) override {} - void OnCompositingChildResizing(ui::Compositor* compositor) override {} - void OnCompositingShuttingDown(ui::Compositor* compositor) override {} Widget* widget_ = nullptr;
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm b/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm index 8f08e724..f2c79ed 100644 --- a/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm +++ b/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm
@@ -13,6 +13,11 @@ #include "ui/views/widget/widget.h" #import "testing/gtest_mac.h" +// This file uses the deprecated NSObject accessibility API - see +// https://crbug.com/921109. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + namespace views { namespace test { @@ -163,3 +168,5 @@ } // namespace test } // namespace views + +#pragma clang diagnostic pop
diff --git a/ui/views/examples/multiline_example.cc b/ui/views/examples/multiline_example.cc index 7ecd683..02995b8 100644 --- a/ui/views/examples/multiline_example.cc +++ b/ui/views/examples/multiline_example.cc
@@ -97,9 +97,9 @@ render_text_->SetText(new_contents); render_text_->SetColor(SK_ColorBLACK); render_text_->ApplyColor(0xFFFF0000, color_range); - render_text_->SetStyle(gfx::UNDERLINE, false); - render_text_->ApplyStyle(gfx::UNDERLINE, true, color_range); - render_text_->ApplyStyle(gfx::ITALIC, true, italic_range); + render_text_->SetStyle(gfx::TEXT_STYLE_UNDERLINE, false); + render_text_->ApplyStyle(gfx::TEXT_STYLE_UNDERLINE, true, color_range); + render_text_->ApplyStyle(gfx::TEXT_STYLE_ITALIC, true, italic_range); render_text_->ApplyWeight(gfx::Font::Weight::BOLD, bold_range); InvalidateLayout(); }
diff --git a/ui/views/examples/textfield_example.cc b/ui/views/examples/textfield_example.cc index 8217a52..73cde0b 100644 --- a/ui/views/examples/textfield_example.cc +++ b/ui/views/examples/textfield_example.cc
@@ -150,12 +150,12 @@ if (name_->text().length() >= 5) { size_t fifth = name_->text().length() / 5; const gfx::Range big_range(1 * fifth, 4 * fifth); - name_->ApplyStyle(gfx::UNDERLINE, true, big_range); + name_->ApplyStyle(gfx::TEXT_STYLE_UNDERLINE, true, big_range); name_->ApplyColor(SK_ColorBLUE, big_range); const gfx::Range small_range(2 * fifth, 3 * fifth); - name_->ApplyStyle(gfx::ITALIC, true, small_range); - name_->ApplyStyle(gfx::UNDERLINE, false, small_range); + name_->ApplyStyle(gfx::TEXT_STYLE_ITALIC, true, small_range); + name_->ApplyStyle(gfx::TEXT_STYLE_UNDERLINE, false, small_range); name_->ApplyColor(SK_ColorRED, small_range); } }
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc index 8637b9a7..a2126cd 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.cc +++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -219,54 +219,6 @@ quit_closure.Run(); } -// ScopedTouchTransferController controls the transfer of touch events for -// window move loop. It transfers touches before the window move starts, and -// then transfers them back to the original window when the window move ends. -// However this transferring back to the original shouldn't happen if the client -// wants to continue the dragging on another window (like attaching the dragged -// tab to another window). -class ScopedTouchTransferController : public ui::GestureRecognizerObserver { - public: - ScopedTouchTransferController(aura::Window* source, aura::Window* dest) - : tracker_({source, dest}), - gesture_recognizer_(source->env()->gesture_recognizer()) { - gesture_recognizer_->TransferEventsTo( - source, dest, ui::TransferTouchesBehavior::kDontCancel); - gesture_recognizer_->AddObserver(this); - } - ~ScopedTouchTransferController() override { - gesture_recognizer_->RemoveObserver(this); - if (tracker_.windows().size() == 2) { - aura::Window* source = tracker_.Pop(); - aura::Window* dest = tracker_.Pop(); - gesture_recognizer_->TransferEventsTo( - dest, source, ui::TransferTouchesBehavior::kDontCancel); - } - } - - private: - // ui::GestureRecognizerObserver: - void OnActiveTouchesCanceledExcept( - ui::GestureConsumer* not_cancelled) override {} - void OnEventsTransferred( - ui::GestureConsumer* current_consumer, - ui::GestureConsumer* new_consumer, - ui::TransferTouchesBehavior transfer_touches_behavior) override { - if (tracker_.windows().size() <= 1) - return; - aura::Window* dest = tracker_.windows()[1]; - if (current_consumer == dest) - tracker_.Remove(dest); - } - void OnActiveTouchesCanceled(ui::GestureConsumer* consumer) override {} - - aura::WindowTracker tracker_; - - ui::GestureRecognizer* gesture_recognizer_; - - DISALLOW_COPY_AND_ASSIGN(ScopedTouchTransferController); -}; - } // namespace // WindowObserver installed on DesktopWindowTreeHostMus::window(). Mostly @@ -884,14 +836,6 @@ const gfx::Vector2d& drag_offset, Widget::MoveLoopSource source, Widget::MoveLoopEscapeBehavior escape_behavior) { - // When using WindowService, the touch events for the window move will - // happen on the root window, so the events need to be transferred from - // widget to its root before starting move loop. - ScopedTouchTransferController scoped_controller(content_window(), window()); - - static_cast<internal::NativeWidgetPrivate*>( - desktop_native_widget_aura_)->ReleaseCapture(); - base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); ws::mojom::MoveLoopSource mus_source = @@ -906,8 +850,8 @@ gfx::Point cursor_location = window()->GetBoundsInScreen().origin() + gfx::ToFlooredVector2d(drag_offset); WindowTreeHostMus::PerformWindowMove( - mus_source, cursor_location, - base::Bind(OnMoveLoopEnd, &success, run_loop.QuitClosure())); + content_window(), mus_source, cursor_location, + base::BindOnce(&OnMoveLoopEnd, &success, run_loop.QuitClosure())); run_loop.Run(); @@ -958,6 +902,11 @@ WindowTreeHostMus::SetOpacity(opacity); } +void DesktopWindowTreeHostMus::SetAspectRatio(const gfx::SizeF& aspect_ratio) { + window()->SetProperty(aura::client::kAspectRatio, + new gfx::SizeF(aspect_ratio)); +} + void DesktopWindowTreeHostMus::SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) { NativeWidgetAura::AssignIconToAuraWindow(window(), window_icon, app_icon);
diff --git a/ui/views/mus/desktop_window_tree_host_mus.h b/ui/views/mus/desktop_window_tree_host_mus.h index 4a58e2d..9daf24b3 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.h +++ b/ui/views/mus/desktop_window_tree_host_mus.h
@@ -136,7 +136,7 @@ void SetFullscreen(bool fullscreen) override; bool IsFullscreen() const override; void SetOpacity(float opacity) override; - void SetAspectRatio(const gfx::SizeF& aspect_ratio) override {} + void SetAspectRatio(const gfx::SizeF& aspect_ratio) override; void SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) override; void InitModalType(ui::ModalType modal_type) override;
diff --git a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc index ce64697..d78253d 100644 --- a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc +++ b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
@@ -7,6 +7,7 @@ #include "base/command_line.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind_test_util.h" +#include "services/ws/test_ws/test_ws.mojom-test-utils.h" #include "services/ws/test_ws/test_ws.mojom.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/cursor_client.h"
diff --git a/ui/views/widget/ax_native_widget_mac_unittest.mm b/ui/views/widget/ax_native_widget_mac_unittest.mm index 45e70d3..da25e8ec 100644 --- a/ui/views/widget/ax_native_widget_mac_unittest.mm +++ b/ui/views/widget/ax_native_widget_mac_unittest.mm
@@ -97,6 +97,11 @@ constexpr char TestWidgetDelegate::kAccessibleWindowTitle[]; +// This test framework uses the deprecated NSObject accessibility APIs - see +// https://crbug.com/921109. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + class AXNativeWidgetMacTest : public test::WidgetTest { public: AXNativeWidgetMacTest() {} @@ -927,3 +932,5 @@ } } // namespace views + +#pragma clang diagnostic pop
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc index 24017c9..ab1c54e 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -414,6 +414,12 @@ NOTIMPLEMENTED_LOG_ONCE(); } +void DesktopWindowTreeHostPlatform::SetAspectRatio( + const gfx::SizeF& aspect_ratio) { + // TODO: needs PlatformWindow support. + NOTIMPLEMENTED_LOG_ONCE(); +} + void DesktopWindowTreeHostPlatform::SetWindowIcons( const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h index 039683e7..02f30ef 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -78,7 +78,7 @@ void SetFullscreen(bool fullscreen) override; bool IsFullscreen() const override; void SetOpacity(float opacity) override; - void SetAspectRatio(const gfx::SizeF& aspect_ratio) override {} + void SetAspectRatio(const gfx::SizeF& aspect_ratio) override; void SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) override; void InitModalType(ui::ModalType modal_type) override;
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm index 9bcfb2c4..85370ab 100644 --- a/ui/views/widget/native_widget_mac_unittest.mm +++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -701,6 +701,11 @@ widget->CloseNow(); } +// This test uses the deprecated NSObject accessibility API - see +// https://crbug.com/921109. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + // Tests that an accessibility request from the system makes its way through to // a views::Label filling the window. TEST_F(NativeWidgetMacTest, AccessibilityIntegration) { @@ -726,6 +731,8 @@ widget->CloseNow(); } +#pragma clang diagnostic pop + namespace { Widget* AttachPopupToNativeParent(NSWindow* native_parent) {
diff --git a/ui/views_bridge_mac/alert.mm b/ui/views_bridge_mac/alert.mm index 328f51b..4868e71 100644 --- a/ui/views_bridge_mac/alert.mm +++ b/ui/views_bridge_mac/alert.mm
@@ -209,7 +209,7 @@ case NSAlertSecondButtonReturn: // Cancel alertBridge_->SendResultAndDestroy(AlertDisposition::SECONDARY_BUTTON); break; - case NSRunStoppedResponse: // Window was closed underneath us + case NSModalResponseStop: // Window was closed underneath us alertBridge_->SendResultAndDestroy(AlertDisposition::CLOSE); break; default: @@ -223,10 +223,15 @@ NSAlert* alert = [self alert]; [alert layout]; [[alert window] recalculateKeyViewLoop]; + // TODO(crbug.com/841631): Migrate to `[NSWindow + // beginSheetModalForWindow:completionHandler:]` instead. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" [alert beginSheetModalForWindow:nil // nil here makes it app-modal modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:NULL]; +#pragma clang diagnostic pop } - (void)closeWindow {
diff --git a/ui/views_bridge_mac/bridged_native_widget_impl.mm b/ui/views_bridge_mac/bridged_native_widget_impl.mm index 3190bf9..4b01329 100644 --- a/ui/views_bridge_mac/bridged_native_widget_impl.mm +++ b/ui/views_bridge_mac/bridged_native_widget_impl.mm
@@ -1338,11 +1338,16 @@ // Since |this| may destroy [window_ delegate], use |window_| itself as the // delegate, which will forward to ViewsNSWindowDelegate if |this| is still // alive (i.e. it has not set the window delegate to nil). + // TODO(crbug.com/841631): Migrate to `[NSWindow + // beginSheet:completionHandler:]` instead of this method. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" [NSApp beginSheet:window_ modalForWindow:parent_window modalDelegate:window_ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:nullptr]; +#pragma clang diagnostic pop } } // namespace views
diff --git a/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.js b/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.js index a782c7c..0b7999f6 100644 --- a/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.js +++ b/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.js
@@ -283,11 +283,11 @@ }, /** - * @param {!CustomEvent} e Custom event containing the new pin. + * @param {!CustomEvent<{pin: string}>} e Custom event containing the new pin. * @private */ onPinChange_: function(e) { - const newPin = /** @type {{pin: string}} */ (e.detail).pin; + const newPin = e.detail.pin; if (!this.isConfirmStep) { if (newPin) { this.quickUnlockPrivate.checkCredential(
diff --git a/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html b/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html index 0563c0f0..551405b 100644 --- a/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html +++ b/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.html
@@ -67,7 +67,7 @@ <img id="image" alt="[[previewAltText]]" src="[[getImgSrc_(imageUrl)]]" data-show-discard$="[[showDiscard_(imageType)]]"> <div id="discard" hidden="[[!showDiscard_(imageType)]]"> - <paper-icon-button-light class="icon-delete-white"> + <paper-icon-button-light class="icon-picture-delete"> <button id="discardImage" title="[[discardImageLabel]]" on-tap="onTapDiscardImage_">
diff --git a/ui/webui/resources/cr_elements/cr_icons_css.html b/ui/webui/resources/cr_elements/cr_icons_css.html index 8a19d260..07e27e4 100644 --- a/ui/webui/resources/cr_elements/cr_icons_css.html +++ b/ui/webui/resources/cr_elements/cr_icons_css.html
@@ -41,74 +41,126 @@ :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-back { background-image: url(../images/icon_arrow_back.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-back { + background-image: url(../images/dark/icon_arrow_back.svg); + } :-webkit-any(paper-icon-button-light, .cr-icon).icon-cancel { background-image: url(../images/icon_cancel.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-cancel { + background-image: url(../images/dark/icon_cancel.svg); + } - :-webkit-any(paper-icon-button-light, .cr-icon).icon-cancel-toolbar { - background-image: url(../images/icon_cancel_toolbar.svg); + :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-cancel { + background-image: url(../images/icon_toolbar_cancel.svg); + } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-cancel { + background-image: url(../images/dark/icon_toolbar_cancel.svg); } :-webkit-any(paper-icon-button-light, .cr-icon).icon-clear { background-image: url(../images/icon_clear.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-clear { + background-image: url(../images/dark/icon_clear.svg); + } :-webkit-any(paper-icon-button-light, .cr-icon).icon-delete-gray { background-image: url(../images/icon_delete_gray.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-delete-gray { + background-image: url(../images/dark/icon_delete_gray.svg); + } - :-webkit-any(paper-icon-button-light, .cr-icon).icon-delete-white { - background-image: url(../images/icon_delete_white.svg); + :-webkit-any(paper-icon-button-light, .cr-icon).icon-picture-delete { + background-image: url(../images/icon_picture_delete.svg); + } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-picture-delete { + background-image: url(../images/dark/icon_picture_delete.svg); } :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-less { background-image: url(../images/icon_expand_less.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-less { + background-image: url(../images/dark/icon_expand_less.svg); + } :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-more { background-image: url(../images/icon_expand_more.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-more { + background-image: url(../images/dark/icon_expand_more.svg); + } :-webkit-any(paper-icon-button-light, .cr-icon).icon-external { background-image: url(../images/open_in_new.svg); } + /* Open in new is the same for light and dark mode. */ - :-webkit-any(paper-icon-button-light, .cr-icon).icon-menu-white { - background-image: url(../images/icon_menu_white.svg); + :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-menu { + background-image: url(../images/icon_toolbar_menu.svg); + } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-menu { + background-image: url(../images/dark/icon_toolbar_menu.svg); } :-webkit-any(paper-icon-button-light, .cr-icon).icon-more-vert { background-image: url(../images/icon_more_vert.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-more-vert { + background-image: url(../images/dark/icon_more_vert.svg); + } :-webkit-any(paper-icon-button-light, .cr-icon).icon-refresh { background-image: url(../images/icon_refresh.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-refresh { + background-image: url(../images/dark/icon_refresh.svg); + } :-webkit-any(paper-icon-button-light, .cr-icon).icon-settings { background-image: url(../images/icon_settings.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-settings { + background-image: url(../images/dark/icon_settings.svg); + } :-webkit-any(paper-icon-button-light, .cr-icon).icon-search { background-image: url(../images/icon_search.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-search { + background-image: url(../images/dark/icon_search.svg); + } :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-dropdown { background-image: url(../images/icon_arrow_dropdown.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-dropdown { + background-image: url(../images/dark/icon_arrow_dropdown.svg); + } :-webkit-any(paper-icon-button-light, .cr-icon).subpage-arrow { background-image: url(../images/arrow_right.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).subpage-arrow { + background-image: url(../images/dark/arrow_right.svg); + } :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility { background-image: url(../images/icon_visibility.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility { + background-image: url(../images/dark/icon_visibility.svg); + } :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility-off { background-image: url(../images/icon_visibility_off.svg); } + :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility-off { + background-image: url(../images/dark/icon_visibility_off.svg); + } </style> </template> </dom-module>
diff --git a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html index 1a7b4a3f..8c3df8bf 100644 --- a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html +++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
@@ -145,7 +145,7 @@ <!-- Note: showing #menuPromo relies on this dom-if being [restamp]. --> <template is="dom-if" if="[[showMenu]]" restamp> <paper-icon-button-light id="menuButtonContainer" - class="icon-menu-white no-overlap"> + class="icon-toolbar-menu no-overlap"> <button id="menuButton" on-tap="onMenuTap_" title="[[titleIfNotShowMenuPromo_(menuLabel, showMenuPromo)]]"
diff --git a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html index 0f03fdf8..5c86c8c 100644 --- a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html +++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html
@@ -154,7 +154,7 @@ spellcheck="false"> </div> <template is="dom-if" if="[[hasSearchText]]"> - <paper-icon-button-light class="icon-cancel-toolbar"> + <paper-icon-button-light class="icon-toolbar-cancel"> <button id="clearSearch" title="[[clearLabel]]" on-tap="clearSearch_"> </button> </paper-icon-button-light>
diff --git a/ui/webui/resources/cr_elements/paper_tabs_style_css.html b/ui/webui/resources/cr_elements/paper_tabs_style_css.html index ca193b60..c769c86 100644 --- a/ui/webui/resources/cr_elements/paper_tabs_style_css.html +++ b/ui/webui/resources/cr_elements/paper_tabs_style_css.html
@@ -11,6 +11,11 @@ --paper-tabs-selection-bar-color: var(--google-blue-600); } + :host-context([dark]) paper-tabs { + /* TODO(dbeam): verify these colors with Namrata. */ + --paper-tabs-selection-bar-color: var(--google-blue-refresh-300); + } + paper-tab { --paper-tab-content: { color: var(--google-blue-600); @@ -19,6 +24,12 @@ color: var(--cr-secondary-text-color); }; } + + :host-context([dark]) paper-tab { + --paper-tab-content: { + color: var(--google-blue-refresh-300); + }; + } </style> </template> </dom-module>
diff --git a/ui/webui/resources/cr_elements/shared_vars_css.html b/ui/webui/resources/cr_elements/shared_vars_css.html index ba0a98d..26d7aaf 100644 --- a/ui/webui/resources/cr_elements/shared_vars_css.html +++ b/ui/webui/resources/cr_elements/shared_vars_css.html
@@ -71,11 +71,8 @@ } html[dark] { - --dark-primary-color: var(--google-grey-200); - --dark-secondary-color: var(--google-grey-refresh-500); - - --cr-primary-text-color: var(--dark-primary-color); - --cr-secondary-text-color: var(--dark-secondary-color); + --cr-primary-text-color: var(--google-grey-200); + --cr-secondary-text-color: var(--google-grey-refresh-500); --cr-card-background-color: var(--google-grey-900); --cr-card-elevation: { @@ -95,6 +92,7 @@ --cr-menu-shadow: rgba(0, 0, 0, .3) 0 1px 2px 0, rgba(0, 0, 0, .15) 0 3px 6px 2px; --cr-separator-color: rgba(255, 255, 255, .1); + --cr-title-text-color: var(--cr-primary-text-color); } /* Don't use color values past this point. Instead, create a variable that's
diff --git a/ui/webui/resources/cr_elements_images.grdp b/ui/webui/resources/cr_elements_images.grdp index fbf3a9f..6ac69e4 100644 --- a/ui/webui/resources/cr_elements_images.grdp +++ b/ui/webui/resources/cr_elements_images.grdp
@@ -7,40 +7,42 @@ file="images/arrow_down.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ARROW_RIGHT" file="images/arrow_right.svg" type="BINDATA" compress="gzip" /> + <include name="IDR_WEBUI_IMAGES_DARK_ARROW_DOWN" + file="images/dark/arrow_down.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_OPEN_IN_NEW" file="images/open_in_new.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_ARROW_BACK" file="images/icon_arrow_back.svg" type="BINDATA" compress="gzip" /> + <include name="IDR_WEBUI_IMAGES_ICON_ARROW_DROPDOWN" + file="images/icon_arrow_dropdown.svg" type="BINDATA" + compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_CANCEL" file="images/icon_cancel.svg" type="BINDATA" compress="gzip" /> - <include name="IDR_WEBUI_IMAGES_ICON_CANCEL_TOOLBAR" - file="images/icon_cancel_toolbar.svg" type="BINDATA" - compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_CLEAR" file="images/icon_clear.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_DELETE_GRAY" file="images/icon_delete_gray.svg" type="BINDATA" compress="gzip" /> - <include name="IDR_WEBUI_IMAGES_ICON_DELETE_WHITE" - file="images/icon_delete_white.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_EXPAND_LESS" file="images/icon_expand_less.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_EXPAND_MORE" file="images/icon_expand_more.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_EXTERNAL" file="images/open_in_new.svg" type="BINDATA" compress="gzip" /> - <include name="IDR_WEBUI_IMAGES_ICON_MENU_WHITE" - file="images/icon_menu_white.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_MORE_VERT" file="images/icon_more_vert.svg" type="BINDATA" compress="gzip" /> + <include name="IDR_WEBUI_IMAGES_ICON_PICTURE_DELETE" + file="images/icon_picture_delete.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_REFRESH" file="images/icon_refresh.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_SETTINGS" file="images/icon_settings.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_SEARCH" file="images/icon_search.svg" type="BINDATA" compress="gzip" /> - <include name="IDR_WEBUI_IMAGES_ICON_ARROW_DROPDOWN" - file="images/icon_arrow_dropdown.svg" type="BINDATA" + <include name="IDR_WEBUI_IMAGES_ICON_TOOLBAR_CANCEL" + file="images/icon_toolbar_cancel.svg" type="BINDATA" compress="gzip" /> + <include name="IDR_WEBUI_IMAGES_ICON_TOOLBAR_MENU" + file="images/icon_toolbar_menu.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_VISIBILITY" file="images/icon_visibility.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_ICON_VISIBILITY_OFF"
diff --git a/ui/webui/resources/html/md_select_css.html b/ui/webui/resources/html/md_select_css.html index a98ec39e..9c72fee 100644 --- a/ui/webui/resources/html/md_select_css.html +++ b/ui/webui/resources/html/md_select_css.html
@@ -47,6 +47,7 @@ * possible to style background-image on <option>. */ --md-select-option-bg-color: #28292c; --md-select-text-color: var(--cr-primary-text-color); + background-image: url(chrome://resources/images/dark/arrow_down.svg); } /* Makes sure anything within the dropdown menu has a background. */
diff --git a/ui/webui/resources/images/dark/arrow_down.svg b/ui/webui/resources/images/dark/arrow_down.svg new file mode 100644 index 0000000..ae82ca45 --- /dev/null +++ b/ui/webui/resources/images/dark/arrow_down.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="12px" viewBox="0 0 24 12" fill="#9aa0a6"><g><path d="M 0 0 L 24 0 L 12 12 z"/></g></svg>
diff --git a/ui/webui/resources/images/dark/arrow_right.svg b/ui/webui/resources/images/dark/arrow_right.svg new file mode 100644 index 0000000..5e128dec --- /dev/null +++ b/ui/webui/resources/images/dark/arrow_right.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6"><path d="M10 7l5 5-5 5z"/></svg> \ No newline at end of file
diff --git a/ui/webui/resources/images/dark/icon_arrow_back.svg b/ui/webui/resources/images/dark/icon_arrow_back.svg new file mode 100644 index 0000000..ebb8171 --- /dev/null +++ b/ui/webui/resources/images/dark/icon_arrow_back.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"></path></svg> \ No newline at end of file
diff --git a/ui/webui/resources/images/dark/icon_arrow_dropdown.svg b/ui/webui/resources/images/dark/icon_arrow_dropdown.svg new file mode 100644 index 0000000..4f633ca --- /dev/null +++ b/ui/webui/resources/images/dark/icon_arrow_dropdown.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M7 10l5 5 5-5z"></path></svg> \ No newline at end of file
diff --git a/ui/webui/resources/images/dark/icon_cancel.svg b/ui/webui/resources/images/dark/icon_cancel.svg new file mode 100644 index 0000000..99edf6b --- /dev/null +++ b/ui/webui/resources/images/dark/icon_cancel.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 2 4" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z" /></svg>
diff --git a/ui/webui/resources/images/dark/icon_clear.svg b/ui/webui/resources/images/dark/icon_clear.svg new file mode 100644 index 0000000..c45c8c0 --- /dev/null +++ b/ui/webui/resources/images/dark/icon_clear.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></svg> \ No newline at end of file
diff --git a/ui/webui/resources/images/dark/icon_delete_gray.svg b/ui/webui/resources/images/dark/icon_delete_gray.svg new file mode 100644 index 0000000..c7d1d76 --- /dev/null +++ b/ui/webui/resources/images/dark/icon_delete_gray.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></svg>
diff --git a/ui/webui/resources/images/dark/icon_expand_less.svg b/ui/webui/resources/images/dark/icon_expand_less.svg new file mode 100644 index 0000000..0be183567 --- /dev/null +++ b/ui/webui/resources/images/dark/icon_expand_less.svg
@@ -0,0 +1,4 @@ +<svg xmlns="http://www.w3.org/2000/svg" fill="#9aa0a6" width="24" height="24" + viewbox="0 0 24 24"> + <path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z"></path> +</svg>
diff --git a/ui/webui/resources/images/dark/icon_expand_more.svg b/ui/webui/resources/images/dark/icon_expand_more.svg new file mode 100644 index 0000000..213245e --- /dev/null +++ b/ui/webui/resources/images/dark/icon_expand_more.svg
@@ -0,0 +1,4 @@ +<svg xmlns="http://www.w3.org/2000/svg" fill="#9aa0a6" width="24" height="24" + viewBox="0 0 24 24"> + <path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"></path> +</svg>
diff --git a/ui/webui/resources/images/dark/icon_more_vert.svg b/ui/webui/resources/images/dark/icon_more_vert.svg new file mode 100644 index 0000000..cd21f0f --- /dev/null +++ b/ui/webui/resources/images/dark/icon_more_vert.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></svg> \ No newline at end of file
diff --git a/ui/webui/resources/images/dark/icon_picture_delete.svg b/ui/webui/resources/images/dark/icon_picture_delete.svg new file mode 100644 index 0000000..9c80ccbb7 --- /dev/null +++ b/ui/webui/resources/images/dark/icon_picture_delete.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#e8eaed" preserveAspectRatio="xMidYMid meet"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></svg>
diff --git a/ui/webui/resources/images/dark/icon_refresh.svg b/ui/webui/resources/images/dark/icon_refresh.svg new file mode 100644 index 0000000..d588c54 --- /dev/null +++ b/ui/webui/resources/images/dark/icon_refresh.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"></path></svg> \ No newline at end of file
diff --git a/ui/webui/resources/images/dark/icon_search.svg b/ui/webui/resources/images/dark/icon_search.svg new file mode 100644 index 0000000..8145e69 --- /dev/null +++ b/ui/webui/resources/images/dark/icon_search.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path></svg> \ No newline at end of file
diff --git a/ui/webui/resources/images/dark/icon_settings.svg b/ui/webui/resources/images/dark/icon_settings.svg new file mode 100644 index 0000000..2b2c7b0 --- /dev/null +++ b/ui/webui/resources/images/dark/icon_settings.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"></path></svg> \ No newline at end of file
diff --git a/ui/webui/resources/images/dark/icon_toolbar_cancel.svg b/ui/webui/resources/images/dark/icon_toolbar_cancel.svg new file mode 100644 index 0000000..52d7346 --- /dev/null +++ b/ui/webui/resources/images/dark/icon_toolbar_cancel.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 2 4" fill="#e8eaed" preserveAspectRatio="xMidYMid meet"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z" /></svg>
diff --git a/ui/webui/resources/images/dark/icon_toolbar_menu.svg b/ui/webui/resources/images/dark/icon_toolbar_menu.svg new file mode 100644 index 0000000..3af72ab --- /dev/null +++ b/ui/webui/resources/images/dark/icon_toolbar_menu.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="#e8eaed" preserveAspectRatio="xMidYMid meet"><rect x="2" y="4" width="16" height="2"></rect><rect x="2" y="9" width="16" height="2"></rect><rect x="2" y="14" width="16" height="2"></rect></svg>
diff --git a/ui/webui/resources/images/dark/icon_visibility.svg b/ui/webui/resources/images/dark/icon_visibility.svg new file mode 100644 index 0000000..3be0cc8 --- /dev/null +++ b/ui/webui/resources/images/dark/icon_visibility.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"></path></svg> \ No newline at end of file
diff --git a/ui/webui/resources/images/dark/icon_visibility_off.svg b/ui/webui/resources/images/dark/icon_visibility_off.svg new file mode 100644 index 0000000..9d52f6d --- /dev/null +++ b/ui/webui/resources/images/dark/icon_visibility_off.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#9aa0a6" preserveAspectRatio="xMidYMid meet"><path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"/></svg>
diff --git a/ui/webui/resources/images/icon_delete_white.svg b/ui/webui/resources/images/icon_picture_delete.svg similarity index 100% rename from ui/webui/resources/images/icon_delete_white.svg rename to ui/webui/resources/images/icon_picture_delete.svg
diff --git a/ui/webui/resources/images/icon_cancel_toolbar.svg b/ui/webui/resources/images/icon_toolbar_cancel.svg similarity index 100% rename from ui/webui/resources/images/icon_cancel_toolbar.svg rename to ui/webui/resources/images/icon_toolbar_cancel.svg
diff --git a/ui/webui/resources/images/icon_menu_white.svg b/ui/webui/resources/images/icon_toolbar_menu.svg similarity index 100% rename from ui/webui/resources/images/icon_menu_white.svg rename to ui/webui/resources/images/icon_toolbar_menu.svg
diff --git a/ui/webui/resources/polymer_resources.grdp b/ui/webui/resources/polymer_resources.grdp index 7681d79..a0c34db 100644 --- a/ui/webui/resources/polymer_resources.grdp +++ b/ui/webui/resources/polymer_resources.grdp
@@ -308,15 +308,15 @@ file="../../../third_party/polymer/v1_0/components-chromium/iron-selector/iron-selector.html" type="chrome_html" compress="gzip" /> - <structure name="IDR_POLYMER_1_0_IRON_VALIDATABLE_BEHAVIOR_IRON_VALIDATABLE_BEHAVIOR_EXTRACTED_JS" - file="../../../third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/iron-validatable-behavior-extracted.js" - type="chrome_html" - compress="gzip" /> - <structure name="IDR_POLYMER_1_0_IRON_VALIDATABLE_BEHAVIOR_IRON_VALIDATABLE_BEHAVIOR_HTML" - file="../../../third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/iron-validatable-behavior.html" - type="chrome_html" - compress="gzip" /> <if expr="chromeos"> + <structure name="IDR_POLYMER_1_0_IRON_VALIDATABLE_BEHAVIOR_IRON_VALIDATABLE_BEHAVIOR_EXTRACTED_JS" + file="../../../third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/iron-validatable-behavior-extracted.js" + type="chrome_html" + compress="gzip" /> + <structure name="IDR_POLYMER_1_0_IRON_VALIDATABLE_BEHAVIOR_IRON_VALIDATABLE_BEHAVIOR_HTML" + file="../../../third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/iron-validatable-behavior.html" + type="chrome_html" + compress="gzip" /> <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_FADE_IN_ANIMATION_EXTRACTED_JS" file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/fade-in-animation-extracted.js" type="chrome_html"